diff --git a/.gitignore b/.gitignore index fcbc9cd7f4..0e7eda4f89 100644 --- a/.gitignore +++ b/.gitignore @@ -180,6 +180,7 @@ ID # Executables. *.exe a.out +lib-src/be-resources lib-src/blessmail lib-src/ctags lib-src/ebrowse @@ -201,6 +202,7 @@ nextstep/GNUstep/Emacs.base/Resources/Info-gnustep.plist src/bootstrap-emacs src/emacs src/emacs-[0-9]* +src/Emacs src/temacs src/dmpstruct.h src/*.pdmp diff --git a/Makefile.in b/Makefile.in index 235b707673..8993b54518 100644 --- a/Makefile.in +++ b/Makefile.in @@ -102,6 +102,8 @@ HAVE_NATIVE_COMP = USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@ +HAVE_BE_APP = @HAVE_BE_APP@ + # ==================== Where To Install Things ==================== # Location to install Emacs.app under GNUstep / macOS. @@ -514,8 +516,14 @@ install-arch-dep: $(MAKE) -C lib-src install ifeq (${ns_self_contained},no) ${INSTALL_PROGRAM} $(INSTALL_STRIP) src/emacs${EXEEXT} "$(DESTDIR)${bindir}/$(EMACSFULL)" +ifeq (${HAVE_BE_APP},yes) + ${INSTALL_PROGRAM} $(INSTALL_STRIP) src/Emacs "$(DESTDIR)${bindir}/Emacs" +endif ifeq (${DUMPING},pdumper) ${INSTALL_DATA} src/emacs.pdmp "$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/emacs.pdmp +ifeq (${HAVE_BE_APP},yes) + ${INSTALL_DATA} src/Emacs.pdmp "$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/Emacs.pdmp +endif endif -chmod 755 "$(DESTDIR)${bindir}/$(EMACSFULL)" ifndef NO_BIN_LINK @@ -880,7 +888,7 @@ $(1)_$(2): ### target for GCC does not delete 'libgcc.a', because recompiling it ### is rarely necessary and takes a lot of time. mostlyclean_dirs = src oldXMenu lwlib lib lib-src nt doc/emacs doc/misc \ - doc/lispref doc/lispintro test + doc/lispref doc/lispintro test be_xpm $(foreach dir,$(mostlyclean_dirs),$(eval $(call submake_template,$(dir),mostlyclean))) diff --git a/be_xpm/Attrib.c b/be_xpm/Attrib.c new file mode 100644 index 0000000000..1b380470c9 --- /dev/null +++ b/be_xpm/Attrib.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* Attrib.c: * +* * +* XPM library * +* Functions related to the XpmAttributes structure * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* October 2004, source code review by Thomas Biege */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +/* 3.2 backward compatibility code */ +LFUNC(CreateOldColorTable, int, (XpmColor *ct, unsigned int ncolors, + XpmColor ***oldct)); + +LFUNC(FreeOldColorTable, void, (XpmColor **colorTable, unsigned int ncolors)); + +/* + * Create a colortable compatible with the old style colortable + */ +static int +CreateOldColorTable( + XpmColor *ct, + unsigned int ncolors, + XpmColor ***oldct) +{ + XpmColor **colorTable, **color; + unsigned int a; + + if (ncolors >= UINT_MAX / sizeof(XpmColor *)) + return XpmNoMemory; + + colorTable = (XpmColor **) XpmMalloc(ncolors * sizeof(XpmColor *)); + if (!colorTable) { + *oldct = NULL; + return (XpmNoMemory); + } + for (a = 0, color = colorTable; a < ncolors; a++, color++, ct++) + *color = ct; + *oldct = colorTable; + return (XpmSuccess); +} + +static void +FreeOldColorTable( + XpmColor **colorTable, + unsigned int ncolors) +{ + unsigned int a, b; + XpmColor **color; + char **sptr; + + if (colorTable) { + for (a = 0, color = colorTable; a < ncolors; a++, color++) { + for (b = 0, sptr = (char **) *color; b <= NKEYS; b++, sptr++) + if (*sptr) + XpmFree(*sptr); + } + XpmFree(*colorTable); + XpmFree(colorTable); + } +} + +/* end 3.2 bc */ + +/* + * Free the computed color table + */ +void +xpmFreeColorTable( + XpmColor *colorTable, + int ncolors) +{ + int a, b; + XpmColor *color; + char **sptr; + + if (colorTable) { + for (a = 0, color = colorTable; a < ncolors; a++, color++) { + for (b = 0, sptr = (char **) color; b <= NKEYS; b++, sptr++) + if (*sptr) + XpmFree(*sptr); + } + XpmFree(colorTable); + } +} + +/* + * Free array of extensions + */ +void +XpmFreeExtensions( + XpmExtension *extensions, + int nextensions) +{ + unsigned int i, j, nlines; + XpmExtension *ext; + char **sptr; + + if (extensions && nextensions > 0) { + for (i = 0, ext = extensions; i < nextensions; i++, ext++) { + if (ext->name) + XpmFree(ext->name); + nlines = ext->nlines; + for (j = 0, sptr = ext->lines; j < nlines; j++, sptr++) + if (sptr && *sptr) + XpmFree(*sptr); + if (ext->lines) + XpmFree(ext->lines); + } + XpmFree(extensions); + } +} + +/* + * Return the XpmAttributes structure size + */ + +int +XpmAttributesSize(void) +{ + return sizeof(XpmAttributes); +} + +/* + * Init returned data to free safely later on + */ +void +xpmInitAttributes(XpmAttributes *attributes) +{ + if (attributes) { + attributes->pixels = NULL; + attributes->npixels = 0; + attributes->colorTable = NULL; + attributes->ncolors = 0; +/* 3.2 backward compatibility code */ + attributes->hints_cmt = NULL; + attributes->colors_cmt = NULL; + attributes->pixels_cmt = NULL; +/* end 3.2 bc */ + if (attributes->valuemask & XpmReturnExtensions) { + attributes->extensions = NULL; + attributes->nextensions = 0; + } + if (attributes->valuemask & XpmReturnAllocPixels) { + attributes->alloc_pixels = NULL; + attributes->nalloc_pixels = 0; + } + } +} + +/* + * Fill in the XpmAttributes with the XpmImage and the XpmInfo + */ +void +xpmSetAttributes( + XpmAttributes *attributes, + XpmImage *image, + XpmInfo *info) +{ + if (attributes->valuemask & XpmReturnColorTable) { + attributes->colorTable = image->colorTable; + attributes->ncolors = image->ncolors; + + /* avoid deletion of copied data */ + image->ncolors = 0; + image->colorTable = NULL; + } +/* 3.2 backward compatibility code */ + else if (attributes->valuemask & XpmReturnInfos) { + int ErrorStatus; + + ErrorStatus = CreateOldColorTable(image->colorTable, image->ncolors, + (XpmColor ***) + &attributes->colorTable); + + /* if error just say we can't return requested data */ + if (ErrorStatus != XpmSuccess) { + attributes->valuemask &= ~XpmReturnInfos; + if (!(attributes->valuemask & XpmReturnPixels)) { + XpmFree(attributes->pixels); + attributes->pixels = NULL; + attributes->npixels = 0; + } + attributes->ncolors = 0; + } else { + attributes->ncolors = image->ncolors; + attributes->hints_cmt = info->hints_cmt; + attributes->colors_cmt = info->colors_cmt; + attributes->pixels_cmt = info->pixels_cmt; + + /* avoid deletion of copied data */ + image->ncolors = 0; + image->colorTable = NULL; + info->hints_cmt = NULL; + info->colors_cmt = NULL; + info->pixels_cmt = NULL; + } + } +/* end 3.2 bc */ + if (attributes->valuemask & XpmReturnExtensions) { + attributes->extensions = info->extensions; + attributes->nextensions = info->nextensions; + + /* avoid deletion of copied data */ + info->extensions = NULL; + info->nextensions = 0; + } + if (info->valuemask & XpmHotspot) { + attributes->valuemask |= XpmHotspot; + attributes->x_hotspot = info->x_hotspot; + attributes->y_hotspot = info->y_hotspot; + } + attributes->valuemask |= XpmCharsPerPixel; + attributes->cpp = image->cpp; + attributes->valuemask |= XpmSize; + attributes->width = image->width; + attributes->height = image->height; +} + +/* + * Free the XpmAttributes structure members + * but the structure itself + */ +void +XpmFreeAttributes(XpmAttributes *attributes) +{ + if (attributes->valuemask & XpmReturnPixels && attributes->npixels) { + XpmFree(attributes->pixels); + attributes->pixels = NULL; + attributes->npixels = 0; + } + if (attributes->valuemask & XpmReturnColorTable) { + xpmFreeColorTable(attributes->colorTable, attributes->ncolors); + attributes->colorTable = NULL; + attributes->ncolors = 0; + } +/* 3.2 backward compatibility code */ + else if (attributes->valuemask & XpmInfos) { + if (attributes->colorTable) { + FreeOldColorTable((XpmColor **) attributes->colorTable, + attributes->ncolors); + attributes->colorTable = NULL; + attributes->ncolors = 0; + } + if (attributes->hints_cmt) { + XpmFree(attributes->hints_cmt); + attributes->hints_cmt = NULL; + } + if (attributes->colors_cmt) { + XpmFree(attributes->colors_cmt); + attributes->colors_cmt = NULL; + } + if (attributes->pixels_cmt) { + XpmFree(attributes->pixels_cmt); + attributes->pixels_cmt = NULL; + } + if (attributes->pixels) { + XpmFree(attributes->pixels); + attributes->pixels = NULL; + attributes->npixels = 0; + } + } +/* end 3.2 bc */ + if (attributes->valuemask & XpmReturnExtensions + && attributes->nextensions) { + XpmFreeExtensions(attributes->extensions, attributes->nextensions); + attributes->extensions = NULL; + attributes->nextensions = 0; + } + if (attributes->valuemask & XpmReturnAllocPixels + && attributes->nalloc_pixels) { + XpmFree(attributes->alloc_pixels); + attributes->alloc_pixels = NULL; + attributes->nalloc_pixels = 0; + } + attributes->valuemask = 0; +} diff --git a/be_xpm/COPYING.libXpm b/be_xpm/COPYING.libXpm new file mode 100644 index 0000000000..dac401302b --- /dev/null +++ b/be_xpm/COPYING.libXpm @@ -0,0 +1,68 @@ +Copyright (C) 1989-95 GROUPE BULL + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of GROUPE BULL shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from GROUPE BULL. + +Copyright (C) 1998 Arnaud LE HORS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +Arnaud LE HORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Arnaud LE HORS shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from Arnaud LE HORS. + +Copyright (C) 1996 Lorens Younes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +Lorens Younes BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Lorens Younes shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from Lorens Younes. \ No newline at end of file diff --git a/be_xpm/CrBufFrI.c b/be_xpm/CrBufFrI.c new file mode 100644 index 0000000000..dd242510a7 --- /dev/null +++ b/be_xpm/CrBufFrI.c @@ -0,0 +1,465 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL GROUPE BULL BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from GROUPE BULL. + */ + +/*****************************************************************************\ +* CrBufFrI.c: * +* * +* XPM library * +* Scan an image and possibly its mask and create an XPM buffer * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* October 2004, source code review by Thomas Biege + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +LFUNC (WriteColors, int, + (char **dataptr, unsigned int *data_size, + unsigned int *used_size, XpmColor *colors, + unsigned int ncolors, unsigned int cpp)); + +LFUNC (WritePixels, void, + (char *dataptr, unsigned int data_size, + unsigned int *used_size, unsigned int width, + unsigned int height, unsigned int cpp, unsigned int *pixels, + XpmColor *colors)); + +LFUNC (WriteExtensions, void, + (char *dataptr, unsigned int data_size, + unsigned int *used_size, XpmExtension *ext, + unsigned int num)); + +LFUNC (ExtensionsSize, unsigned int, + (XpmExtension * ext, unsigned int num)); +LFUNC (CommentsSize, int, (XpmInfo * info)); + +int +XpmCreateBufferFromImage (Display *display, char **buffer_return, + XImage *image, XImage *shapeimage, + XpmAttributes *attributes) +{ + XpmImage xpmimage; + XpmInfo info; + int ErrorStatus; + + /* initialize return value */ + if (buffer_return) + *buffer_return = NULL; + + /* create an XpmImage from the image */ + ErrorStatus + = XpmCreateXpmImageFromImage (display, image, shapeimage, + &xpmimage, attributes); + if (ErrorStatus != XpmSuccess) + return (ErrorStatus); + + /* create the buffer from the XpmImage */ + if (attributes) + { + xpmSetInfo (&info, attributes); + ErrorStatus = XpmCreateBufferFromXpmImage (buffer_return, + &xpmimage, &info); + } + else + ErrorStatus + = XpmCreateBufferFromXpmImage (buffer_return, &xpmimage, NULL); + + /* free the XpmImage */ + XpmFreeXpmImage (&xpmimage); + + return (ErrorStatus); +} + +#undef RETURN +#define RETURN(status) \ + do \ + { \ + ErrorStatus = status; \ + goto error; \ + } \ + while (0) + +int +XpmCreateBufferFromXpmImage (char **buffer_return, XpmImage *image, + XpmInfo *info) +{ + /* calculation variables */ + int ErrorStatus; + char buf[BUFSIZ]; + unsigned int cmts, extensions, ext_size = 0; + unsigned int l, cmt_size = 0; + char *ptr = NULL, *p; + unsigned int ptr_size, used_size, tmp; + + *buffer_return = NULL; + + cmts = info && (info->valuemask & XpmComments); + extensions + = info && (info->valuemask & XpmExtensions) && info->nextensions; + + /* compute the extensions and comments size */ + if (extensions) + ext_size = ExtensionsSize (info->extensions, info->nextensions); + if (cmts) + cmt_size = CommentsSize (info); + + /* write the header line */ +#ifndef VOID_SPRINTF + used_size = +#endif + sprintf (buf, "/* XPM */\nstatic char * image_name[] = {\n"); +#ifdef VOID_SPRINTF + used_size = strlen (buf); +#endif + ptr_size + = used_size + ext_size + cmt_size + 1; /* ptr_size can't be 0 */ + if (ptr_size <= used_size || ptr_size <= ext_size + || ptr_size <= cmt_size) + { + return XpmNoMemory; + } + ptr = (char *) XpmMalloc (ptr_size); + if (!ptr) + return XpmNoMemory; + strcpy (ptr, buf); + + /* write the values line */ + if (cmts && info->hints_cmt) + { +#ifndef VOID_SPRINTF + used_size += +#endif + snprintf (ptr + used_size, ptr_size - used_size, "/*%s*/\n", + info->hints_cmt); +#ifdef VOID_SPRINTF + used_size += strlen (info->hints_cmt) + 5; +#endif + } +#ifndef VOID_SPRINTF + l = +#endif + sprintf (buf, "\"%d %d %d %d", image->width, image->height, + image->ncolors, image->cpp); +#ifdef VOID_SPRINTF + l = strlen (buf); +#endif + + if (info && (info->valuemask & XpmHotspot)) + { +#ifndef VOID_SPRINTF + l += +#endif + snprintf (buf + l, sizeof (buf) - l, " %d %d", + info->x_hotspot, info->y_hotspot); +#ifdef VOID_SPRINTF + l = strlen (buf); +#endif + } + if (extensions) + { +#ifndef VOID_SPRINTF + l += +#endif + sprintf (buf + l, " XPMEXT"); +#ifdef VOID_SPRINTF + l = strlen (buf); +#endif + } +#ifndef VOID_SPRINTF + l += +#endif + sprintf (buf + l, "\",\n"); +#ifdef VOID_SPRINTF + l = strlen (buf); +#endif + ptr_size += l; + if (ptr_size <= l) + RETURN (XpmNoMemory); + p = (char *) XpmRealloc (ptr, ptr_size); + if (!p) + RETURN (XpmNoMemory); + ptr = p; + strcpy (ptr + used_size, buf); + used_size += l; + + /* write colors */ + if (cmts && info->colors_cmt) + { +#ifndef VOID_SPRINTF + used_size += +#endif + snprintf (ptr + used_size, ptr_size - used_size, "/*%s*/\n", + info->colors_cmt); +#ifdef VOID_SPRINTF + used_size += strlen (info->colors_cmt) + 5; +#endif + } + ErrorStatus + = WriteColors (&ptr, &ptr_size, &used_size, image->colorTable, + image->ncolors, image->cpp); + + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + + /* + * now we know the exact size we need, realloc the data + * 4 = 1 (for '"') + 3 (for '",\n') + * 1 = - 2 (because the last line does not end with ',\n') + 3 (for + * '};\n') + */ + if (image->width > UINT_MAX / image->cpp + || (tmp = image->width * image->cpp + 4) <= 4 + || image->height > UINT_MAX / tmp + || (tmp = image->height * tmp + 1) <= 1 + || (ptr_size += tmp) <= tmp) + RETURN (XpmNoMemory); + + p = (char *) XpmRealloc (ptr, ptr_size); + if (!p) + RETURN (XpmNoMemory); + ptr = p; + + /* print pixels */ + if (cmts && info->pixels_cmt) + { +#ifndef VOID_SPRINTF + used_size += +#endif + snprintf (ptr + used_size, ptr_size - used_size, "/*%s*/\n", + info->pixels_cmt); +#ifdef VOID_SPRINTF + used_size += strlen (info->pixels_cmt) + 5; +#endif + } + WritePixels (ptr + used_size, ptr_size - used_size, &used_size, + image->width, image->height, image->cpp, image->data, + image->colorTable); + + /* print extensions */ + if (extensions) + WriteExtensions (ptr + used_size, ptr_size - used_size, + &used_size, info->extensions, info->nextensions); + + /* close the array */ + strcpy (ptr + used_size, "};\n"); + + *buffer_return = ptr; + + return (XpmSuccess); + +/* exit point in case of error, free only locally allocated variables + */ +error: + if (ptr) + XpmFree (ptr); + return (ErrorStatus); +} + +static int +WriteColors (char **dataptr, unsigned int *data_size, + unsigned int *used_size, XpmColor *colors, + unsigned int ncolors, unsigned int cpp) +{ + char buf[BUFSIZ] = { 0 }; + unsigned int a, key, l; + char *s, *s2; + char **defaults; + + *buf = '"'; + for (a = 0; a < ncolors; a++, colors++) + { + defaults = (char **) colors; + s = buf + 1; + if (cpp > (sizeof (buf) - (s - buf))) + return (XpmNoMemory); + strncpy (s, *defaults++, cpp); + s += cpp; + + for (key = 1; key <= NKEYS; key++, defaults++) + { + if ((s2 = *defaults)) + { +#ifndef VOID_SPRINTF + s += +#endif + /* assume C99 compliance */ + snprintf (s, sizeof (buf) - (s - buf), "\t%s %s", + xpmColorKeys[key - 1], s2); +#ifdef VOID_SPRINTF + s += strlen (s); +#endif + /* now let's check if s points out-of-bounds */ + if ((s - buf) > sizeof (buf)) + return (XpmNoMemory); + } + } + if (sizeof (buf) - (s - buf) < 4) + return (XpmNoMemory); + strcpy (s, "\",\n"); + l = s + 3 - buf; + if (*data_size >= UINT_MAX - l || *data_size + l <= *used_size + || (*data_size + l - *used_size) <= sizeof (buf)) + return (XpmNoMemory); + s = (char *) XpmRealloc (*dataptr, *data_size + l); + if (!s) + return (XpmNoMemory); + *data_size += l; + strcpy (s + *used_size, buf); + *used_size += l; + *dataptr = s; + } + return (XpmSuccess); +} + +static void +WritePixels (char *dataptr, unsigned int data_size, + unsigned int *used_size, unsigned int width, + unsigned int height, unsigned int cpp, + unsigned int *pixels, XpmColor *colors) +{ + char *s = dataptr; + unsigned int x, y, h; + + if (height <= 1) + return; + + h = height - 1; + for (y = 0; y < h; y++) + { + *s++ = '"'; + for (x = 0; x < width; x++, pixels++) + { + if (cpp >= (data_size - (s - dataptr))) + return; + strncpy (s, colors[*pixels].string, + cpp); /* how can we trust *pixels? :-\ */ + s += cpp; + } + if ((data_size - (s - dataptr)) < 4) + return; + strcpy (s, "\",\n"); + s += 3; + } + /* duplicate some code to avoid a test in the loop */ + *s++ = '"'; + for (x = 0; x < width; x++, pixels++) + { + if (cpp >= (data_size - (s - dataptr))) + return; + strncpy (s, colors[*pixels].string, + cpp); /* how can we trust *pixels? */ + s += cpp; + } + *s++ = '"'; + *used_size += s - dataptr; +} + +static unsigned int +ExtensionsSize (XpmExtension *ext, unsigned int num) +{ + unsigned int x, y, a, size; + char **line; + + size = 0; + if (num == 0) + return (0); /* ok? */ + for (x = 0; x < num; x++, ext++) + { + /* 11 = 10 (for ',\n"XPMEXT ') + 1 (for '"') */ + size += strlen (ext->name) + 11; + a = ext->nlines; /* how can we trust ext->nlines to be not + out-of-bounds? */ + for (y = 0, line = ext->lines; y < a; y++, line++) + /* 4 = 3 (for ',\n"') + 1 (for '"') */ + size += strlen (*line) + 4; + } + /* 13 is for ',\n"XPMENDEXT"' */ + if (size > UINT_MAX - 13) /* unlikely */ + return (0); + return size + 13; +} + +static void +WriteExtensions (char *dataptr, unsigned int data_size, + unsigned int *used_size, XpmExtension *ext, + unsigned int num) +{ + unsigned int x, y, a; + char **line; + char *s = dataptr; + + for (x = 0; x < num; x++, ext++) + { +#ifndef VOID_SPRINTF + s += +#endif + snprintf (s, data_size - (s - dataptr), ",\n\"XPMEXT %s\"", + ext->name); +#ifdef VOID_SPRINTF + s += strlen (ext->name) + 11; +#endif + a = ext->nlines; + for (y = 0, line = ext->lines; y < a; y++, line++) + { +#ifndef VOID_SPRINTF + s += +#endif + snprintf (s, data_size - (s - dataptr), ",\n\"%s\"", + *line); +#ifdef VOID_SPRINTF + s += strlen (*line) + 4; +#endif + } + } + strncpy (s, ",\n\"XPMENDEXT\"", data_size - (s - dataptr) - 1); + *used_size += s - dataptr + 13; +} + +static int +CommentsSize (XpmInfo *info) +{ + int size = 0; + + /* 5 = 2 (for "/_*") + 3 (for "*_/\n") */ + /* wrap possible but *very* unlikely */ + if (info->hints_cmt) + size += 5 + strlen (info->hints_cmt); + + if (info->colors_cmt) + size += 5 + strlen (info->colors_cmt); + + if (info->pixels_cmt) + size += 5 + strlen (info->pixels_cmt); + + return size; +} diff --git a/be_xpm/CrDatFrI.c b/be_xpm/CrDatFrI.c new file mode 100644 index 0000000000..07c50b9848 --- /dev/null +++ b/be_xpm/CrDatFrI.c @@ -0,0 +1,436 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL GROUPE BULL BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from GROUPE BULL. + */ + +/*****************************************************************************\ +* CrDataFI.c: * +* * +* XPM library * +* Scan an image and possibly its mask and create an XPM array * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* October 2004, source code review by Thomas Biege + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +LFUNC (CreateColors, int, + (char **dataptr, unsigned int *data_size, XpmColor *colors, + unsigned int ncolors, unsigned int cpp)); + +LFUNC (CreatePixels, void, + (char **dataptr, unsigned int data_size, unsigned int width, + unsigned int height, unsigned int cpp, unsigned int *pixels, + XpmColor *colors)); + +LFUNC (CountExtensions, int, + (XpmExtension * ext, unsigned int num, unsigned int *ext_size, + unsigned int *ext_nlines)); + +LFUNC (CreateExtensions, void, + (char **dataptr, unsigned int data_size, unsigned int offset, + XpmExtension *ext, unsigned int num, + unsigned int ext_nlines)); + +int +XpmCreateDataFromImage (Display *display, char ***data_return, + XImage *image, XImage *shapeimage, + XpmAttributes *attributes) +{ + XpmImage xpmimage; + XpmInfo info; + int ErrorStatus; + + /* initialize return value */ + if (data_return) + *data_return = NULL; + + /* create an XpmImage from the image */ + ErrorStatus + = XpmCreateXpmImageFromImage (display, image, shapeimage, + &xpmimage, attributes); + if (ErrorStatus != XpmSuccess) + return (ErrorStatus); + + /* create the data from the XpmImage */ + if (attributes) + { + xpmSetInfo (&info, attributes); + ErrorStatus + = XpmCreateDataFromXpmImage (data_return, &xpmimage, &info); + } + else + ErrorStatus + = XpmCreateDataFromXpmImage (data_return, &xpmimage, NULL); + + /* free the XpmImage */ + XpmFreeXpmImage (&xpmimage); + + return (ErrorStatus); +} + +#undef RETURN +#define RETURN(status) \ + do \ + { \ + ErrorStatus = status; \ + goto exit; \ + } \ + while (0) + +int +XpmCreateDataFromXpmImage (char ***data_return, XpmImage *image, + XpmInfo *info) +{ + /* calculation variables */ + int ErrorStatus; + char buf[BUFSIZ]; + char **header = NULL, **data, **sptr, **sptr2, *s; + unsigned int header_size, header_nlines; + unsigned int data_size, data_nlines; + unsigned int extensions = 0, ext_size = 0, ext_nlines = 0; + unsigned int offset, l, n; + + *data_return = NULL; + + extensions + = info && (info->valuemask & XpmExtensions) && info->nextensions; + + /* compute the number of extensions lines and size */ + if (extensions) + if (CountExtensions (info->extensions, info->nextensions, + &ext_size, &ext_nlines)) + return (XpmNoMemory); + + /* + * alloc a temporary array of char pointer for the header section + * which is the hints line + the color table lines + */ + header_nlines + = 1 + image->ncolors; /* this may wrap and/or become 0 */ + + /* 2nd check superfluous if we do not need header_nlines any further + */ + if (header_nlines <= image->ncolors + || header_nlines >= UINT_MAX / sizeof (char *)) + return (XpmNoMemory); + + header_size = sizeof (char *) * header_nlines; + if (header_size >= UINT_MAX / sizeof (char *)) + return (XpmNoMemory); + header = (char **) + XpmCalloc (header_size, + sizeof (char *)); /* can we trust image->ncolors */ + if (!header) + return (XpmNoMemory); + + /* print the hints line */ + s = buf; +#ifndef VOID_SPRINTF + s += +#endif + sprintf (s, "%d %d %d %d", image->width, image->height, + image->ncolors, image->cpp); +#ifdef VOID_SPRINTF + s += strlen (s); +#endif + + if (info && (info->valuemask & XpmHotspot)) + { +#ifndef VOID_SPRINTF + s += +#endif + sprintf (s, " %d %d", info->x_hotspot, info->y_hotspot); +#ifdef VOID_SPRINTF + s += strlen (s); +#endif + } + if (extensions) + { + strcpy (s, " XPMEXT"); + s += 7; + } + l = s - buf + 1; + *header = (char *) XpmMalloc (l); + if (!*header) + RETURN (XpmNoMemory); + header_size += l; + strcpy (*header, buf); + + /* print colors */ + ErrorStatus + = CreateColors (header + 1, &header_size, image->colorTable, + image->ncolors, image->cpp); + + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + + /* now we know the size needed, alloc the data and copy the header + * lines */ + offset = image->width * image->cpp + 1; + + if (offset <= image->width || offset <= image->cpp) + RETURN (XpmNoMemory); + + if (image->height > UINT_MAX - ext_nlines + || image->height + ext_nlines >= UINT_MAX / sizeof (char *)) + RETURN (XpmNoMemory); + data_size = (image->height + ext_nlines) * sizeof (char *); + + if (image->height > UINT_MAX / offset + || image->height * offset > UINT_MAX - data_size) + RETURN (XpmNoMemory); + data_size += image->height * offset; + + if (header_size > UINT_MAX - ext_size + || header_size + ext_size >= (UINT_MAX - data_size)) + RETURN (XpmNoMemory); + data_size += header_size + ext_size; + + data = (char **) XpmMalloc (data_size); + if (!data) + RETURN (XpmNoMemory); + + data_nlines = header_nlines + image->height + ext_nlines; + *data = (char *) (data + data_nlines); + + /* can header have less elements then n suggests? */ + n = image->ncolors; + for (l = 0, sptr = data, sptr2 = header; l <= n && sptr && sptr2; + l++, sptr++, sptr2++) + { + strcpy (*sptr, *sptr2); + *(sptr + 1) = *sptr + strlen (*sptr2) + 1; + } + + /* print pixels */ + data[header_nlines] + = (char *) data + header_size + + (image->height + ext_nlines) * sizeof (char *); + + CreatePixels (data + header_nlines, data_size - header_nlines, + image->width, image->height, image->cpp, image->data, + image->colorTable); + + /* print extensions */ + if (extensions) + CreateExtensions (data + header_nlines + image->height - 1, + data_size - header_nlines - image->height + 1, + offset, info->extensions, info->nextensions, + ext_nlines); + + *data_return = data; + ErrorStatus = XpmSuccess; + +/* exit point, free only locally allocated variables */ +exit: + if (header) + { + for (l = 0; l < header_nlines; l++) + if (header[l]) + XpmFree (header[l]); + XpmFree (header); + } + return (ErrorStatus); +} + +static int +CreateColors (char **dataptr, unsigned int *data_size, + XpmColor *colors, unsigned int ncolors, + unsigned int cpp) +{ + char buf[BUFSIZ]; + unsigned int a, key, l; + char *s, *s2; + char **defaults; + + /* can ncolors be trusted here? */ + for (a = 0; a < ncolors; a++, colors++, dataptr++) + { + defaults = (char **) colors; + if (sizeof (buf) <= cpp) + return (XpmNoMemory); + strncpy (buf, *defaults++, cpp); + s = buf + cpp; + + if (sizeof (buf) <= (s - buf)) + return XpmNoMemory; + + for (key = 1; key <= NKEYS; key++, defaults++) + { + if ((s2 = *defaults)) + { +#ifndef VOID_SPRINTF + s += +#endif + /* assume C99 compliance */ + snprintf (s, sizeof (buf) - (s - buf), "\t%s %s", + xpmColorKeys[key - 1], s2); +#ifdef VOID_SPRINTF + s += strlen (s); +#endif + /* does s point out-of-bounds? */ + if (sizeof (buf) < (s - buf)) + return XpmNoMemory; + } + } + /* what about using strdup()? */ + l = s - buf + 1; + s = (char *) XpmMalloc (l); + if (!s) + return (XpmNoMemory); + *data_size += l; + *dataptr = strcpy (s, buf); + } + return (XpmSuccess); +} + +static void +CreatePixels (char **dataptr, unsigned int data_size, + unsigned int width, unsigned int height, + unsigned int cpp, unsigned int *pixels, + XpmColor *colors) +{ + char *s; + unsigned int x, y, h, offset; + + if (height <= 1) + return; + + h = height - 1; + + offset = width * cpp + 1; + + if (offset <= width || offset <= cpp) + return; + + /* why trust h? */ + for (y = 0; y < h; y++, dataptr++) + { + s = *dataptr; + /* why trust width? */ + for (x = 0; x < width; x++, pixels++) + { + if (cpp > (data_size - (s - *dataptr))) + return; + strncpy (s, colors[*pixels].string, + cpp); /* why trust pixel? */ + s += cpp; + } + *s = '\0'; + if (offset > data_size) + return; + *(dataptr + 1) = *dataptr + offset; + } + /* duplicate some code to avoid a test in the loop */ + s = *dataptr; + /* why trust width? */ + for (x = 0; x < width; x++, pixels++) + { + if (cpp > data_size - (s - *dataptr)) + return; + strncpy (s, colors[*pixels].string, + cpp); /* why should we trust *pixel? */ + s += cpp; + } + *s = '\0'; +} + +static int +CountExtensions (XpmExtension *ext, unsigned int num, + unsigned int *ext_size, unsigned int *ext_nlines) +{ + size_t len; + unsigned int x, y, a, size, nlines; + char **line; + + size = 0; + nlines = 0; + for (x = 0; x < num; x++, ext++) + { + /* 1 for the name */ + if (ext->nlines == UINT_MAX + || nlines > UINT_MAX - ext->nlines - 1) + return (1); + nlines += ext->nlines + 1; + /* 8 = 7 (for "XPMEXT ") + 1 (for 0) */ + len = strlen (ext->name) + 8; + if (len > UINT_MAX - size) + return (1); + size += len; + a = ext->nlines; + for (y = 0, line = ext->lines; y < a; y++, line++) + { + len = strlen (*line) + 1; + if (len > UINT_MAX - size) + return (1); + size += len; + } + } + if (size > UINT_MAX - 10 || nlines > UINT_MAX - 1) + return (1); + /* 10 and 1 are for the ending "XPMENDEXT" */ + *ext_size = size + 10; + *ext_nlines = nlines + 1; + return (0); +} + +static void +CreateExtensions (char **dataptr, unsigned int data_size, + unsigned int offset, XpmExtension *ext, + unsigned int num, unsigned int ext_nlines) +{ + unsigned int x, y, a, b; + char **line; + + *(dataptr + 1) = *dataptr + offset; + dataptr++; + a = 0; + for (x = 0; x < num; x++, ext++) + { + snprintf (*dataptr, data_size, "XPMEXT %s", ext->name); + a++; + if (a < ext_nlines) + *(dataptr + 1) = *dataptr + strlen (ext->name) + 8; + dataptr++; + b = ext->nlines; /* can we trust these values? */ + for (y = 0, line = ext->lines; y < b; y++, line++) + { + strcpy (*dataptr, *line); + a++; + if (a < ext_nlines) + *(dataptr + 1) = *dataptr + strlen (*line) + 1; + dataptr++; + } + } + strcpy (*dataptr, "XPMENDEXT"); +} diff --git a/be_xpm/CrDatFrP.c b/be_xpm/CrDatFrP.c new file mode 100644 index 0000000000..0e17fee140 --- /dev/null +++ b/be_xpm/CrDatFrP.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* CrDataFP.c: * +* * +* XPM library * +* Scan a pixmap and possibly its mask and create an XPM array * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +int +XpmCreateDataFromPixmap( + Display *display, + char ***data_return, + Pixmap pixmap, + Pixmap shapemask, + XpmAttributes *attributes) +{ + XImage *ximage = NULL; + XImage *shapeimage = NULL; + unsigned int width = 0; + unsigned int height = 0; + int ErrorStatus; + + /* get geometry */ + if (attributes && attributes->valuemask & XpmSize) { + width = attributes->width; + height = attributes->height; + } + /* get the ximages */ + if (pixmap) + xpmCreateImageFromPixmap(display, pixmap, &ximage, &width, &height); + if (shapemask) + xpmCreateImageFromPixmap(display, shapemask, &shapeimage, + &width, &height); + + /* create the data */ + ErrorStatus = XpmCreateDataFromImage(display, data_return, ximage, + shapeimage, attributes); + + /* destroy the ximages */ + if (ximage) + XDestroyImage(ximage); + if (shapeimage) + XDestroyImage(shapeimage); + + return (ErrorStatus); +} diff --git a/be_xpm/CrIFrBuf.c b/be_xpm/CrIFrBuf.c new file mode 100644 index 0000000000..b6b12cad1c --- /dev/null +++ b/be_xpm/CrIFrBuf.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* CrIFrBuf.c: * +* * +* XPM library * +* Parse an Xpm buffer (file in memory) and create the image and possibly its * +* mask * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +LFUNC(OpenBuffer, void, (char *buffer, xpmData *mdata)); + +int +XpmCreateImageFromBuffer( + Display *display, + char *buffer, + XImage **image_return, + XImage **shapeimage_return, + XpmAttributes *attributes) +{ + XpmImage image; + XpmInfo info; + int ErrorStatus; + xpmData mdata; + + xpmInitXpmImage(&image); + xpmInitXpmInfo(&info); + + /* open buffer to read */ + OpenBuffer(buffer, &mdata); + + /* create the XImage from the XpmData */ + if (attributes) { + xpmInitAttributes(attributes); + xpmSetInfoMask(&info, attributes); + ErrorStatus = xpmParseDataAndCreate(display, &mdata, + image_return, shapeimage_return, + &image, &info, attributes); + } else + ErrorStatus = xpmParseDataAndCreate(display, &mdata, + image_return, shapeimage_return, + &image, NULL, attributes); + if (attributes) { + if (ErrorStatus >= 0) /* no fatal error */ + xpmSetAttributes(attributes, &image, &info); + XpmFreeXpmInfo(&info); + } + + /* free the XpmImage */ + XpmFreeXpmImage(&image); + + return (ErrorStatus); +} + +int +XpmCreateXpmImageFromBuffer( + char *buffer, + XpmImage *image, + XpmInfo *info) +{ + xpmData mdata; + int ErrorStatus; + + /* init returned values */ + xpmInitXpmImage(image); + xpmInitXpmInfo(info); + + /* open buffer to read */ + OpenBuffer(buffer, &mdata); + + /* create the XpmImage from the XpmData */ + ErrorStatus = xpmParseData(&mdata, image, info); + + return (ErrorStatus); +} + +/* + * open the given buffer to be read or written as an xpmData which is returned + */ +static void +OpenBuffer( + char *buffer, + xpmData *mdata) +{ + mdata->type = XPMBUFFER; + mdata->cptr = buffer; + mdata->CommentLength = 0; +} diff --git a/be_xpm/CrIFrDat.c b/be_xpm/CrIFrDat.c new file mode 100644 index 0000000000..9ef1557218 --- /dev/null +++ b/be_xpm/CrIFrDat.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* CrIFrData.c: * +* * +* XPM library * +* Parse an Xpm array and create the image and possibly its mask * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +LFUNC(OpenArray, void, (char **data, xpmData *mdata)); + +int +XpmCreateImageFromData( + Display *display, + char **data, + XImage **image_return, + XImage **shapeimage_return, + XpmAttributes *attributes) +{ + XpmImage image; + XpmInfo info; + int ErrorStatus; + xpmData mdata; + + xpmInitXpmImage(&image); + xpmInitXpmInfo(&info); + + /* open data */ + OpenArray(data, &mdata); + + /* create an XpmImage from the file */ + if (attributes) { + xpmInitAttributes(attributes); + xpmSetInfoMask(&info, attributes); + ErrorStatus = xpmParseDataAndCreate(display, &mdata, + image_return, shapeimage_return, + &image, &info, attributes); + } else + ErrorStatus = xpmParseDataAndCreate(display, &mdata, + image_return, shapeimage_return, + &image, NULL, attributes); + if (attributes) { + if (ErrorStatus >= 0) /* no fatal error */ + xpmSetAttributes(attributes, &image, &info); + XpmFreeXpmInfo(&info); + } + + /* free the XpmImage */ + XpmFreeXpmImage(&image); + + return (ErrorStatus); +} + +int +XpmCreateXpmImageFromData( + char **data, + XpmImage *image, + XpmInfo *info) +{ + xpmData mdata; + int ErrorStatus; + + /* init returned values */ + xpmInitXpmImage(image); + xpmInitXpmInfo(info); + + /* open data */ + OpenArray(data, &mdata); + + /* create the XpmImage from the XpmData */ + ErrorStatus = xpmParseData(&mdata, image, info); + + return (ErrorStatus); +} + +/* + * open the given array to be read or written as an xpmData which is returned + */ +static void +OpenArray( + char **data, + xpmData *mdata) +{ + mdata->type = XPMARRAY; + mdata->stream.data = data; + mdata->cptr = *data; + mdata->line = 0; + mdata->CommentLength = 0; + mdata->Bcmt = mdata->Ecmt = NULL; + mdata->Bos = mdata->Eos = '\0'; + mdata->format = 0; /* this can only be Xpm 2 or 3 */ +} diff --git a/be_xpm/Image.c b/be_xpm/Image.c new file mode 100644 index 0000000000..e0223cc2a9 --- /dev/null +++ b/be_xpm/Image.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* Image.c: * +* * +* XPM library * +* Functions to init and free the XpmImage structure. * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +/* + * Init returned data to free safely later on + */ +void +xpmInitXpmImage(XpmImage *image) +{ + image->ncolors = 0; + image->colorTable = NULL; + image->data = NULL; +} + +/* + * Free the XpmImage data which have been allocated + */ +void +XpmFreeXpmImage(XpmImage *image) +{ + if (image->colorTable) + xpmFreeColorTable(image->colorTable, image->ncolors); + if (image->data) + XpmFree(image->data); + image->data = NULL; +} diff --git a/be_xpm/Info.c b/be_xpm/Info.c new file mode 100644 index 0000000000..e975a6dce6 --- /dev/null +++ b/be_xpm/Info.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* Info.c: * +* * +* XPM library * +* Functions related to the XpmInfo structure. * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +/* + * Init returned data to free safely later on + */ +void +xpmInitXpmInfo(XpmInfo *info) +{ + if (info) { + info->hints_cmt = NULL; + info->colors_cmt = NULL; + info->pixels_cmt = NULL; + info->extensions = NULL; + info->nextensions = 0; + } +} + +/* + * Free the XpmInfo data which have been allocated + */ +void +XpmFreeXpmInfo(XpmInfo *info) +{ + if (info) { + if (info->valuemask & XpmComments) { + if (info->hints_cmt) { + XpmFree(info->hints_cmt); + info->hints_cmt = NULL; + } + if (info->colors_cmt) { + XpmFree(info->colors_cmt); + info->colors_cmt = NULL; + } + if (info->pixels_cmt) { + XpmFree(info->pixels_cmt); + info->pixels_cmt = NULL; + } + } + if (info->valuemask & XpmReturnExtensions && info->nextensions) { + XpmFreeExtensions(info->extensions, info->nextensions); + info->extensions = NULL; + info->nextensions = 0; + } + info->valuemask = 0; + } +} + +/* + * Set the XpmInfo valuemask to retrieve required info + */ +void +xpmSetInfoMask( + XpmInfo *info, + XpmAttributes *attributes) +{ + info->valuemask = 0; + if (attributes->valuemask & XpmReturnInfos) + info->valuemask |= XpmReturnComments; + if (attributes->valuemask & XpmReturnExtensions) + info->valuemask |= XpmReturnExtensions; +} + +/* + * Fill in the XpmInfo with the XpmAttributes + */ +void +xpmSetInfo( + XpmInfo *info, + XpmAttributes *attributes) +{ + info->valuemask = 0; + if (attributes->valuemask & XpmInfos) { + info->valuemask |= XpmComments | XpmColorTable; + info->hints_cmt = attributes->hints_cmt; + info->colors_cmt = attributes->colors_cmt; + info->pixels_cmt = attributes->pixels_cmt; + } + if (attributes->valuemask & XpmExtensions) { + info->valuemask |= XpmExtensions; + info->extensions = attributes->extensions; + info->nextensions = attributes->nextensions; + } + if (attributes->valuemask & XpmHotspot) { + info->valuemask |= XpmHotspot; + info->x_hotspot = attributes->x_hotspot; + info->y_hotspot = attributes->y_hotspot; + } +} diff --git a/be_xpm/Makefile.in b/be_xpm/Makefile.in new file mode 100644 index 0000000000..9c368f222e --- /dev/null +++ b/be_xpm/Makefile.in @@ -0,0 +1,66 @@ +### @configure_input@ + +# Copyright (C) 2021 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs 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 3 of the License, or +# (at your option) any later version. + +# GNU Emacs 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 GNU Emacs. If not, see . + +CC=@CC@ +CFLAGS=@CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +AR = @AR@ + +top_builddir = @top_builddir@ + +HAVE_BE_APP = @HAVE_BE_APP@ +BE_XPM_OBJECTS = Attrib.o Info.o CrBufFrI.o CrDatFrI.o \ + create.o CrIFrBuf.o CrIFrDat.o data.o hashtab.o \ + Image.o misc.o parse.o RdFToBuf.o RdFToDat.o RdFToI.o \ + rgb.o scan.o +RM = rm -f +RANLIB = @RANLIB@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ + +-include ${top_builddir}/src/verbose.mk + +AUTO_DEPEND = @AUTO_DEPEND@ +DEPDIR = deps +ifeq ($(AUTO_DEPEND),yes) + DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP + -include $(BE_XPM_OBJECTS:%.o=$(DEPDIR)/%.d) +else + DEPFLAGS = + include $(srcdir)/deps.mk +endif + +all: libXpmBe.a +.PHONY: all + +.c.o: + $(AM_V_CC)$(CC) -c $(CPPFLAGS) -DFOR_MSW $(ALL_CFLAGS) -o $@ $< + +libXpmBe.a: $(BE_XPM_OBJECTS) + $(AM_V_GEN)$(RM) $@ + $(AM_V_at)$(AR) $(ARFLAGS) $@ $(BE_XPM_OBJECTS) $(EXTRA) + $(AM_V_at)$(RANLIB) $@ + +clean: + rm -f ./*.[ao] ./*/*.o ./*-t \#* $(DEPDIR)/*.d $(DEPDIR)/*/*.d +mostlyclean: clean + rm -f $(filter-out %-t,$(MOSTLYCLEANFILES)) +distclean bootstrap-clean: mostlyclean + rm -f Makefile + rm -fr $(DEPDIR) diff --git a/be_xpm/README b/be_xpm/README new file mode 100644 index 0000000000..0fd7dcd1c2 --- /dev/null +++ b/be_xpm/README @@ -0,0 +1,10 @@ +libXpm - X Pixmap (XPM) image file format library +------------------------------------------------- + +This directory contains a port of the X Pixmap library to Haiku; on +other platforms, Emacs uses the system libXpm. + +Almost everything neccessary is included in this directory, with the +notable exception of an implementation of everything in simx.h, which +is actually in the main Emacs source folder under the name +haiku_simx.c. \ No newline at end of file diff --git a/be_xpm/RdFToBuf.c b/be_xpm/RdFToBuf.c new file mode 100644 index 0000000000..eda52c3ce7 --- /dev/null +++ b/be_xpm/RdFToBuf.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* RdFToBuf.c: * +* * +* XPM library * +* Copy a file to a malloc'ed buffer, provided as a convenience. * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * The code related to FOR_MSW has been added by + * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 + */ + +/* October 2004, source code review by Thomas Biege */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" +#include +#if !defined(FOR_MSW) && !defined(WIN32) +#include +#endif +#ifndef VAX11C +#include +#endif + +int +XpmReadFileToBuffer( + const char *filename, + char **buffer_return) +{ + int fd, fcheck; + off_t len; + char *ptr; + struct stat stats; + FILE *fp; + + *buffer_return = NULL; + +#ifndef VAX11C + fd = open(filename, O_RDONLY); +#else + fd = open(filename, O_RDONLY, NULL); +#endif + if (fd < 0) + return XpmOpenFailed; + + if (fstat(fd, &stats)) { + close(fd); + return XpmOpenFailed; + } + fp = fdopen(fd, "r"); + if (!fp) { + close(fd); + return XpmOpenFailed; + } + len = stats.st_size; + if (len < 0 || len >= SIZE_MAX) { + fclose(fp); + return XpmOpenFailed; + } + ptr = (char *) XpmMalloc(len + 1); + if (!ptr) { + fclose(fp); + return XpmNoMemory; + } + fcheck = fread(ptr, 1, len, fp); + fclose(fp); +#ifdef VMS + /* VMS often stores text files in a variable-length record format, + where there are two bytes of size followed by the record. fread + converts this so it looks like a record followed by a newline. + Unfortunately, the size reported by fstat() (and fseek/ftell) + counts the two bytes for the record terminator, while fread() + counts only one. So, fread() sees fewer bytes in the file (size + minus # of records) and thus when asked to read the amount + returned by stat(), it fails. + The best solution, suggested by DEC, seems to consider the length + returned from fstat() as an upper bound and call fread() with + a record length of 1. Then don't check the return value. + We'll check for 0 for gross error that's all. + */ + len = fcheck; + if (fcheck == 0) { +#else + if (fcheck != len) { +#endif + XpmFree(ptr); + return XpmOpenFailed; + } + ptr[len] = '\0'; + *buffer_return = ptr; + return XpmSuccess; +} diff --git a/be_xpm/RdFToDat.c b/be_xpm/RdFToDat.c new file mode 100644 index 0000000000..fa92bd40a7 --- /dev/null +++ b/be_xpm/RdFToDat.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* RdFToDat.c: * +* * +* XPM library * +* Parse an XPM file and create an array of strings corresponding to it. * +* * +* Developed by Dan Greening dgreen@cs.ucla.edu / dgreen@sti.com * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +int +XpmReadFileToData( + const char *filename, + char ***data_return) +{ + XpmImage image; + XpmInfo info; + int ErrorStatus; + + info.valuemask = XpmReturnComments | XpmReturnExtensions; + + /* + * initialize return value + */ + if (data_return) + *data_return = NULL; + + ErrorStatus = XpmReadFileToXpmImage(filename, &image, &info); + if (ErrorStatus != XpmSuccess) + return (ErrorStatus); + + ErrorStatus = + XpmCreateDataFromXpmImage(data_return, &image, &info); + + XpmFreeXpmImage(&image); + XpmFreeXpmInfo(&info); + + return (ErrorStatus); +} diff --git a/be_xpm/RdFToI.c b/be_xpm/RdFToI.c new file mode 100644 index 0000000000..bd09611b19 --- /dev/null +++ b/be_xpm/RdFToI.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* RdFToI.c: * +* * +* XPM library * +* Parse an XPM file and create the image and possibly its mask * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* October 2004, source code review by Thomas Biege */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" +#ifndef NO_ZPIPE +#include +#include +#include +#include +#else +#ifdef FOR_MSW +#include +#endif +#endif + +LFUNC(OpenReadFile, int, (const char *filename, xpmData *mdata)); +LFUNC(xpmDataClose, void, (xpmData *mdata)); + +FUNC(xpmPipeThrough, FILE*, (int fd, + const char *cmd, + const char *arg1, + const char *mode)); + +#ifndef CXPMPROG +int +XpmReadFileToImage( + Display *display, + const char *filename, + XImage **image_return, + XImage **shapeimage_return, + XpmAttributes *attributes) +{ + XpmImage image; + XpmInfo info; + int ErrorStatus; + xpmData mdata; + + xpmInitXpmImage(&image); + xpmInitXpmInfo(&info); + + /* open file to read */ + if ((ErrorStatus = OpenReadFile(filename, &mdata)) != XpmSuccess) + return (ErrorStatus); + + /* create the XImage from the XpmData */ + if (attributes) { + xpmInitAttributes(attributes); + xpmSetInfoMask(&info, attributes); + ErrorStatus = xpmParseDataAndCreate(display, &mdata, + image_return, shapeimage_return, + &image, &info, attributes); + } else + ErrorStatus = xpmParseDataAndCreate(display, &mdata, + image_return, shapeimage_return, + &image, NULL, attributes); + if (attributes) { + if (ErrorStatus >= 0) /* no fatal error */ + xpmSetAttributes(attributes, &image, &info); + XpmFreeXpmInfo(&info); + } + + xpmDataClose(&mdata); + /* free the XpmImage */ + XpmFreeXpmImage(&image); + + return (ErrorStatus); +} + +int +XpmReadFileToXpmImage( + const char *filename, + XpmImage *image, + XpmInfo *info) +{ + xpmData mdata; + int ErrorStatus; + + /* init returned values */ + xpmInitXpmImage(image); + xpmInitXpmInfo(info); + + /* open file to read */ + if ((ErrorStatus = OpenReadFile(filename, &mdata)) != XpmSuccess) + return (ErrorStatus); + + /* create the XpmImage from the XpmData */ + ErrorStatus = xpmParseData(&mdata, image, info); + + xpmDataClose(&mdata); + + return (ErrorStatus); +} +#endif /* CXPMPROG */ + +#ifndef NO_ZPIPE +/* Do not depend on errno after read_through */ +FILE* +xpmPipeThrough( + int fd, + const char *cmd, + const char *arg1, + const char *mode) +{ + FILE* fp; + int status, fds[2], in = 0, out = 1; + pid_t pid; + if ( 'w' == *mode ) + out = 0, in = 1; + if ( pipe(fds) < 0 ) + return NULL; + pid = fork(); + if ( pid < 0 ) + goto fail1; + if ( 0 == pid ) + { + close(fds[in]); + if ( dup2(fds[out], out) < 0 ) + goto err; + close(fds[out]); + if ( dup2(fd, in) < 0 ) + goto err; + close(fd); + pid = fork(); + if ( pid < 0 ) + goto err; + if ( 0 == pid ) + { + execlp(cmd, cmd, arg1, (char *)NULL); + perror(cmd); + goto err; + } + _exit(0); + err: + _exit(1); + } + close(fds[out]); + /* calling process: wait for first child */ + while ( waitpid(pid, &status, 0) < 0 && EINTR == errno ) + ; + if ( WIFSIGNALED(status) || + (WIFEXITED(status) && WEXITSTATUS(status) != 0) ) + goto fail2; + fp = fdopen(fds[in], mode); + if ( !fp ) + goto fail2; + close(fd); /* still open in 2nd child */ + return fp; +fail1: + close(fds[out]); +fail2: + close(fds[in]); + return NULL; +} +#endif + +/* + * open the given file to be read as an xpmData which is returned. + */ +static int +OpenReadFile( + const char *filename, + xpmData *mdata) +{ + if (!filename) { + mdata->stream.file = (stdin); + mdata->type = XPMFILE; + } else { + int fd = open(filename, O_RDONLY); +#if defined(NO_ZPIPE) + if ( fd < 0 ) + return XpmOpenFailed; +#else + const char* ext = NULL; + if ( fd >= 0 ) + ext = strrchr(filename, '.'); +#ifdef STAT_ZFILE /* searching for z-files if the given name not found */ + else + { + size_t len = strlen(filename); + char *compressfile = (char *) XpmMalloc(len + 4); + if ( !compressfile ) + return (XpmNoMemory); + strcpy(compressfile, filename); + strcpy(compressfile + len, ext = ".Z"); + fd = open(compressfile, O_RDONLY); + if ( fd < 0 ) + { + strcpy(compressfile + len, ext = ".gz"); + fd = open(compressfile, O_RDONLY); + if ( fd < 0 ) + { + XpmFree(compressfile); + return XpmOpenFailed; + } + } + XpmFree(compressfile); + } +#endif + if ( ext && !strcmp(ext, ".Z") ) + { + mdata->type = XPMPIPE; + mdata->stream.file = xpmPipeThrough(fd, "uncompress", "-c", "r"); + } + else if ( ext && !strcmp(ext, ".gz") ) + { + mdata->type = XPMPIPE; + mdata->stream.file = xpmPipeThrough(fd, "gunzip", "-qc", "r"); + } + else +#endif /* z-files */ + { + mdata->type = XPMFILE; + mdata->stream.file = fdopen(fd, "r"); + } + if (!mdata->stream.file) + { + close(fd); + return (XpmOpenFailed); + } + } + mdata->CommentLength = 0; +#ifdef CXPMPROG + mdata->lineNum = 0; + mdata->charNum = 0; +#endif + return (XpmSuccess); +} + +/* + * close the file related to the xpmData if any + */ +static void +xpmDataClose(xpmData *mdata) +{ + if (mdata->stream.file != (stdin)) + fclose(mdata->stream.file); +} diff --git a/be_xpm/XpmI.h b/be_xpm/XpmI.h new file mode 100644 index 0000000000..4a251594f9 --- /dev/null +++ b/be_xpm/XpmI.h @@ -0,0 +1,334 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* XpmI.h: * +* * +* XPM library * +* Internal Include file * +* * +* ** Everything defined here is subject to changes any time. ** * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * The code related to FOR_MSW has been added by + * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 + */ + +#ifndef XPMI_h +#define XPMI_h + +#include "xpm_be.h" + +/* + * lets try to solve include files + */ + +#include +#include +#include +#include +/* stdio.h doesn't declare popen on a Sequent DYNIX OS */ +#ifdef sequent +extern FILE *popen(); +#endif + +#ifdef FOR_MSW +#include "simx.h" +#else +#include +#include +#include +#endif + +#ifdef VMS +#include +#include +#endif + +/* The following should help people wanting to use their own memory allocation + * functions. To avoid the overhead of a function call when the standard + * functions are used these are all macros, even the XpmFree function which + * needs to be a real function for the outside world though. + * So if change these be sure to change the XpmFree function in misc.c + * accordingly. + */ +#define XpmFree(ptr) free(ptr) + +#ifndef FOR_MSW +#define XpmMalloc(size) malloc((size)) +#define XpmRealloc(ptr, size) realloc((ptr), (size)) +#define XpmCalloc(nelem, elsize) calloc((nelem), (elsize)) +#else +/* checks for mallocs bigger than 64K */ +#define XpmMalloc(size) boundCheckingMalloc((long)(size))/* in simx.[ch] */ +#define XpmRealloc(ptr, size) boundCheckingRealloc((ptr),(long)(size)) +#define XpmCalloc(nelem, elsize) \ + boundCheckingCalloc((long)(nelem),(long) (elsize)) +#endif + +#if defined(SCO) || defined(__USLC__) +#include /* For SIZE_MAX */ +#endif +#include +#ifndef SIZE_MAX +# ifdef ULONG_MAX +# define SIZE_MAX ULONG_MAX +# else +# define SIZE_MAX UINT_MAX +# endif +#endif + +#define XPMMAXCMTLEN BUFSIZ +typedef struct { + unsigned int type; + union { + FILE *file; + char **data; + } stream; + char *cptr; + unsigned int line; + int CommentLength; + char Comment[XPMMAXCMTLEN]; + const char *Bcmt, *Ecmt; + char Bos, Eos; + int format; /* 1 if XPM1, 0 otherwise */ +#ifdef CXPMPROG + int lineNum; + int charNum; +#endif +} xpmData; + +#define XPMARRAY 0 +#define XPMFILE 1 +#define XPMPIPE 2 +#define XPMBUFFER 3 + +#define EOL '\n' +#define TAB '\t' +#define SPC ' ' + +typedef struct { + const char *type; /* key word */ + const char *Bcmt; /* string beginning comments */ + const char *Ecmt; /* string ending comments */ + char Bos; /* character beginning strings */ + char Eos; /* character ending strings */ + const char *Strs; /* strings separator */ + const char *Dec; /* data declaration string */ + const char *Boa; /* string beginning assignment */ + const char *Eoa; /* string ending assignment */ +} xpmDataType; + +extern xpmDataType xpmDataTypes[]; + +/* + * rgb values and ascii names (from rgb text file) rgb values, + * range of 0 -> 65535 color mnemonic of rgb value + */ +typedef struct { + int r, g, b; + char *name; +} xpmRgbName; + +/* Maximum number of rgb mnemonics allowed in rgb text file. */ +#define MAX_RGBNAMES 1024 + +extern const char *xpmColorKeys[]; + +#define TRANSPARENT_COLOR "None" /* this must be a string! */ + +/* number of xpmColorKeys */ +#define NKEYS 5 + +/* XPM internal routines */ + +FUNC(xpmParseData, int, (xpmData *data, XpmImage *image, XpmInfo *info)); +FUNC(xpmParseDataAndCreate, int, (Display *display, xpmData *data, + XImage **image_return, + XImage **shapeimage_return, + XpmImage *image, XpmInfo *info, + XpmAttributes *attributes)); + +FUNC(xpmFreeColorTable, void, (XpmColor *colorTable, int ncolors)); + +FUNC(xpmInitAttributes, void, (XpmAttributes *attributes)); + +FUNC(xpmInitXpmImage, void, (XpmImage *image)); + +FUNC(xpmInitXpmInfo, void, (XpmInfo *info)); + +FUNC(xpmSetInfoMask, void, (XpmInfo *info, XpmAttributes *attributes)); +FUNC(xpmSetInfo, void, (XpmInfo *info, XpmAttributes *attributes)); +FUNC(xpmSetAttributes, void, (XpmAttributes *attributes, XpmImage *image, + XpmInfo *info)); + +#if !defined(FOR_MSW) && !defined(AMIGA) +FUNC(xpmCreatePixmapFromImage, void, (Display *display, Drawable d, + XImage *ximage, Pixmap *pixmap_return)); + +FUNC(xpmCreateImageFromPixmap, void, (Display *display, Pixmap pixmap, + XImage **ximage_return, + unsigned int *width, + unsigned int *height)); +#endif + +/* structures and functions related to hastable code */ + +typedef struct _xpmHashAtom { + char *name; + void *data; +} *xpmHashAtom; + +typedef struct { + unsigned int size; + unsigned int limit; + unsigned int used; + xpmHashAtom *atomTable; +} xpmHashTable; + +FUNC(xpmHashTableInit, int, (xpmHashTable *table)); +FUNC(xpmHashTableFree, void, (xpmHashTable *table)); +FUNC(xpmHashSlot, xpmHashAtom *, (xpmHashTable *table, char *s)); +FUNC(xpmHashIntern, int, (xpmHashTable *table, char *tag, void *data)); + +#if defined(_MSC_VER) && defined(_M_X64) +#define HashAtomData(i) ((void *)(long long)i) +#define HashColorIndex(slot) ((unsigned long long)((*slot)->data)) +#else +#define HashAtomData(i) ((void *)(long)i) +#define HashColorIndex(slot) ((unsigned long)((*slot)->data)) +#endif +#define USE_HASHTABLE (cpp > 2 && ncolors > 4) + +/* I/O utility */ + +FUNC(xpmNextString, int, (xpmData *mdata)); +FUNC(xpmNextUI, int, (xpmData *mdata, unsigned int *ui_return)); +FUNC(xpmGetString, int, (xpmData *mdata, char **sptr, unsigned int *l)); + +#define xpmGetC(mdata) \ + ((!mdata->type || mdata->type == XPMBUFFER) ? \ + (*mdata->cptr++) : (getc(mdata->stream.file))) + +FUNC(xpmNextWord, unsigned int, + (xpmData *mdata, char *buf, unsigned int buflen)); +FUNC(xpmGetCmt, int, (xpmData *mdata, char **cmt)); +FUNC(xpmParseHeader, int, (xpmData *mdata)); +FUNC(xpmParseValues, int, (xpmData *data, unsigned int *width, + unsigned int *height, unsigned int *ncolors, + unsigned int *cpp, unsigned int *x_hotspot, + unsigned int *y_hotspot, unsigned int *hotspot, + unsigned int *extensions)); + +FUNC(xpmParseColors, int, (xpmData *data, unsigned int ncolors, + unsigned int cpp, XpmColor **colorTablePtr, + xpmHashTable *hashtable)); + +FUNC(xpmParseExtensions, int, (xpmData *data, XpmExtension **extensions, + unsigned int *nextensions)); + +/* RGB utility */ + +FUNC(xpmReadRgbNames, int, (char *rgb_fname, xpmRgbName *rgbn)); +FUNC(xpmGetRgbName, char *, (xpmRgbName *rgbn, int rgbn_max, + int red, int green, int blue)); +FUNC(xpmFreeRgbNames, void, (xpmRgbName *rgbn, int rgbn_max)); +#ifdef FOR_MSW +FUNC(xpmGetRGBfromName,int, (char *name, int *r, int *g, int *b)); +#endif + +#ifndef AMIGA +FUNC(xpm_xynormalizeimagebits, void, (register unsigned char *bp, + register XImage *img)); +FUNC(xpm_znormalizeimagebits, void, (register unsigned char *bp, + register XImage *img)); + +/* + * Macros + * + * The XYNORMALIZE macro determines whether XY format data requires + * normalization and calls a routine to do so if needed. The logic in + * this module is designed for LSBFirst byte and bit order, so + * normalization is done as required to present the data in this order. + * + * The ZNORMALIZE macro performs byte and nibble order normalization if + * required for Z format data. + * + * The XYINDEX macro computes the index to the starting byte (char) boundary + * for a bitmap_unit containing a pixel with coordinates x and y for image + * data in XY format. + * + * The ZINDEX* macros compute the index to the starting byte (char) boundary + * for a pixel with coordinates x and y for image data in ZPixmap format. + * + */ + +#define XYNORMALIZE(bp, img) \ + if ((img->byte_order == MSBFirst) || (img->bitmap_bit_order == MSBFirst)) \ + xpm_xynormalizeimagebits((unsigned char *)(bp), img) + +#define ZNORMALIZE(bp, img) \ + if (img->byte_order == MSBFirst) \ + xpm_znormalizeimagebits((unsigned char *)(bp), img) + +#define XYINDEX(x, y, img) \ + ((y) * img->bytes_per_line) + \ + (((x) + img->xoffset) / img->bitmap_unit) * (img->bitmap_unit >> 3) + +#define ZINDEX(x, y, img) ((y) * img->bytes_per_line) + \ + (((x) * img->bits_per_pixel) >> 3) + +#define ZINDEX32(x, y, img) ((y) * img->bytes_per_line) + ((x) << 2) + +#define ZINDEX16(x, y, img) ((y) * img->bytes_per_line) + ((x) << 1) + +#define ZINDEX8(x, y, img) ((y) * img->bytes_per_line) + (x) + +#define ZINDEX1(x, y, img) ((y) * img->bytes_per_line) + ((x) >> 3) +#endif /* not AMIGA */ + +#ifdef NEED_STRDUP +FUNC(xpmstrdup, char *, (char *s1)); +#else +#undef xpmstrdup +#define xpmstrdup strdup +#include +#endif + +#ifdef NEED_STRCASECMP +FUNC(xpmstrcasecmp, int, (char *s1, char *s2)); +#else +#undef xpmstrcasecmp +#define xpmstrcasecmp strcasecmp +#include +#endif + +FUNC(xpmatoui, unsigned int, + (char *p, unsigned int l, unsigned int *ui_return)); + +#endif diff --git a/be_xpm/create.c b/be_xpm/create.c new file mode 100644 index 0000000000..99bfabdbf4 --- /dev/null +++ b/be_xpm/create.c @@ -0,0 +1,2517 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL GROUPE BULL BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from GROUPE BULL. + */ + +/*****************************************************************************\ +* create.c: * +* * +* XPM library * +* Create an X image and possibly its related shape mask * +* from the given XpmImage. * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * The code related to FOR_MSW has been added by + * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 + */ + +/* + * The code related to AMIGA has been added by + * Lorens Younes (d93-hyo@nada.kth.se) 4/96 + */ + +/* October 2004, source code review by Thomas Biege + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include "XpmI.h" + +LFUNC (xpmVisualType, int, (Visual * visual)); + +LFUNC (AllocColor, int, + (Display * display, Colormap colormap, char *colorname, + XColor *xcolor, void *closure)); +LFUNC (FreeColors, int, + (Display * display, Colormap colormap, Pixel *pixels, int n, + void *closure)); + +#ifndef FOR_MSW +LFUNC (SetCloseColor, int, + (Display * display, Colormap colormap, Visual *visual, + XColor *col, Pixel *image_pixel, Pixel *mask_pixel, + Pixel *alloc_pixels, unsigned int *nalloc_pixels, + XpmAttributes *attributes, XColor *cols, int ncols, + XpmAllocColorFunc allocColor, void *closure)); +#else +/* let the window system take care of close colors */ +#endif + +LFUNC (SetColor, int, + (Display * display, Colormap colormap, Visual *visual, + char *colorname, unsigned int color_index, Pixel *image_pixel, + Pixel *mask_pixel, unsigned int *mask_pixel_index, + Pixel *alloc_pixels, unsigned int *nalloc_pixels, + Pixel *used_pixels, unsigned int *nused_pixels, + XpmAttributes *attributes, XColor *cols, int ncols, + XpmAllocColorFunc allocColor, void *closure)); + +LFUNC (CreateXImage, int, + (Display * display, Visual *visual, unsigned int depth, + int format, unsigned int width, unsigned int height, + XImage **image_return)); + +LFUNC (CreateColors, int, + (Display * display, XpmAttributes *attributes, + XpmColor *colors, unsigned int ncolors, Pixel *image_pixels, + Pixel *mask_pixels, unsigned int *mask_pixel_index, + Pixel *alloc_pixels, unsigned int *nalloc_pixels, + Pixel *used_pixels, unsigned int *nused_pixels)); + +#ifndef FOR_MSW +LFUNC (ParseAndPutPixels, int, + (xpmData * data, unsigned int width, unsigned int height, + unsigned int ncolors, unsigned int cpp, XpmColor *colorTable, + xpmHashTable *hashtable, XImage *image, Pixel *image_pixels, + XImage *mask, Pixel *mask_pixels)); +#else /* FOR_MSW */ +LFUNC (ParseAndPutPixels, int, + (Display * dc, xpmData *data, unsigned int width, + unsigned int height, unsigned int ncolors, unsigned int cpp, + XpmColor *colorTable, xpmHashTable *hashtable, XImage *image, + Pixel *image_pixels, XImage *mask, Pixel *mask_pixels)); +#endif + +#ifndef FOR_MSW +#ifndef AMIGA +/* XImage pixel routines */ +LFUNC (PutImagePixels, void, + (XImage * image, unsigned int width, unsigned int height, + unsigned int *pixelindex, Pixel *pixels)); + +LFUNC (PutImagePixels32, void, + (XImage * image, unsigned int width, unsigned int height, + unsigned int *pixelindex, Pixel *pixels)); + +LFUNC (PutImagePixels16, void, + (XImage * image, unsigned int width, unsigned int height, + unsigned int *pixelindex, Pixel *pixels)); + +LFUNC (PutImagePixels8, void, + (XImage * image, unsigned int width, unsigned int height, + unsigned int *pixelindex, Pixel *pixels)); + +LFUNC (PutImagePixels1, void, + (XImage * image, unsigned int width, unsigned int height, + unsigned int *pixelindex, Pixel *pixels)); + +LFUNC (PutPixel1, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +LFUNC (PutPixel, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +#if !defined(WORD64) && !defined(LONG64) +LFUNC (PutPixel32, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +#endif +LFUNC (PutPixel32MSB, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +LFUNC (PutPixel32LSB, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +LFUNC (PutPixel16MSB, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +LFUNC (PutPixel16LSB, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +LFUNC (PutPixel8, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +LFUNC (PutPixel1MSB, int, + (XImage * ximage, int x, int y, unsigned long pixel)); +LFUNC (PutPixel1LSB, int, + (XImage * ximage, int x, int y, unsigned long pixel)); + +#else /* AMIGA */ +LFUNC (APutImagePixels, void, + (XImage * ximage, unsigned int width, unsigned int height, + unsigned int *pixelindex, Pixel *pixels)); +#endif /* AMIGA */ +#else /* FOR_MSW */ +/* FOR_MSW pixel routine */ +LFUNC (MSWPutImagePixels, void, + (Display * dc, XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels)); +#endif /* FOR_MSW */ + +#ifdef NEED_STRCASECMP +FUNC (xpmstrcasecmp, int, (char *s1, char *s2)); + +/* + * in case strcasecmp is not provided by the system here is one + * which does the trick + */ +int +xpmstrcasecmp (register char *s1, register char *s2) +{ + register int c1, c2; + + while (*s1 && *s2) + { + c1 = tolower (*s1); + c2 = tolower (*s2); + if (c1 != c2) + return (c1 - c2); + s1++; + s2++; + } + return (int) (*s1 - *s2); +} + +#endif + +/* + * return the default color key related to the given visual + */ +static int +xpmVisualType (Visual *visual) +{ +#ifndef FOR_MSW +#ifndef AMIGA + switch (visual->class) + { + case StaticGray: + case GrayScale: + switch (visual->map_entries) + { + case 2: + return (XPM_MONO); + case 4: + return (XPM_GRAY4); + default: + return (XPM_GRAY); + } + default: + return (XPM_COLOR); + } +#else + /* set the key explicitly in the XpmAttributes to override this */ + return (XPM_COLOR); +#endif +#else + /* there should be a similar switch for MSW */ + return (XPM_COLOR); +#endif +} + +typedef struct +{ + int cols_index; + long closeness; +} CloseColor; + +static int +closeness_cmp (const void *a, const void *b) +{ + const CloseColor *x = (const CloseColor *) a, + *y = (const CloseColor *) b; + + /* cast to int as qsort requires */ + return (int) (x->closeness - y->closeness); +} + +/* default AllocColor function: + * call XParseColor if colorname is given, return negative value if + * failure call XAllocColor and return 0 if failure, positive + * otherwise + */ +static int +AllocColor (Display *display, Colormap colormap, char *colorname, + XColor *xcolor, void *closure) /* not used */ +{ + int status; + if (colorname) + if (!XParseColor (display, colormap, colorname, xcolor)) + return -1; + status = XAllocColor (display, colormap, xcolor); + return status != 0 ? 1 : 0; +} + +#ifndef FOR_MSW +/* + * set a close color in case the exact one can't be set + * return 0 if success, 1 otherwise. + */ + +static int +SetCloseColor (Display *display, Colormap colormap, Visual *visual, + XColor *col, Pixel *image_pixel, Pixel *mask_pixel, + Pixel *alloc_pixels, unsigned int *nalloc_pixels, + XpmAttributes *attributes, XColor *cols, int ncols, + XpmAllocColorFunc allocColor, void *closure) +{ + /* + * Allocation failed, so try close colors. To get here the visual + * must be GreyScale, PseudoColor or DirectColor (or perhaps + * StaticColor? What about sharing systems like QDSS?). Beware: we + * have to treat DirectColor differently. + */ + + long int red_closeness, green_closeness, blue_closeness; + int n; + Bool alloc_color; + + if (attributes && (attributes->valuemask & XpmCloseness)) + red_closeness = green_closeness = blue_closeness + = attributes->closeness; + else + { + red_closeness = attributes->red_closeness; + green_closeness = attributes->green_closeness; + blue_closeness = attributes->blue_closeness; + } + if (attributes && (attributes->valuemask & XpmAllocCloseColors)) + alloc_color = attributes->alloc_close_colors; + else + alloc_color = True; + + /* + * We sort the colormap by closeness and try to allocate the color + * closest to the target. If the allocation of this close color + * fails, which almost never happens, then one of two scenarios is + * possible. Either the colormap must have changed (since the last + * close color allocation or possibly while we were sorting the + * colormap), or the color is allocated as Read/Write by some + * other client. (Note: X _should_ allow clients to check if a + * particular color is Read/Write, but it doesn't! :-( ). We + * cannot determine which of these scenarios occurred, so we try + * the next closest color, and so on, until no more colors are + * within closeness of the target. If we knew that the colormap + * had changed, we could skip this sequence. + * + * If _none_ of the colors within closeness of the target can be + * allocated, then we can finally be pretty sure that the colormap + * has actually changed. In this case we try to allocate the + * original color (again), then try the closecolor stuff + * (again)... + * + * In theory it would be possible for an infinite loop to occur if + * another process kept changing the colormap every time we sorted + * it, so we set a maximum on the number of iterations. After this + * many tries, we use XGrabServer() to ensure that the colormap + * remains unchanged. + * + * This approach gives particularly bad worst case performance - + * as many as colormap reads and sorts may be + * needed, and as many as * + * attempted allocations may fail. On an 8-bit system, this means + * as many as 3 colormap reads, 3 sorts and 768 failed allocations + * per execution of this code! Luckily, my experiments show that + * in general use in a typical 8-bit color environment only about + * 1 in every 10000 allocations fails to succeed in the fastest + * possible time. So virtually every time what actually happens is + * a single sort followed by a successful allocate. The very first + * allocation also costs a colormap read, but no further reads are + * usually necessary. + */ + +#define ITERATIONS \ + 2 /* more than one is almost never \ + * necessary */ + + for (n = 0; n <= ITERATIONS; ++n) + { + CloseColor *closenesses + = (CloseColor *) XpmCalloc (ncols, sizeof (CloseColor)); + int i, c; + + for (i = 0; i < ncols; ++i) + { /* build & sort closenesses table */ +#define COLOR_FACTOR 3 +#define BRIGHTNESS_FACTOR 1 + + closenesses[i].cols_index = i; + closenesses[i].closeness + = COLOR_FACTOR + * (labs ((long) col->red - (long) cols[i].red) + + labs ((long) col->green - (long) cols[i].green) + + labs ((long) col->blue - (long) cols[i].blue)) + + BRIGHTNESS_FACTOR + * labs (((long) col->red + (long) col->green + + (long) col->blue) + - ((long) cols[i].red + (long) cols[i].green + + (long) cols[i].blue)); + } + qsort (closenesses, ncols, sizeof (CloseColor), closeness_cmp); + + i = 0; + c = closenesses[i].cols_index; + while ( + (long) cols[c].red >= (long) col->red - red_closeness + && (long) cols[c].red <= (long) col->red + red_closeness + && (long) cols[c].green >= (long) col->green - green_closeness + && (long) cols[c].green <= (long) col->green + green_closeness + && (long) cols[c].blue >= (long) col->blue - blue_closeness + && (long) cols[c].blue <= (long) col->blue + blue_closeness) + { + if (alloc_color) + { + if ((*allocColor) (display, colormap, NULL, &cols[c], + closure)) + { + if (n == ITERATIONS) + XUngrabServer (display); + XpmFree (closenesses); + *image_pixel = cols[c].pixel; + *mask_pixel = 1; + alloc_pixels[(*nalloc_pixels)++] = cols[c].pixel; + return (0); + } + else + { + ++i; + if (i == ncols) + break; + c = closenesses[i].cols_index; + } + } + else + { + if (n == ITERATIONS) + XUngrabServer (display); + XpmFree (closenesses); + *image_pixel = cols[c].pixel; + *mask_pixel = 1; + return (0); + } + } + + /* Couldn't allocate _any_ of the close colors! */ + + if (n == ITERATIONS) + XUngrabServer (display); + XpmFree (closenesses); + + if (i == 0 || i == ncols) /* no color close enough or cannot */ + return (1); /* alloc any color (full of r/w's) */ + + if ((*allocColor) (display, colormap, NULL, col, closure)) + { + *image_pixel = col->pixel; + *mask_pixel = 1; + alloc_pixels[(*nalloc_pixels)++] = col->pixel; + return (0); + } + else + { /* colormap has probably changed, so + * re-read... */ + if (n == ITERATIONS - 1) + XGrabServer (display); + +#if 0 + if (visual->class == DirectColor) { + /* TODO */ + } else +#endif + XQueryColors (display, colormap, cols, ncols); + } + } + return (1); +} + +#define USE_CLOSECOLOR \ + attributes \ + && (((attributes->valuemask & XpmCloseness) \ + && attributes->closeness != 0) \ + || ((attributes->valuemask & XpmRGBCloseness) \ + && (attributes->red_closeness != 0 \ + || attributes->green_closeness != 0 \ + || attributes->blue_closeness != 0))) + +#else +/* FOR_MSW part */ +/* nothing to do here, the window system does it */ +#endif + +/* + * set the color pixel related to the given colorname, + * return 0 if success, 1 otherwise. + */ + +static int +SetColor (Display *display, Colormap colormap, Visual *visual, + char *colorname, unsigned int color_index, + Pixel *image_pixel, Pixel *mask_pixel, + unsigned int *mask_pixel_index, Pixel *alloc_pixels, + unsigned int *nalloc_pixels, Pixel *used_pixels, + unsigned int *nused_pixels, XpmAttributes *attributes, + XColor *cols, int ncols, XpmAllocColorFunc allocColor, + void *closure) +{ + XColor xcolor; + int status; + + if (xpmstrcasecmp (colorname, TRANSPARENT_COLOR)) + { + status = (*allocColor) (display, colormap, colorname, &xcolor, + closure); + if (status < 0) /* parse color failed */ + return (1); + + if (status == 0) + { +#ifndef FOR_MSW + if (USE_CLOSECOLOR) + return (SetCloseColor (display, colormap, visual, &xcolor, + image_pixel, mask_pixel, + alloc_pixels, nalloc_pixels, + attributes, cols, ncols, + allocColor, closure)); + else +#endif /* ndef FOR_MSW */ + return (1); + } + else + alloc_pixels[(*nalloc_pixels)++] = xcolor.pixel; + *image_pixel = xcolor.pixel; + *mask_pixel = 1; + used_pixels[(*nused_pixels)++] = xcolor.pixel; + } + else + { + *image_pixel = 0; + *mask_pixel = 0; + /* store the color table index */ + *mask_pixel_index = color_index; + } + return (0); +} + +static int +CreateColors (Display *display, XpmAttributes *attributes, + XpmColor *colors, unsigned int ncolors, + Pixel *image_pixels, Pixel *mask_pixels, + unsigned int *mask_pixel_index, Pixel *alloc_pixels, + unsigned int *nalloc_pixels, Pixel *used_pixels, + unsigned int *nused_pixels) +{ + /* variables stored in the XpmAttributes structure */ + Visual *visual; + Colormap colormap; + XpmColorSymbol *colorsymbols = NULL; + unsigned int numsymbols; + XpmAllocColorFunc allocColor; + void *closure; + + char *colorname; + unsigned int color, key; + Bool pixel_defined; + XpmColorSymbol *symbol = NULL; + char **defaults; + int ErrorStatus = XpmSuccess; + char *s; + int default_index; + + XColor *cols = NULL; + unsigned int ncols = 0; + + /* + * retrieve information from the XpmAttributes + */ + if (attributes && attributes->valuemask & XpmColorSymbols) + { + colorsymbols = attributes->colorsymbols; + numsymbols = attributes->numsymbols; + } + else + numsymbols = 0; + + if (attributes && attributes->valuemask & XpmVisual) + visual = attributes->visual; + else + visual = XDefaultVisual (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmColormap)) + colormap = attributes->colormap; + else + colormap = XDefaultColormap (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmColorKey)) + key = attributes->color_key; + else + key = xpmVisualType (visual); + + if (attributes && (attributes->valuemask & XpmAllocColor)) + allocColor = attributes->alloc_color; + else + allocColor = AllocColor; + if (attributes && (attributes->valuemask & XpmColorClosure)) + closure = attributes->color_closure; + else + closure = NULL; + +#ifndef FOR_MSW + if (USE_CLOSECOLOR) + { + /* originally from SetCloseColor */ +#if 0 + if (visual->class == DirectColor) { + + /* + * TODO: Implement close colors for DirectColor visuals. This is + * difficult situation. Chances are that we will never get here, + * because any machine that supports DirectColor will probably + * also support TrueColor (and probably PseudoColor). Also, + * DirectColor colormaps can be very large, so looking for close + * colors may be too slow. + */ + } else { +#endif + unsigned int i; + +#ifndef AMIGA + ncols = visual->map_entries; +#else + ncols = colormap->Count; +#endif + cols = (XColor *) XpmCalloc (ncols, sizeof (XColor)); + for (i = 0; i < ncols; ++i) + cols[i].pixel = i; + XQueryColors (display, colormap, cols, ncols); +#if 0 + } +#endif + } +#endif /* ndef FOR_MSW */ + + switch (key) + { + case XPM_MONO: + default_index = 2; + break; + case XPM_GRAY4: + default_index = 3; + break; + case XPM_GRAY: + default_index = 4; + break; + case XPM_COLOR: + default: + default_index = 5; + break; + } + + for (color = 0; color < ncolors; + color++, colors++, image_pixels++, mask_pixels++) + { + colorname = NULL; + pixel_defined = False; + defaults = (char **) colors; + + /* + * look for a defined symbol + */ + if (numsymbols) + { + unsigned int n; + + s = defaults[1]; + for (n = 0, symbol = colorsymbols; n < numsymbols; + n++, symbol++) + { + if (symbol->name && s && !strcmp (symbol->name, s)) + /* override name */ + break; + if (!symbol->name && symbol->value) + { /* override value */ + int def_index = default_index; + + while (defaults[def_index] == NULL) /* find defined + * colorname */ + --def_index; + if (def_index < 2) + { /* nothing towards mono, so try + * towards color */ + def_index = default_index + 1; + while (def_index <= 5 + && defaults[def_index] == NULL) + ++def_index; + } + if (def_index >= 2 && def_index <= 5 + && defaults[def_index] != NULL + && !xpmstrcasecmp (symbol->value, + defaults[def_index])) + break; + } + } + if (n != numsymbols) + { + if (symbol->name && symbol->value) + colorname = symbol->value; + else + pixel_defined = True; + } + } + if (!pixel_defined) + { /* pixel not given as symbol value */ + + unsigned int k; + + if (colorname) + { /* colorname given as symbol value */ + if (!SetColor (display, colormap, visual, colorname, + color, image_pixels, mask_pixels, + mask_pixel_index, alloc_pixels, + nalloc_pixels, used_pixels, nused_pixels, + attributes, cols, ncols, allocColor, + closure)) + pixel_defined = True; + else + ErrorStatus = XpmColorError; + } + k = key; + while (!pixel_defined && k > 1) + { + if (defaults[k]) + { + if (!SetColor (display, colormap, visual, + defaults[k], color, image_pixels, + mask_pixels, mask_pixel_index, + alloc_pixels, nalloc_pixels, + used_pixels, nused_pixels, + attributes, cols, ncols, allocColor, + closure)) + { + pixel_defined = True; + break; + } + else + ErrorStatus = XpmColorError; + } + k--; + } + k = key + 1; + while (!pixel_defined && k < NKEYS + 1) + { + if (defaults[k]) + { + if (!SetColor (display, colormap, visual, + defaults[k], color, image_pixels, + mask_pixels, mask_pixel_index, + alloc_pixels, nalloc_pixels, + used_pixels, nused_pixels, + attributes, cols, ncols, allocColor, + closure)) + { + pixel_defined = True; + break; + } + else + ErrorStatus = XpmColorError; + } + k++; + } + if (!pixel_defined) + { + if (cols) + XpmFree (cols); + return (XpmColorFailed); + } + } + else + { + /* simply use the given pixel */ + *image_pixels = symbol->pixel; + /* the following makes the mask to be built even if none + is given a particular pixel */ + if (symbol->value + && !xpmstrcasecmp (symbol->value, TRANSPARENT_COLOR)) + { + *mask_pixels = 0; + *mask_pixel_index = color; + } + else + *mask_pixels = 1; + used_pixels[(*nused_pixels)++] = *image_pixels; + } + } + if (cols) + XpmFree (cols); + return (ErrorStatus); +} + +/* default FreeColors function, simply call XFreeColors */ +static int +FreeColors (Display *display, Colormap colormap, Pixel *pixels, int n, + void *closure) /* not used */ +{ + return XFreeColors (display, colormap, pixels, n, 0); +} + +/* function call in case of error */ + +#undef RETURN +#define RETURN(status) \ + do \ + { \ + ErrorStatus = status; \ + goto error; \ + } \ + while (0) + +int +XpmCreateImageFromXpmImage (Display *display, XpmImage *image, + XImage **image_return, + XImage **shapeimage_return, + XpmAttributes *attributes) +{ + /* variables stored in the XpmAttributes structure */ + Visual *visual; + Colormap colormap; + unsigned int depth; + int bitmap_format; + XpmFreeColorsFunc freeColors; + + /* variables to return */ + XImage *ximage = NULL; + XImage *shapeimage = NULL; + unsigned int mask_pixel_index = XpmUndefPixel; + int ErrorStatus; + + /* calculation variables */ + Pixel *image_pixels = NULL; + Pixel *mask_pixels = NULL; + Pixel *alloc_pixels = NULL; + Pixel *used_pixels = NULL; + unsigned int nalloc_pixels = 0; + unsigned int nused_pixels = 0; + + /* initialize return values */ + if (image_return) + *image_return = NULL; + if (shapeimage_return) + *shapeimage_return = NULL; + + /* retrieve information from the XpmAttributes */ + if (attributes && (attributes->valuemask & XpmVisual)) + visual = attributes->visual; + else + visual = XDefaultVisual (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmColormap)) + colormap = attributes->colormap; + else + colormap = XDefaultColormap (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmDepth)) + depth = attributes->depth; + else + depth = XDefaultDepth (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmBitmapFormat)) + bitmap_format = attributes->bitmap_format; + else + bitmap_format = ZPixmap; + + if (attributes && (attributes->valuemask & XpmFreeColors)) + freeColors = attributes->free_colors; + else + freeColors = FreeColors; + + ErrorStatus = XpmSuccess; + + if (image->ncolors >= UINT_MAX / sizeof (Pixel)) + return (XpmNoMemory); + + /* malloc pixels index tables */ + image_pixels + = (Pixel *) XpmMalloc (sizeof (Pixel) * image->ncolors); + if (!image_pixels) + return (XpmNoMemory); + + mask_pixels = (Pixel *) XpmMalloc (sizeof (Pixel) * image->ncolors); + if (!mask_pixels) + RETURN (XpmNoMemory); + + /* maximum of allocated pixels will be the number of colors */ + alloc_pixels + = (Pixel *) XpmMalloc (sizeof (Pixel) * image->ncolors); + if (!alloc_pixels) + RETURN (XpmNoMemory); + + /* maximum of allocated pixels will be the number of colors */ + used_pixels = (Pixel *) XpmMalloc (sizeof (Pixel) * image->ncolors); + if (!used_pixels) + RETURN (XpmNoMemory); + + /* get pixel colors, store them in index tables */ + ErrorStatus + = CreateColors (display, attributes, image->colorTable, + image->ncolors, image_pixels, mask_pixels, + &mask_pixel_index, alloc_pixels, &nalloc_pixels, + used_pixels, &nused_pixels); + + if (ErrorStatus != XpmSuccess + && (ErrorStatus < 0 + || (attributes && (attributes->valuemask & XpmExactColors) + && attributes->exactColors))) + RETURN (ErrorStatus); + + /* create the ximage */ + if (image_return) + { + ErrorStatus + = CreateXImage (display, visual, depth, + (depth == 1 ? bitmap_format : ZPixmap), + image->width, image->height, &ximage); + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + +#ifndef FOR_MSW +#ifndef AMIGA + + /* + * set the ximage data using optimized functions for ZPixmap + */ + + if (ximage->bits_per_pixel == 8) + PutImagePixels8 (ximage, image->width, image->height, + image->data, image_pixels); + else if (((ximage->bits_per_pixel | ximage->depth) == 1) + && (ximage->byte_order == ximage->bitmap_bit_order)) + PutImagePixels1 (ximage, image->width, image->height, + image->data, image_pixels); + else if (ximage->bits_per_pixel == 16) + PutImagePixels16 (ximage, image->width, image->height, + image->data, image_pixels); + else if (ximage->bits_per_pixel == 32) + PutImagePixels32 (ximage, image->width, image->height, + image->data, image_pixels); + else + PutImagePixels (ximage, image->width, image->height, + image->data, image_pixels); +#else /* AMIGA */ + APutImagePixels (ximage, image->width, image->height, + image->data, image_pixels); +#endif +#else /* FOR_MSW */ + MSWPutImagePixels (display, ximage, image->width, image->height, + image->data, image_pixels); +#endif + } + /* create the shape mask image */ + if (mask_pixel_index != XpmUndefPixel && shapeimage_return) + { + ErrorStatus + = CreateXImage (display, visual, 1, bitmap_format, + image->width, image->height, &shapeimage); + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + +#ifndef FOR_MSW +#ifndef AMIGA + PutImagePixels1 (shapeimage, image->width, image->height, + image->data, mask_pixels); +#else /* AMIGA */ + APutImagePixels (shapeimage, image->width, image->height, + image->data, mask_pixels); +#endif +#else /* FOR_MSW */ + MSWPutImagePixels (display, shapeimage, image->width, + image->height, image->data, mask_pixels); +#endif + } + XpmFree (image_pixels); + XpmFree (mask_pixels); + + /* if requested return used pixels in the XpmAttributes structure */ + if (attributes + && (attributes->valuemask & XpmReturnPixels || + /* 3.2 backward compatibility code */ + attributes->valuemask & XpmReturnInfos)) + { + /* end 3.2 bc */ + attributes->pixels = used_pixels; + attributes->npixels = nused_pixels; + attributes->mask_pixel = mask_pixel_index; + } + else + XpmFree (used_pixels); + + /* if requested return alloc'ed pixels in the XpmAttributes + * structure */ + if (attributes && (attributes->valuemask & XpmReturnAllocPixels)) + { + attributes->alloc_pixels = alloc_pixels; + attributes->nalloc_pixels = nalloc_pixels; + } + else + XpmFree (alloc_pixels); + + /* return created images */ + if (image_return) + *image_return = ximage; + if (shapeimage_return) + *shapeimage_return = shapeimage; + + return (ErrorStatus); + +/* exit point in case of error, free only locally allocated variables + */ +error: + if (ximage) + XDestroyImage (ximage); + if (shapeimage) + XDestroyImage (shapeimage); + if (image_pixels) + XpmFree (image_pixels); + if (mask_pixels) + XpmFree (mask_pixels); + if (nalloc_pixels) + (*freeColors) (display, colormap, alloc_pixels, nalloc_pixels, + NULL); + if (alloc_pixels) + XpmFree (alloc_pixels); + if (used_pixels) + XpmFree (used_pixels); + + return (ErrorStatus); +} + +/* + * Create an XImage with its data + */ +static int +CreateXImage (Display *display, Visual *visual, unsigned int depth, + int format, unsigned int width, unsigned int height, + XImage **image_return) +{ + int bitmap_pad; + + /* first get bitmap_pad */ + if (depth > 16) + bitmap_pad = 32; + else if (depth > 8) + bitmap_pad = 16; + else + bitmap_pad = 8; + + /* then create the XImage with data = NULL and bytes_per_line = 0 */ + *image_return = XCreateImage (display, visual, depth, format, 0, 0, + width, height, bitmap_pad, 0); + if (!*image_return) + return (XpmNoMemory); + +#if !defined(FOR_MSW) && !defined(AMIGA) + if (height != 0 + && (*image_return)->bytes_per_line >= INT_MAX / height) + { + XDestroyImage (*image_return); + return XpmNoMemory; + } + /* now that bytes_per_line must have been set properly alloc data */ + if ((*image_return)->bytes_per_line == 0 || height == 0) + return XpmNoMemory; + (*image_return)->data + = (char *) XpmMalloc ((*image_return)->bytes_per_line * height); + + if (!(*image_return)->data) + { + XDestroyImage (*image_return); + *image_return = NULL; + return (XpmNoMemory); + } +#else + /* under FOR_MSW and AMIGA XCreateImage has done it all */ +#endif + return (XpmSuccess); +} + +#ifndef FOR_MSW +#ifndef AMIGA +/* + * The functions below are written from X11R5 MIT's code (XImUtil.c) + * + * The idea is to have faster functions than the standard XPutPixel + * function to build the image data. Indeed we can speed up things by + * suppressing tests performed for each pixel. We do the same tests + * but at the image level. We also assume that we use only ZPixmap + * images with null offsets. + */ + +LFUNC (_putbits, void, + (register char *src, int dstoffset, register int numbits, + register char *dst)); + +LFUNC (_XReverse_Bytes, int, + (register unsigned char *bpt, register unsigned int nb)); + +static unsigned char const _reverse_byte[0x100] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, + 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, + 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, + 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, + 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, + 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, + 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, + 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, + 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, + 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, + 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, + 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, + 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, + 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, + 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, + 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, + 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, + 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, + 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, + 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, + 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, + 0xbf, 0x7f, 0xff +}; + +static int +_XReverse_Bytes (register unsigned char *bpt, + register unsigned int nb) +{ + do + { + *bpt = _reverse_byte[*bpt]; + bpt++; + } + while (--nb > 0); /* is nb user-controled? */ + return 0; +} + +void +xpm_xynormalizeimagebits (register unsigned char *bp, + register XImage *img) +{ + register unsigned char c; + + if (img->byte_order != img->bitmap_bit_order) + { + switch (img->bitmap_unit) + { + case 16: + c = *bp; + *bp = *(bp + 1); + *(bp + 1) = c; + break; + + case 32: + c = *(bp + 3); + *(bp + 3) = *bp; + *bp = c; + c = *(bp + 2); + *(bp + 2) = *(bp + 1); + *(bp + 1) = c; + break; + } + } + if (img->bitmap_bit_order == MSBFirst) + _XReverse_Bytes (bp, img->bitmap_unit >> 3); +} + +void +xpm_znormalizeimagebits (register unsigned char *bp, + register XImage *img) +{ + register unsigned char c; + + switch (img->bits_per_pixel) + { + case 2: + _XReverse_Bytes (bp, 1); + break; + + case 4: + *bp = ((*bp >> 4) & 0xF) | ((*bp << 4) & ~0xF); + break; + + case 16: + c = *bp; + *bp = *(bp + 1); + *(bp + 1) = c; + break; + + case 24: + c = *(bp + 2); + *(bp + 2) = *bp; + *bp = c; + break; + + case 32: + c = *(bp + 3); + *(bp + 3) = *bp; + *bp = c; + c = *(bp + 2); + *(bp + 2) = *(bp + 1); + *(bp + 1) = c; + break; + } +} + +static unsigned char const _lomask[0x09] + = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; +static unsigned char const _himask[0x09] + = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 }; + +static void +_putbits (register char *src, /* address of source bit string */ + int dstoffset, /* bit offset into destination; + * range is 0-31 */ + register int numbits, /* number of bits to copy to + * destination */ + register char *dst) /* address of destination bit string */ +{ + register unsigned char chlo, chhi; + int hibits; + + dst = dst + (dstoffset >> 3); + dstoffset = dstoffset & 7; + hibits = 8 - dstoffset; + chlo = *dst & _lomask[dstoffset]; + for (;;) + { + chhi = (*src << dstoffset) & _himask[dstoffset]; + if (numbits <= hibits) + { + chhi = chhi & _lomask[dstoffset + numbits]; + *dst = (*dst & _himask[dstoffset + numbits]) | chlo | chhi; + break; + } + *dst = chhi | chlo; + dst++; + numbits = numbits - hibits; + chlo = (unsigned char) (*src & _himask[hibits]) >> hibits; + src++; + if (numbits <= dstoffset) + { + chlo = chlo & _lomask[numbits]; + *dst = (*dst & _himask[numbits]) | chlo; + break; + } + numbits = numbits - dstoffset; + } +} + +/* + * Default method to write pixels into a Z image data structure. + * The algorithm used is: + * + * copy the destination bitmap_unit or Zpixel to temp + * normalize temp if needed + * copy the pixel bits into the temp + * renormalize temp if needed + * copy the temp back into the destination image data + */ + +static void +PutImagePixels (XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels) +{ + register char *src; + register char *dst; + register unsigned int *iptr; + register unsigned int x, y; + register char *data; + Pixel pixel, px; + int nbytes, depth, ibu, ibpp, i; + + data = image->data; + iptr = pixelindex; + depth = image->depth; + if (depth == 1) + { + ibu = image->bitmap_unit; + for (y = 0; y < height; y++) /* how can we trust height */ + for (x = 0; x < width; x++, iptr++) + { /* how can we trust width */ + pixel = pixels[*iptr]; + for (i = 0, px = pixel; i < sizeof (unsigned long); + i++, px >>= 8) + ((unsigned char *) &pixel)[i] = px; + src = &data[XYINDEX (x, y, image)]; + dst = (char *) &px; + px = 0; + nbytes = ibu >> 3; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + XYNORMALIZE (&px, image); + _putbits ((char *) &pixel, (x % ibu), 1, (char *) &px); + XYNORMALIZE (&px, image); + src = (char *) &px; + dst = &data[XYINDEX (x, y, image)]; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + } + } + else + { + ibpp = image->bits_per_pixel; + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + pixel = pixels[*iptr]; + if (depth == 4) + pixel &= 0xf; + for (i = 0, px = pixel; i < sizeof (unsigned long); + i++, px >>= 8) + ((unsigned char *) &pixel)[i] = px; + src = &data[ZINDEX (x, y, image)]; + dst = (char *) &px; + px = 0; + nbytes = (ibpp + 7) >> 3; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + ZNORMALIZE (&px, image); + _putbits ((char *) &pixel, (x * ibpp) & 7, ibpp, + (char *) &px); + ZNORMALIZE (&px, image); + src = (char *) &px; + dst = &data[ZINDEX (x, y, image)]; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + } + } +} + +/* + * write pixels into a 32-bits Z image data structure + */ + +#if !defined(WORD64) && !defined(LONG64) +/* this item is static but deterministic so let it slide; doesn't + * hurt re-entrancy of this library. Note if it is actually const then + * would be OK under rules of ANSI-C but probably not C++ which may + * not want to allocate space for it. + */ +static unsigned long byteorderpixel = MSBFirst << 24; + +#endif + +/* + WITHOUT_SPEEDUPS is a flag to be turned on if you wish to use the + original 3.2e code - by default you get the speeded-up version. +*/ + +static void +PutImagePixels32 (XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels) +{ + unsigned char *data; + unsigned int *iptr; + unsigned int y; + Pixel pixel; + +#ifdef WITHOUT_SPEEDUPS + + unsigned int x; + unsigned char *addr; + + data = (unsigned char *) image->data; + iptr = pixelindex; +#if !defined(WORD64) && !defined(LONG64) + if (*((char *) &byteorderpixel) == image->byte_order) + { + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + addr = &data[ZINDEX32 (x, y, image)]; + *((unsigned long *) addr) = pixels[*iptr]; + } + } + else +#endif + if (image->byte_order == MSBFirst) + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + addr = &data[ZINDEX32 (x, y, image)]; + pixel = pixels[*iptr]; + addr[0] = pixel >> 24; + addr[1] = pixel >> 16; + addr[2] = pixel >> 8; + addr[3] = pixel; + } + else + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + addr = &data[ZINDEX32 (x, y, image)]; + pixel = pixels[*iptr]; + addr[0] = pixel; + addr[1] = pixel >> 8; + addr[2] = pixel >> 16; + addr[3] = pixel >> 24; + } + +#else /* WITHOUT_SPEEDUPS */ + + unsigned int bpl = image->bytes_per_line; + unsigned char *data_ptr, *max_data; + + data = (unsigned char *) image->data; + iptr = pixelindex; +#if !defined(WORD64) && !defined(LONG64) + if (*((char *) &byteorderpixel) == image->byte_order) + { + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + (width << 2); + + while (data_ptr < max_data) + { + *((unsigned long *) data_ptr) = pixels[*(iptr++)]; + data_ptr += (1 << 2); + } + data += bpl; + } + } + else +#endif + if (image->byte_order == MSBFirst) + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + (width << 2); + + while (data_ptr < max_data) + { + pixel = pixels[*(iptr++)]; + + *data_ptr++ = pixel >> 24; + *data_ptr++ = pixel >> 16; + *data_ptr++ = pixel >> 8; + *data_ptr++ = pixel; + } + data += bpl; + } + else + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + (width << 2); + + while (data_ptr < max_data) + { + pixel = pixels[*(iptr++)]; + + *data_ptr++ = pixel; + *data_ptr++ = pixel >> 8; + *data_ptr++ = pixel >> 16; + *data_ptr++ = pixel >> 24; + } + data += bpl; + } + +#endif /* WITHOUT_SPEEDUPS */ +} + +/* + * write pixels into a 16-bits Z image data structure + */ + +static void +PutImagePixels16 (XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels) +{ + unsigned char *data; + unsigned int *iptr; + unsigned int y; + +#ifdef WITHOUT_SPEEDUPS + + unsigned int x; + unsigned char *addr; + + data = (unsigned char *) image->data; + iptr = pixelindex; + if (image->byte_order == MSBFirst) + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + addr = &data[ZINDEX16 (x, y, image)]; + addr[0] = pixels[*iptr] >> 8; + addr[1] = pixels[*iptr]; + } + else + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + addr = &data[ZINDEX16 (x, y, image)]; + addr[0] = pixels[*iptr]; + addr[1] = pixels[*iptr] >> 8; + } + +#else /* WITHOUT_SPEEDUPS */ + + Pixel pixel; + + unsigned int bpl = image->bytes_per_line; + unsigned char *data_ptr, *max_data; + + data = (unsigned char *) image->data; + iptr = pixelindex; + if (image->byte_order == MSBFirst) + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + (width << 1); + + while (data_ptr < max_data) + { + pixel = pixels[*(iptr++)]; + + data_ptr[0] = pixel >> 8; + data_ptr[1] = pixel; + + data_ptr += (1 << 1); + } + data += bpl; + } + else + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + (width << 1); + + while (data_ptr < max_data) + { + pixel = pixels[*(iptr++)]; + + data_ptr[0] = pixel; + data_ptr[1] = pixel >> 8; + + data_ptr += (1 << 1); + } + data += bpl; + } + +#endif /* WITHOUT_SPEEDUPS */ +} + +/* + * write pixels into a 8-bits Z image data structure + */ + +static void +PutImagePixels8 (XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels) +{ + char *data; + unsigned int *iptr; + unsigned int y; + +#ifdef WITHOUT_SPEEDUPS + + unsigned int x; + + data = image->data; + iptr = pixelindex; + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + data[ZINDEX8 (x, y, image)] = pixels[*iptr]; + +#else /* WITHOUT_SPEEDUPS */ + + unsigned int bpl = image->bytes_per_line; + char *data_ptr, *max_data; + + data = image->data; + iptr = pixelindex; + + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + width; + + while (data_ptr < max_data) + *(data_ptr++) = pixels[*(iptr++)]; + + data += bpl; + } + +#endif /* WITHOUT_SPEEDUPS */ +} + +/* + * write pixels into a 1-bit depth image data structure and **offset + * null** + */ + +static void +PutImagePixels1 (XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels) +{ + if (image->byte_order != image->bitmap_bit_order) + PutImagePixels (image, width, height, pixelindex, pixels); + else + { + unsigned int *iptr; + unsigned int y; + char *data; + +#ifdef WITHOUT_SPEEDUPS + + unsigned int x; + + data = image->data; + iptr = pixelindex; + if (image->bitmap_bit_order == MSBFirst) + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + if (pixels[*iptr] & 1) + data[ZINDEX1 (x, y, image)] |= 0x80 >> (x & 7); + else + data[ZINDEX1 (x, y, image)] &= ~(0x80 >> (x & 7)); + } + else + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) + { + if (pixels[*iptr] & 1) + data[ZINDEX1 (x, y, image)] |= 1 << (x & 7); + else + data[ZINDEX1 (x, y, image)] &= ~(1 << (x & 7)); + } + +#else /* WITHOUT_SPEEDUPS */ + + char value; + char *data_ptr, *max_data; + int bpl = image->bytes_per_line; + int diff, count; + + data = image->data; + iptr = pixelindex; + + diff = width & 7; + width >>= 3; + + if (image->bitmap_bit_order == MSBFirst) + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + width; + while (data_ptr < max_data) + { + value = 0; + + value = (value << 1) | (pixels[*(iptr++)] & 1); + value = (value << 1) | (pixels[*(iptr++)] & 1); + value = (value << 1) | (pixels[*(iptr++)] & 1); + value = (value << 1) | (pixels[*(iptr++)] & 1); + value = (value << 1) | (pixels[*(iptr++)] & 1); + value = (value << 1) | (pixels[*(iptr++)] & 1); + value = (value << 1) | (pixels[*(iptr++)] & 1); + value = (value << 1) | (pixels[*(iptr++)] & 1); + + *(data_ptr++) = value; + } + if (diff) + { + value = 0; + for (count = 0; count < diff; count++) + { + if (pixels[*(iptr++)] & 1) + value |= (0x80 >> count); + } + *(data_ptr) = value; + } + data += bpl; + } + else + for (y = 0; y < height; y++) + { + data_ptr = data; + max_data = data_ptr + width; + while (data_ptr < max_data) + { + value = 0; + iptr += 8; + + value = (value << 1) | (pixels[*(--iptr)] & 1); + value = (value << 1) | (pixels[*(--iptr)] & 1); + value = (value << 1) | (pixels[*(--iptr)] & 1); + value = (value << 1) | (pixels[*(--iptr)] & 1); + value = (value << 1) | (pixels[*(--iptr)] & 1); + value = (value << 1) | (pixels[*(--iptr)] & 1); + value = (value << 1) | (pixels[*(--iptr)] & 1); + value = (value << 1) | (pixels[*(--iptr)] & 1); + + iptr += 8; + *(data_ptr++) = value; + } + if (diff) + { + value = 0; + for (count = 0; count < diff; count++) + { + if (pixels[*(iptr++)] & 1) + value |= (1 << count); + } + *(data_ptr) = value; + } + data += bpl; + } + +#endif /* WITHOUT_SPEEDUPS */ + } +} + +int +XpmCreatePixmapFromXpmImage (Display *display, Drawable d, + XpmImage *image, Pixmap *pixmap_return, + Pixmap *shapemask_return, + XpmAttributes *attributes) +{ + XImage *ximage, *shapeimage; + int ErrorStatus; + + /* initialize return values */ + if (pixmap_return) + *pixmap_return = 0; + if (shapemask_return) + *shapemask_return = 0; + + /* create the ximages */ + ErrorStatus + = XpmCreateImageFromXpmImage (display, image, + (pixmap_return ? &ximage : NULL), + (shapemask_return ? &shapeimage + : NULL), + attributes); + if (ErrorStatus < 0) + return (ErrorStatus); + + /* create the pixmaps and destroy images */ + if (pixmap_return && ximage) + { + xpmCreatePixmapFromImage (display, d, ximage, pixmap_return); + XDestroyImage (ximage); + } + if (shapemask_return && shapeimage) + { + xpmCreatePixmapFromImage (display, d, shapeimage, + shapemask_return); + XDestroyImage (shapeimage); + } + return (ErrorStatus); +} + +#else /* AMIGA */ + +static void +APutImagePixels (XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels) +{ + unsigned int *data = pixelindex; + unsigned int x, y; + unsigned char *array; + XImage *tmp_img; + BOOL success = FALSE; + + array = XpmMalloc ((((width + 15) >> 4) << 4) * sizeof (*array)); + if (array != NULL) + { + tmp_img = AllocXImage ((((width + 15) >> 4) << 4), 1, + image->rp->BitMap->Depth); + if (tmp_img != NULL) + { + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + array[x] = pixels[*(data++)]; + WritePixelLine8 (image->rp, 0, y, width, array, + tmp_img->rp); + } + FreeXImage (tmp_img); + success = TRUE; + } + XpmFree (array); + } + + if (!success) + { + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) + XPutPixel (image, x, y, pixels[*(data++)]); + } +} + +#endif /* AMIGA */ +#else /* FOR_MSW part follows */ +static void +MSWPutImagePixels (Display *dc, XImage *image, unsigned int width, + unsigned int height, unsigned int *pixelindex, + Pixel *pixels) +{ + unsigned int *data = pixelindex; + unsigned int x, y; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + XPutPixel (image, x, y, + pixels[*(data++)]); /* data is [x+y*width] */ + } + } +} + +#endif /* FOR_MSW */ + +#if !defined(FOR_MSW) && !defined(AMIGA) + +static int +PutPixel1 (register XImage *ximage, int x, int y, unsigned long pixel) +{ + register char *src; + register char *dst; + register int i; + Pixel px; + int nbytes; + + if (x < 0 || y < 0) + return 0; + + for (i = 0, px = pixel; i < sizeof (unsigned long); i++, px >>= 8) + ((unsigned char *) &pixel)[i] = px; + src = &ximage->data[XYINDEX (x, y, ximage)]; + dst = (char *) &px; + px = 0; + nbytes = ximage->bitmap_unit >> 3; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + XYNORMALIZE (&px, ximage); + i = ((x + ximage->xoffset) % ximage->bitmap_unit); + _putbits ((char *) &pixel, i, 1, (char *) &px); + XYNORMALIZE (&px, ximage); + src = (char *) &px; + dst = &ximage->data[XYINDEX (x, y, ximage)]; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + + return 1; +} + +static int +PutPixel (register XImage *ximage, int x, int y, unsigned long pixel) +{ + register char *src; + register char *dst; + register int i; + Pixel px; + unsigned int nbytes, ibpp; + + if (x < 0 || y < 0) + return 0; + + ibpp = ximage->bits_per_pixel; + if (ximage->depth == 4) + pixel &= 0xf; + for (i = 0, px = pixel; i < sizeof (unsigned long); i++, px >>= 8) + ((unsigned char *) &pixel)[i] = px; + src = &ximage->data[ZINDEX (x, y, ximage)]; + dst = (char *) &px; + px = 0; + nbytes = (ibpp + 7) >> 3; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + ZNORMALIZE (&px, ximage); + _putbits ((char *) &pixel, (x * ibpp) & 7, ibpp, (char *) &px); + ZNORMALIZE (&px, ximage); + src = (char *) &px; + dst = &ximage->data[ZINDEX (x, y, ximage)]; + for (i = nbytes; --i >= 0;) + *dst++ = *src++; + + return 1; +} + +#if !defined(WORD64) && !defined(LONG64) +static int +PutPixel32 (register XImage *ximage, int x, int y, + unsigned long pixel) +{ + unsigned char *addr; + + if (x < 0 || y < 0) + return 0; + + addr = &((unsigned char *) ximage->data)[ZINDEX32 (x, y, ximage)]; + *((unsigned long *) addr) = pixel; + return 1; +} +#endif + +static int +PutPixel32MSB (register XImage *ximage, int x, int y, + unsigned long pixel) +{ + unsigned char *addr; + + if (x < 0 || y < 0) + return 0; + + addr = &((unsigned char *) ximage->data)[ZINDEX32 (x, y, ximage)]; + addr[0] = pixel >> 24; + addr[1] = pixel >> 16; + addr[2] = pixel >> 8; + addr[3] = pixel; + return 1; +} + +static int +PutPixel32LSB (register XImage *ximage, int x, int y, + unsigned long pixel) +{ + unsigned char *addr; + + if (x < 0 || y < 0) + return 0; + + addr = &((unsigned char *) ximage->data)[ZINDEX32 (x, y, ximage)]; + addr[3] = pixel >> 24; + addr[2] = pixel >> 16; + addr[1] = pixel >> 8; + addr[0] = pixel; + return 1; +} + +static int +PutPixel16MSB (register XImage *ximage, int x, int y, + unsigned long pixel) +{ + unsigned char *addr; + + if (x < 0 || y < 0) + return 0; + + addr = &((unsigned char *) ximage->data)[ZINDEX16 (x, y, ximage)]; + addr[0] = pixel >> 8; + addr[1] = pixel; + return 1; +} + +static int +PutPixel16LSB (register XImage *ximage, int x, int y, + unsigned long pixel) +{ + unsigned char *addr; + + if (x < 0 || y < 0) + return 0; + + addr = &((unsigned char *) ximage->data)[ZINDEX16 (x, y, ximage)]; + addr[1] = pixel >> 8; + addr[0] = pixel; + return 1; +} + +static int +PutPixel8 (register XImage *ximage, int x, int y, unsigned long pixel) +{ + if (x < 0 || y < 0) + return 0; + + ximage->data[ZINDEX8 (x, y, ximage)] = pixel; + return 1; +} + +static int +PutPixel1MSB (register XImage *ximage, int x, int y, + unsigned long pixel) +{ + if (x < 0 || y < 0) + return 0; + + if (pixel & 1) + ximage->data[ZINDEX1 (x, y, ximage)] |= 0x80 >> (x & 7); + else + ximage->data[ZINDEX1 (x, y, ximage)] &= ~(0x80 >> (x & 7)); + return 1; +} + +static int +PutPixel1LSB (register XImage *ximage, int x, int y, + unsigned long pixel) +{ + if (x < 0 || y < 0) + return 0; + + if (pixel & 1) + ximage->data[ZINDEX1 (x, y, ximage)] |= 1 << (x & 7); + else + ximage->data[ZINDEX1 (x, y, ximage)] &= ~(1 << (x & 7)); + return 1; +} + +#endif /* not FOR_MSW && not AMIGA */ + +/* + * This function parses an Xpm file or data and directly create an + * XImage + */ +int +xpmParseDataAndCreate (Display *display, xpmData *data, + XImage **image_return, + XImage **shapeimage_return, XpmImage *image, + XpmInfo *info, XpmAttributes *attributes) +{ + /* variables stored in the XpmAttributes structure */ + Visual *visual; + Colormap colormap; + unsigned int depth; + int bitmap_format; + XpmFreeColorsFunc freeColors; + + /* variables to return */ + XImage *ximage = NULL; + XImage *shapeimage = NULL; + unsigned int mask_pixel_index = XpmUndefPixel; + + /* calculation variables */ + Pixel *image_pixels = NULL; + Pixel *mask_pixels = NULL; + Pixel *alloc_pixels = NULL; + Pixel *used_pixels = NULL; + unsigned int nalloc_pixels = 0; + unsigned int nused_pixels = 0; + unsigned int width, height, ncolors, cpp; + unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0; + XpmColor *colorTable = NULL; + char *hints_cmt = NULL; + char *colors_cmt = NULL; + char *pixels_cmt = NULL; + + unsigned int cmts; + int ErrorStatus; + xpmHashTable hashtable; + + /* initialize return values */ + if (image_return) + *image_return = NULL; + if (shapeimage_return) + *shapeimage_return = NULL; + + /* retrieve information from the XpmAttributes */ + if (attributes && (attributes->valuemask & XpmVisual)) + visual = attributes->visual; + else + visual = XDefaultVisual (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmColormap)) + colormap = attributes->colormap; + else + colormap = XDefaultColormap (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmDepth)) + depth = attributes->depth; + else + depth = XDefaultDepth (display, XDefaultScreen (display)); + + if (attributes && (attributes->valuemask & XpmBitmapFormat)) + bitmap_format = attributes->bitmap_format; + else + bitmap_format = ZPixmap; + + if (attributes && (attributes->valuemask & XpmFreeColors)) + freeColors = attributes->free_colors; + else + freeColors = FreeColors; + + cmts = info && (info->valuemask & XpmReturnComments); + + /* + * parse the header + */ + ErrorStatus = xpmParseHeader (data); + if (ErrorStatus != XpmSuccess) + return (ErrorStatus); + + /* + * read values + */ + ErrorStatus + = xpmParseValues (data, &width, &height, &ncolors, &cpp, + &x_hotspot, &y_hotspot, &hotspot, &extensions); + if (ErrorStatus != XpmSuccess) + return (ErrorStatus); + + /* + * store the hints comment line + */ + if (cmts) + xpmGetCmt (data, &hints_cmt); + + /* + * init the hashtable + */ + if (USE_HASHTABLE) + { + ErrorStatus = xpmHashTableInit (&hashtable); + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + } + + /* + * read colors + */ + ErrorStatus + = xpmParseColors (data, ncolors, cpp, &colorTable, &hashtable); + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + + /* + * store the colors comment line + */ + if (cmts) + xpmGetCmt (data, &colors_cmt); + + /* malloc pixels index tables */ + if (ncolors >= UINT_MAX / sizeof (Pixel)) + RETURN (XpmNoMemory); + + image_pixels = (Pixel *) XpmMalloc (sizeof (Pixel) * ncolors); + if (!image_pixels) + RETURN (XpmNoMemory); + + mask_pixels = (Pixel *) XpmMalloc (sizeof (Pixel) * ncolors); + if (!mask_pixels) + RETURN (XpmNoMemory); + + /* maximum of allocated pixels will be the number of colors */ + alloc_pixels = (Pixel *) XpmMalloc (sizeof (Pixel) * ncolors); + if (!alloc_pixels) + RETURN (XpmNoMemory); + + /* maximum of allocated pixels will be the number of colors */ + used_pixels = (Pixel *) XpmMalloc (sizeof (Pixel) * ncolors); + if (!used_pixels) + RETURN (XpmNoMemory); + + /* get pixel colors, store them in index tables */ + ErrorStatus + = CreateColors (display, attributes, colorTable, ncolors, + image_pixels, mask_pixels, &mask_pixel_index, + alloc_pixels, &nalloc_pixels, used_pixels, + &nused_pixels); + + if (ErrorStatus != XpmSuccess + && (ErrorStatus < 0 + || (attributes && (attributes->valuemask & XpmExactColors) + && attributes->exactColors))) + RETURN (ErrorStatus); + + /* now create the ximage */ + if (image_return) + { + ErrorStatus + = CreateXImage (display, visual, depth, + (depth == 1 ? bitmap_format : ZPixmap), width, + height, &ximage); + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + +#if !defined(FOR_MSW) && !defined(AMIGA) + + /* + * set the XImage pointer function, to be used with XPutPixel, + * to an internal optimized function + */ + + if (ximage->bits_per_pixel == 8) + ximage->f.put_pixel = PutPixel8; + else if (((ximage->bits_per_pixel | ximage->depth) == 1) + && (ximage->byte_order == ximage->bitmap_bit_order)) + if (ximage->bitmap_bit_order == MSBFirst) + ximage->f.put_pixel = PutPixel1MSB; + else + ximage->f.put_pixel = PutPixel1LSB; + else if (ximage->bits_per_pixel == 16) + if (ximage->bitmap_bit_order == MSBFirst) + ximage->f.put_pixel = PutPixel16MSB; + else + ximage->f.put_pixel = PutPixel16LSB; + else if (ximage->bits_per_pixel == 32) +#if !defined(WORD64) && !defined(LONG64) + if (*((char *) &byteorderpixel) == ximage->byte_order) + ximage->f.put_pixel = PutPixel32; + else +#endif + if (ximage->bitmap_bit_order == MSBFirst) + ximage->f.put_pixel = PutPixel32MSB; + else + ximage->f.put_pixel = PutPixel32LSB; + else if ((ximage->bits_per_pixel | ximage->depth) == 1) + ximage->f.put_pixel = PutPixel1; + else + ximage->f.put_pixel = PutPixel; +#endif /* not FOR_MSW && not AMIGA */ + } + + /* create the shape mask image */ + if (mask_pixel_index != XpmUndefPixel && shapeimage_return) + { + ErrorStatus = CreateXImage (display, visual, 1, bitmap_format, + width, height, &shapeimage); + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + +#if !defined(FOR_MSW) && !defined(AMIGA) + if (shapeimage->bitmap_bit_order == MSBFirst) + shapeimage->f.put_pixel = PutPixel1MSB; + else + shapeimage->f.put_pixel = PutPixel1LSB; +#endif + } + + /* + * read pixels and put them in the XImage + */ + ErrorStatus = ParseAndPutPixels ( +#ifdef FOR_MSW + display, +#endif + data, width, height, ncolors, cpp, colorTable, &hashtable, ximage, + image_pixels, shapeimage, mask_pixels); + XpmFree (image_pixels); + image_pixels = NULL; + XpmFree (mask_pixels); + mask_pixels = NULL; + + /* + * free the hastable + */ + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + else if (USE_HASHTABLE) + xpmHashTableFree (&hashtable); + + /* + * store the pixels comment line + */ + if (cmts) + xpmGetCmt (data, &pixels_cmt); + + /* + * parse extensions + */ + if (info && (info->valuemask & XpmReturnExtensions)) + { + if (extensions) + { + ErrorStatus = xpmParseExtensions (data, &info->extensions, + &info->nextensions); + if (ErrorStatus != XpmSuccess) + RETURN (ErrorStatus); + } + else + { + info->extensions = NULL; + info->nextensions = 0; + } + } + /* + * store found informations in the XpmImage structure + */ + image->width = width; + image->height = height; + image->cpp = cpp; + image->ncolors = ncolors; + image->colorTable = colorTable; + image->data = NULL; + + if (info) + { + if (cmts) + { + info->hints_cmt = hints_cmt; + info->colors_cmt = colors_cmt; + info->pixels_cmt = pixels_cmt; + } + if (hotspot) + { + info->x_hotspot = x_hotspot; + info->y_hotspot = y_hotspot; + info->valuemask |= XpmHotspot; + } + } + /* if requested return used pixels in the XpmAttributes structure */ + if (attributes + && (attributes->valuemask & XpmReturnPixels || + /* 3.2 backward compatibility code */ + attributes->valuemask & XpmReturnInfos)) + { + /* end 3.2 bc */ + attributes->pixels = used_pixels; + attributes->npixels = nused_pixels; + attributes->mask_pixel = mask_pixel_index; + } + else + XpmFree (used_pixels); + + /* if requested return alloc'ed pixels in the XpmAttributes + * structure */ + if (attributes && (attributes->valuemask & XpmReturnAllocPixels)) + { + attributes->alloc_pixels = alloc_pixels; + attributes->nalloc_pixels = nalloc_pixels; + } + else + XpmFree (alloc_pixels); + + /* return created images */ + if (image_return) + *image_return = ximage; + if (shapeimage_return) + *shapeimage_return = shapeimage; + + return (XpmSuccess); + +/* exit point in case of error, free only locally allocated variables + */ +error: + if (USE_HASHTABLE) + xpmHashTableFree (&hashtable); + if (colorTable) + xpmFreeColorTable (colorTable, ncolors); + if (hints_cmt) + XpmFree (hints_cmt); + if (colors_cmt) + XpmFree (colors_cmt); + if (pixels_cmt) + XpmFree (pixels_cmt); + if (ximage) + XDestroyImage (ximage); + if (shapeimage) + XDestroyImage (shapeimage); + if (image_pixels) + XpmFree (image_pixels); + if (mask_pixels) + XpmFree (mask_pixels); + if (nalloc_pixels) + (*freeColors) (display, colormap, alloc_pixels, nalloc_pixels, + NULL); + if (alloc_pixels) + XpmFree (alloc_pixels); + if (used_pixels) + XpmFree (used_pixels); + + return (ErrorStatus); +} + +static int +ParseAndPutPixels ( +#ifdef FOR_MSW + Display *dc, +#endif + xpmData *data, unsigned int width, unsigned int height, + unsigned int ncolors, unsigned int cpp, XpmColor *colorTable, + xpmHashTable *hashtable, XImage *image, Pixel *image_pixels, + XImage *shapeimage, Pixel *shape_pixels) +{ + unsigned int a, x, y; + + switch (cpp) + { + case (1): /* Optimize for single character + * colors */ + { + unsigned short colidx[256]; + if (ncolors > 256) + return (XpmFileInvalid); + + bzero ((char *) colidx, 256 * sizeof (short)); + for (a = 0; a < ncolors; a++) + colidx[(unsigned char) colorTable[a].string[0]] = a + 1; + + for (y = 0; y < height; y++) + { + xpmNextString (data); + for (x = 0; x < width; x++) + { + int c = xpmGetC (data); + + if (c > 0 && c < 256 && colidx[c] != 0) + { + XPutPixel (image, x, y, + image_pixels[colidx[c] - 1]); + if (shapeimage) + XPutPixel (shapeimage, x, y, + shape_pixels[colidx[c] - 1]); + } + else + return (XpmFileInvalid); + } + } + } + break; + + case (2): /* Optimize for double character + * colors */ + { +/* free all allocated pointers at all exits */ +#define FREE_CIDX \ + { \ + int f; \ + for (f = 0; f < 256; f++) \ + if (cidx[f]) \ + XpmFree (cidx[f]); \ + } + + /* array of pointers malloced by need */ + unsigned short *cidx[256]; + unsigned int char1; + + bzero ((char *) cidx, + 256 * sizeof (unsigned short *)); /* init */ + for (a = 0; a < ncolors; a++) + { + char1 = (unsigned char) colorTable[a].string[0]; + if (cidx[char1] == NULL) + { /* get new memory */ + cidx[char1] = (unsigned short *) + XpmCalloc (256, sizeof (unsigned short)); + if (cidx[char1] == NULL) + { /* new block failed */ + FREE_CIDX; + return (XpmNoMemory); + } + } + cidx[char1][(unsigned char) colorTable[a].string[1]] + = a + 1; + } + + for (y = 0; y < height; y++) + { + xpmNextString (data); + for (x = 0; x < width; x++) + { + int cc1 = xpmGetC (data); + if (cc1 > 0 && cc1 < 256) + { + int cc2 = xpmGetC (data); + if (cc2 > 0 && cc2 < 256 && cidx[cc1] + && cidx[cc1][cc2] != 0) + { + XPutPixel (image, x, y, + image_pixels[cidx[cc1][cc2] - 1]); + if (shapeimage) + XPutPixel (shapeimage, x, y, + shape_pixels[cidx[cc1][cc2] + - 1]); + } + else + { + FREE_CIDX; + return (XpmFileInvalid); + } + } + else + { + FREE_CIDX; + return (XpmFileInvalid); + } + } + } + FREE_CIDX; + } + break; + + default: /* Non-optimized case of long color + * names */ + { + char *s; + char buf[BUFSIZ]; + + if (cpp >= sizeof (buf)) + return (XpmFileInvalid); + + buf[cpp] = '\0'; + if (USE_HASHTABLE) + { + xpmHashAtom *slot; + + for (y = 0; y < height; y++) + { + xpmNextString (data); + for (x = 0; x < width; x++) + { + for (a = 0, s = buf; a < cpp; a++, s++) + *s = xpmGetC (data); + slot = xpmHashSlot (hashtable, buf); + if (!*slot) /* no color matches */ + return (XpmFileInvalid); + XPutPixel (image, x, y, + image_pixels[HashColorIndex (slot)]); + if (shapeimage) + XPutPixel (shapeimage, x, y, + shape_pixels[HashColorIndex (slot)]); + } + } + } + else + { + for (y = 0; y < height; y++) + { + xpmNextString (data); + for (x = 0; x < width; x++) + { + for (a = 0, s = buf; a < cpp; a++, s++) + *s = xpmGetC (data); + for (a = 0; a < ncolors; a++) + if (!strcmp (colorTable[a].string, buf)) + break; + if (a == ncolors) /* no color matches */ + return (XpmFileInvalid); + XPutPixel (image, x, y, image_pixels[a]); + if (shapeimage) + XPutPixel (shapeimage, x, y, shape_pixels[a]); + } + } + } + } + break; + } + return (XpmSuccess); +} diff --git a/be_xpm/data.c b/be_xpm/data.c new file mode 100644 index 0000000000..898889c37a --- /dev/null +++ b/be_xpm/data.c @@ -0,0 +1,481 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* data.c: * +* * +* XPM library * +* IO utilities * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* October 2004, source code review by Thomas Biege */ + +#ifndef CXPMPROG +#if 0 +/* Official version number */ +static char *RCS_Version = "$XpmVersion: 3.4k $"; + +/* Internal version number */ +static char *RCS_Id = "Id: xpm.shar,v 3.71 1998/03/19 19:47:14 lehors Exp $"; +#endif +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" +#endif +#include + +#ifndef CXPMPROG +#define Getc(data, file) getc(file) +#define Ungetc(data, c, file) ungetc(c, file) +#endif + +static int +ParseComment(xpmData *data) +{ + if (data->type == XPMBUFFER) { + register char c; + register unsigned int n = 0; + unsigned int notend; + char *s; + const char *s2; + + s = data->Comment; + *s = data->Bcmt[0]; + + /* skip the string beginning comment */ + s2 = data->Bcmt; + do { + c = *data->cptr++; + *++s = c; + n++; + s2++; + } while (c == *s2 && *s2 != '\0' && c); + + if (*s2 != '\0') { + /* this wasn't the beginning of a comment */ + data->cptr -= n; + return 0; + } + /* store comment */ + data->Comment[0] = *s; + s = data->Comment; + notend = 1; + n = 0; + while (notend) { + s2 = data->Ecmt; + while (*s != *s2 && c) { + c = *data->cptr++; + if (n == XPMMAXCMTLEN - 1) { /* forget it */ + s = data->Comment; + n = 0; + } + *++s = c; + n++; + } + data->CommentLength = n; + do { + c = *data->cptr++; + if (n == XPMMAXCMTLEN - 1) { /* forget it */ + s = data->Comment; + n = 0; + } + *++s = c; + n++; + s2++; + } while (c == *s2 && *s2 != '\0' && c); + if (*s2 == '\0') { + /* this is the end of the comment */ + notend = 0; + data->cptr--; + } + } + return 0; + } else { + FILE *file = data->stream.file; + register int c; + register unsigned int n = 0, a; + unsigned int notend; + char *s; + const char *s2; + + s = data->Comment; + *s = data->Bcmt[0]; + + /* skip the string beginning comment */ + s2 = data->Bcmt; + do { + c = Getc(data, file); + *++s = c; + n++; + s2++; + } while (c == *s2 && *s2 != '\0' && c != EOF); + + if (*s2 != '\0') { + /* this wasn't the beginning of a comment */ + /* put characters back in the order that we got them */ + for (a = n; a > 0; a--, s--) + Ungetc(data, *s, file); + return 0; + } + /* store comment */ + data->Comment[0] = *s; + s = data->Comment; + notend = 1; + n = 0; + while (notend) { + s2 = data->Ecmt; + while (*s != *s2 && c != EOF) { + c = Getc(data, file); + if (n == XPMMAXCMTLEN - 1) { /* forget it */ + s = data->Comment; + n = 0; + } + *++s = c; + n++; + } + data->CommentLength = n; + do { + c = Getc(data, file); + if (n == XPMMAXCMTLEN - 1) { /* forget it */ + s = data->Comment; + n = 0; + } + *++s = c; + n++; + s2++; + } while (c == *s2 && *s2 != '\0' && c != EOF); + if (*s2 == '\0') { + /* this is the end of the comment */ + notend = 0; + Ungetc(data, *s, file); + } + } + return 0; + } +} + +/* + * skip to the end of the current string and the beginning of the next one + */ +int +xpmNextString(xpmData *data) +{ + if (!data->type) + data->cptr = (data->stream.data)[++data->line]; + else if (data->type == XPMBUFFER) { + register char c; + + /* get to the end of the current string */ + if (data->Eos) + while ((c = *data->cptr++) && c != data->Eos); + + /* + * then get to the beginning of the next string looking for possible + * comment + */ + if (data->Bos) { + while ((c = *data->cptr++) && c != data->Bos) + if (data->Bcmt && c == data->Bcmt[0]) + ParseComment(data); + } else if (data->Bcmt) { /* XPM2 natural */ + while ((c = *data->cptr++) == data->Bcmt[0]) + ParseComment(data); + data->cptr--; + } + } else { + register int c; + FILE *file = data->stream.file; + + /* get to the end of the current string */ + if (data->Eos) + while ((c = Getc(data, file)) != data->Eos && c != EOF); + + /* + * then get to the beginning of the next string looking for possible + * comment + */ + if (data->Bos) { + while ((c = Getc(data, file)) != data->Bos && c != EOF) + if (data->Bcmt && c == data->Bcmt[0]) + ParseComment(data); + + } else if (data->Bcmt) { /* XPM2 natural */ + while ((c = Getc(data, file)) == data->Bcmt[0]) + ParseComment(data); + Ungetc(data, c, file); + } + } + return 0; +} + + +/* + * skip whitespace and return the following word + */ +unsigned int +xpmNextWord( + xpmData *data, + char *buf, + unsigned int buflen) +{ + register unsigned int n = 0; + int c; + + if (!data->type || data->type == XPMBUFFER) { + while (isspace(c = *data->cptr) && c != data->Eos) + data->cptr++; + do { + c = *data->cptr++; + *buf++ = c; + n++; + } while (!isspace(c) && c != data->Eos && n < buflen); + n--; + data->cptr--; + } else { + FILE *file = data->stream.file; + + while ((c = Getc(data, file)) != EOF && isspace(c) && c != data->Eos); + while (!isspace(c) && c != data->Eos && c != EOF && n < buflen) { + *buf++ = c; + n++; + c = Getc(data, file); + } + Ungetc(data, c, file); + } + return (n); /* this returns bytes read + 1 */ +} + +/* + * skip whitespace and compute the following unsigned int, + * returns 1 if one is found and 0 if not + */ +int +xpmNextUI( + xpmData *data, + unsigned int *ui_return) +{ + char buf[BUFSIZ]; + int l; + + l = xpmNextWord(data, buf, BUFSIZ); + return xpmatoui(buf, l, ui_return); +} + +/* + * return end of string - WARNING: malloc! + */ +int +xpmGetString( + xpmData *data, + char **sptr, + unsigned int *l) +{ + unsigned int i, n = 0; + int c; + char *p = NULL, *q, buf[BUFSIZ]; + + if (!data->type || data->type == XPMBUFFER) { + if (data->cptr) { + char *start = data->cptr; + while ((c = *data->cptr) && c != data->Eos) + data->cptr++; + n = data->cptr - start + 1; + p = (char *) XpmMalloc(n); + if (!p) + return (XpmNoMemory); + strncpy(p, start, n); + if (data->type) /* XPMBUFFER */ + p[n - 1] = '\0'; + } + } else { + FILE *file = data->stream.file; + + if ((c = Getc(data, file)) == EOF) + return (XpmFileInvalid); + + i = 0; + q = buf; + p = (char *) XpmMalloc(1); + while (c != data->Eos && c != EOF) { + if (i == BUFSIZ) { + /* get to the end of the buffer */ + /* malloc needed memory */ + q = (char *) XpmRealloc(p, n + i); + if (!q) { + XpmFree(p); + return (XpmNoMemory); + } + p = q; + q += n; + /* and copy what we already have */ + strncpy(q, buf, i); + n += i; + i = 0; + q = buf; + } + *q++ = c; + i++; + c = Getc(data, file); + } + if (c == EOF) { + XpmFree(p); + return (XpmFileInvalid); + } + if (n + i != 0) { + /* malloc needed memory */ + q = (char *) XpmRealloc(p, n + i + 1); + if (!q) { + XpmFree(p); + return (XpmNoMemory); + } + p = q; + q += n; + /* and copy the buffer */ + strncpy(q, buf, i); + n += i; + p[n++] = '\0'; + } else { + *p = '\0'; + n = 1; + } + Ungetc(data, c, file); + } + *sptr = p; + *l = n; + return (XpmSuccess); +} + +/* + * get the current comment line + */ +int +xpmGetCmt( + xpmData *data, + char **cmt) +{ + if (!data->type) + *cmt = NULL; + else if (data->CommentLength != 0 && data->CommentLength < UINT_MAX - 1) { + if( (*cmt = (char *) XpmMalloc(data->CommentLength + 1)) == NULL) + return XpmNoMemory; + strncpy(*cmt, data->Comment, data->CommentLength); + (*cmt)[data->CommentLength] = '\0'; + data->CommentLength = 0; + } else + *cmt = NULL; + return 0; +} + +xpmDataType xpmDataTypes[] = +{ + {"", "!", "\n", '\0', '\n', "", "", "", ""}, /* Natural type */ + {"C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n"}, + {"Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n"}, + {NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL} +}; + +/* + * parse xpm header + */ +int +xpmParseHeader(xpmData *data) +{ + char buf[BUFSIZ+1] = {0}; + int l, n = 0; + + if (data->type) { + data->Bos = '\0'; + data->Eos = '\n'; + data->Bcmt = data->Ecmt = NULL; + l = xpmNextWord(data, buf, BUFSIZ); + if (l == 7 && !strncmp("#define", buf, 7)) { + /* this maybe an XPM 1 file */ + char *ptr; + + l = xpmNextWord(data, buf, BUFSIZ); + if (!l) + return (XpmFileInvalid); + buf[l] = '\0'; + ptr = strrchr(buf, '_'); + if (!ptr || strncmp("_format", ptr, l - (ptr - buf))) + return XpmFileInvalid; + /* this is definitely an XPM 1 file */ + data->format = 1; + n = 1; /* handle XPM1 as mainly XPM2 C */ + } else { + + /* + * skip the first word, get the second one, and see if this is + * XPM 2 or 3 + */ + l = xpmNextWord(data, buf, BUFSIZ); + if ((l == 3 && !strncmp("XPM", buf, 3)) || + (l == 4 && !strncmp("XPM2", buf, 4))) { + if (l == 3) + n = 1; /* handle XPM as XPM2 C */ + else { + /* get the type key word */ + l = xpmNextWord(data, buf, BUFSIZ); + + /* + * get infos about this type + */ + while (xpmDataTypes[n].type + && strncmp(xpmDataTypes[n].type, buf, l)) + n++; + } + data->format = 0; + } else + /* nope this is not an XPM file */ + return XpmFileInvalid; + } + if (xpmDataTypes[n].type) { + if (n == 0) { /* natural type */ + data->Bcmt = xpmDataTypes[n].Bcmt; + data->Ecmt = xpmDataTypes[n].Ecmt; + xpmNextString(data); /* skip the end of the headerline */ + data->Bos = xpmDataTypes[n].Bos; + data->Eos = xpmDataTypes[n].Eos; + } else { + data->Bcmt = xpmDataTypes[n].Bcmt; + data->Ecmt = xpmDataTypes[n].Ecmt; + if (!data->format) { /* XPM 2 or 3 */ + data->Bos = xpmDataTypes[n].Bos; + data->Eos = '\0'; + /* get to the beginning of the first string */ + xpmNextString(data); + data->Eos = xpmDataTypes[n].Eos; + } else /* XPM 1 skip end of line */ + xpmNextString(data); + } + } else + /* we don't know about that type of XPM file... */ + return XpmFileInvalid; + } + return XpmSuccess; +} diff --git a/be_xpm/hashtab.c b/be_xpm/hashtab.c new file mode 100644 index 0000000000..1bd4109a41 --- /dev/null +++ b/be_xpm/hashtab.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* hashtab.c: * +* * +* XPM library * +* * +* Developed by Arnaud Le Hors * +* this originaly comes from Colas Nahaboo as a part of Wool * +* * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +LFUNC(AtomMake, xpmHashAtom, (char *name, void *data)); +LFUNC(HashTableGrows, int, (xpmHashTable * table)); + +static xpmHashAtom +AtomMake( /* makes an atom */ + char *name, /* WARNING: is just pointed to */ + void *data) +{ + xpmHashAtom object = (xpmHashAtom) XpmMalloc(sizeof(struct _xpmHashAtom)); + + if (object) { + object->name = name; + object->data = data; + } + return object; +} + +/************************\ +* * +* hash table routines * +* * +\************************/ + +/* + * Hash function definition: + * HASH_FUNCTION: hash function, hash = hashcode, hp = pointer on char, + * hash2 = temporary for hashcode. + * INITIAL_TABLE_SIZE in slots + * HASH_TABLE_GROWS how hash table grows. + */ + +/* Mock lisp function */ +#define HASH_FUNCTION hash = (hash << 5) - hash + *hp++; +/* #define INITIAL_HASH_SIZE 2017 */ +#define INITIAL_HASH_SIZE 256 /* should be enough for colors */ +#define HASH_TABLE_GROWS size = size * 2; + +/* aho-sethi-ullman's HPJ (sizes should be primes)*/ +#ifdef notdef +#define HASH_FUNCTION hash <<= 4; hash += *hp++; \ + if(hash2 = hash & 0xf0000000) hash ^= (hash2 >> 24) ^ hash2; +#define INITIAL_HASH_SIZE 4095 /* should be 2^n - 1 */ +#define HASH_TABLE_GROWS size = size << 1 + 1; +#endif + +/* GNU emacs function */ +/* +#define HASH_FUNCTION hash = (hash << 3) + (hash >> 28) + *hp++; +#define INITIAL_HASH_SIZE 2017 +#define HASH_TABLE_GROWS size = size * 2; +*/ + +/* end of hash functions */ + +/* + * The hash table is used to store atoms via their NAME: + * + * NAME --hash--> ATOM |--name--> "foo" + * |--data--> any value which has to be stored + * + */ + +/* + * xpmHashSlot gives the slot (pointer to xpmHashAtom) of a name + * (slot points to NULL if it is not defined) + * + */ + +xpmHashAtom * +xpmHashSlot( + xpmHashTable *table, + char *s) +{ + xpmHashAtom *atomTable = table->atomTable; + unsigned int hash; + xpmHashAtom *p; + char *hp = s; + char *ns; + + hash = 0; + while (*hp) { /* computes hash function */ + HASH_FUNCTION + } + p = atomTable + hash % table->size; + while (*p) { + ns = (*p)->name; + if (ns[0] == s[0] && strcmp(ns, s) == 0) + break; + p--; + if (p < atomTable) + p = atomTable + table->size - 1; + } + return p; +} + +static int +HashTableGrows(xpmHashTable *table) +{ + xpmHashAtom *atomTable = table->atomTable; + unsigned int size = table->size; + xpmHashAtom *t, *p; + int i; + unsigned int oldSize = size; + + t = atomTable; + HASH_TABLE_GROWS + table->size = size; + table->limit = size / 3; + if (size >= UINT_MAX / sizeof(*atomTable)) + return (XpmNoMemory); + atomTable = (xpmHashAtom *) XpmMalloc(size * sizeof(*atomTable)); + if (!atomTable) + return (XpmNoMemory); + table->atomTable = atomTable; + for (p = atomTable + size; p > atomTable;) + *--p = NULL; + for (i = 0, p = t; i < oldSize; i++, p++) + if (*p) { + xpmHashAtom *ps = xpmHashSlot(table, (*p)->name); + + *ps = *p; + } + XpmFree(t); + return (XpmSuccess); +} + +/* + * xpmHashIntern(table, name, data) + * an xpmHashAtom is created if name doesn't exist, with the given data. + */ + +int +xpmHashIntern( + xpmHashTable *table, + char *tag, + void *data) +{ + xpmHashAtom *slot; + + if (!*(slot = xpmHashSlot(table, tag))) { + /* undefined, make a new atom with the given data */ + if (!(*slot = AtomMake(tag, data))) + return (XpmNoMemory); + if (table->used >= table->limit) { + int ErrorStatus; + + if ((ErrorStatus = HashTableGrows(table)) != XpmSuccess) + return (ErrorStatus); + table->used++; + return (XpmSuccess); + } + table->used++; + } + return (XpmSuccess); +} + +/* + * must be called before allocating any atom + */ + +int +xpmHashTableInit(xpmHashTable *table) +{ + xpmHashAtom *p; + xpmHashAtom *atomTable; + + table->size = INITIAL_HASH_SIZE; + table->limit = table->size / 3; + table->used = 0; + table->atomTable = NULL; + if (table->size >= UINT_MAX / sizeof(*atomTable)) + return (XpmNoMemory); + atomTable = (xpmHashAtom *) XpmMalloc(table->size * sizeof(*atomTable)); + if (!atomTable) + return (XpmNoMemory); + for (p = atomTable + table->size; p > atomTable;) + *--p = NULL; + table->atomTable = atomTable; + return (XpmSuccess); +} + +/* + * frees a hashtable and all the stored atoms + */ + +void +xpmHashTableFree(xpmHashTable *table) +{ + xpmHashAtom *p; + xpmHashAtom *atomTable = table->atomTable; + + if (!atomTable) + return; + for (p = atomTable + table->size; p > atomTable;) + if (*--p) + XpmFree(*p); + XpmFree(atomTable); + table->atomTable = NULL; +} diff --git a/be_xpm/misc.c b/be_xpm/misc.c new file mode 100644 index 0000000000..e5bc0f6b6c --- /dev/null +++ b/be_xpm/misc.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* misc.c: * +* * +* XPM library * +* Miscellaneous utilities * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +#ifdef NEED_STRDUP +/* + * in case strdup is not provided by the system here is one + * which does the trick + */ +char * +xpmstrdup(char *s1) +{ + char *s2; + size_t l = strlen(s1) + 1; + + if (s2 = (char *) XpmMalloc(l)) + strcpy(s2, s1); + return s2; +} + +#endif + +unsigned int +xpmatoui( + register char *p, + unsigned int l, + unsigned int *ui_return) +{ + register unsigned int n, i; + + n = 0; + for (i = 0; i < l; i++) + if (*p >= '0' && *p <= '9') + n = n * 10 + *p++ - '0'; + else + break; + + if (i != 0 && i == l) { + *ui_return = n; + return 1; + } else + return 0; +} + +/* + * Function returning a character string related to an error code. + */ +char * +XpmGetErrorString(int errcode) +{ + switch (errcode) { + case XpmColorError: + return ("XpmColorError"); + case XpmSuccess: + return ("XpmSuccess"); + case XpmOpenFailed: + return ("XpmOpenFailed"); + case XpmFileInvalid: + return ("XpmFileInvalid"); + case XpmNoMemory: + return ("XpmNoMemory"); + case XpmColorFailed: + return ("XpmColorFailed"); + default: + return ("Invalid XpmError"); + } +} + +/* + * The following function provides a way to figure out if the linked library is + * newer or older than the one with which a program has been first compiled. + */ +int +XpmLibraryVersion(void) +{ + return XpmIncludeVersion; +} + + +/* The following should help people wanting to use their own functions */ +#ifdef XpmFree +#undef XpmFree +#endif + +void +XpmFree(void *ptr) +{ + free(ptr); +} diff --git a/be_xpm/parse.c b/be_xpm/parse.c new file mode 100644 index 0000000000..613529e627 --- /dev/null +++ b/be_xpm/parse.c @@ -0,0 +1,865 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* parse.c: * +* * +* XPM library * +* Parse an XPM file or array and store the found informations * +* in the given XpmImage structure. * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * The code related to FOR_MSW has been added by + * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 + */ + +/* October 2004, source code review by Thomas Biege */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" +#include +#include + +/** + * like strlcat() but returns true on success and false if the string got + * truncated. + */ +static inline Bool +xstrlcat(char *dst, const char *src, size_t dstsize) +{ +#if defined(HAS_STRLCAT) || defined(HAVE_STRLCAT) + return strlcat(dst, src, dstsize) < dstsize; +#else + if ((strlen(dst) + strlen(src)) < dstsize) { + strcat(dst, src); + return True; + } else { + return False; + } +#endif +} + +/** + * like strlcpy() but returns true on success and false if the string got + * truncated. + */ +static inline Bool +xstrlcpy(char *dst, const char *src, size_t dstsize) +{ +#if defined(HAS_STRLCAT) || defined(HAVE_STRLCAT) + return strlcpy(dst, src, dstsize) < dstsize; +#else + if (strlen(src) < dstsize) { + strcpy(dst, src); + return True; + } else { + return False; + } +#endif +} + +LFUNC(ParsePixels, int, (xpmData *data, unsigned int width, + unsigned int height, unsigned int ncolors, + unsigned int cpp, XpmColor *colorTable, + xpmHashTable *hashtable, unsigned int **pixels)); + +const char *xpmColorKeys[] = { + "s", /* key #1: symbol */ + "m", /* key #2: mono visual */ + "g4", /* key #3: 4 grays visual */ + "g", /* key #4: gray visual */ + "c", /* key #5: color visual */ +}; + +int +xpmParseValues( + xpmData *data, + unsigned int *width, + unsigned int *height, + unsigned int *ncolors, + unsigned int *cpp, + unsigned int *x_hotspot, + unsigned int *y_hotspot, + unsigned int *hotspot, + unsigned int *extensions) +{ + unsigned int l; + char buf[BUFSIZ + 1]; + + if (!data->format) { /* XPM 2 or 3 */ + + /* + * read values: width, height, ncolors, chars_per_pixel + */ + if (!(xpmNextUI(data, width) && xpmNextUI(data, height) + && xpmNextUI(data, ncolors) && xpmNextUI(data, cpp))) + return (XpmFileInvalid); + + /* + * read optional information (hotspot and/or XPMEXT) if any + */ + l = xpmNextWord(data, buf, BUFSIZ); + if (l) { + *extensions = (l == 6 && !strncmp("XPMEXT", buf, 6)); + if (*extensions) + *hotspot = (xpmNextUI(data, x_hotspot) + && xpmNextUI(data, y_hotspot)); + else { + *hotspot = (xpmatoui(buf, l, x_hotspot) + && xpmNextUI(data, y_hotspot)); + l = xpmNextWord(data, buf, BUFSIZ); + *extensions = (l == 6 && !strncmp("XPMEXT", buf, 6)); + } + } + } else { + + /* + * XPM 1 file read values: width, height, ncolors, chars_per_pixel + */ + int i; + char *ptr; + Bool got_one, saw_width = False, saw_height = False; + Bool saw_ncolors = False, saw_chars_per_pixel = False; + + for (i = 0; i < 4; i++) { + l = xpmNextWord(data, buf, BUFSIZ); + if (l != 7 || strncmp("#define", buf, 7)) + return (XpmFileInvalid); + l = xpmNextWord(data, buf, BUFSIZ); + if (!l) + return (XpmFileInvalid); + buf[l] = '\0'; + ptr = buf; + got_one = False; + while (!got_one) { + ptr = strchr(ptr, '_'); + if (!ptr) + return (XpmFileInvalid); + switch (l - (ptr - buf)) { + case 6: + if (saw_width || strncmp("_width", ptr, 6) + || !xpmNextUI(data, width)) + return (XpmFileInvalid); + else + saw_width = True; + got_one = True; + break; + case 7: + if (saw_height || strncmp("_height", ptr, 7) + || !xpmNextUI(data, height)) + return (XpmFileInvalid); + else + saw_height = True; + got_one = True; + break; + case 8: + if (saw_ncolors || strncmp("_ncolors", ptr, 8) + || !xpmNextUI(data, ncolors)) + return (XpmFileInvalid); + else + saw_ncolors = True; + got_one = True; + break; + case 16: + if (saw_chars_per_pixel + || strncmp("_chars_per_pixel", ptr, 16) + || !xpmNextUI(data, cpp)) + return (XpmFileInvalid); + else + saw_chars_per_pixel = True; + got_one = True; + break; + default: + ptr++; + } + } + /* skip the end of line */ + xpmNextString(data); + } + if (!saw_width || !saw_height || !saw_ncolors || !saw_chars_per_pixel) + return (XpmFileInvalid); + + *hotspot = 0; + *extensions = 0; + } + return (XpmSuccess); +} + +int +xpmParseColors( + xpmData *data, + unsigned int ncolors, + unsigned int cpp, + XpmColor **colorTablePtr, + xpmHashTable *hashtable) +{ + unsigned int key = 0, l, a, b, len; + unsigned int curkey; /* current color key */ + unsigned int lastwaskey; /* key read */ + char buf[BUFSIZ+1]; + char curbuf[BUFSIZ]; /* current buffer */ + const char **sptr; + char *s; + XpmColor *color; + XpmColor *colorTable; + char **defaults; + int ErrorStatus; + + if (ncolors >= UINT_MAX / sizeof(XpmColor)) + return (XpmNoMemory); + colorTable = (XpmColor *) XpmCalloc(ncolors, sizeof(XpmColor)); + if (!colorTable) + return (XpmNoMemory); + + if (!data->format) { /* XPM 2 or 3 */ + for (a = 0, color = colorTable; a < ncolors; a++, color++) { + xpmNextString(data); /* skip the line */ + + /* + * read pixel value + */ + if (cpp >= UINT_MAX - 1) { + ErrorStatus = XpmNoMemory; + goto error; + } + color->string = (char *) XpmMalloc(cpp + 1); + if (!color->string) { + ErrorStatus = XpmNoMemory; + goto error; + } + for (b = 0, s = color->string; b < cpp; b++, s++) { + int c = xpmGetC(data); + if (c < 0) { + ErrorStatus = XpmFileInvalid; + goto error; + } + *s = (char) c; + } + *s = '\0'; + + /* + * store the string in the hashtable with its color index number + */ + if (USE_HASHTABLE) { + ErrorStatus = + xpmHashIntern(hashtable, color->string, HashAtomData(a)); + if (ErrorStatus != XpmSuccess) { + goto error; + } + } + + /* + * read color keys and values + */ + defaults = (char **) color; + curkey = 0; + lastwaskey = 0; + *curbuf = '\0'; /* init curbuf */ + while ((l = xpmNextWord(data, buf, BUFSIZ))) { + if (!lastwaskey) { + for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++, + sptr++) + if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l))) + break; + } + if (!lastwaskey && key < NKEYS) { /* open new key */ + if (curkey) { /* flush string */ + len = strlen(curbuf) + 1; + s = (char *) XpmMalloc(len); + if (!s) { + ErrorStatus = XpmNoMemory; + goto error; + } + defaults[curkey] = s; + memcpy(s, curbuf, len); + } + curkey = key + 1; /* set new key */ + *curbuf = '\0'; /* reset curbuf */ + lastwaskey = 1; + } else { + if (!curkey) { /* key without value */ + ErrorStatus = XpmFileInvalid; + goto error; + } + if (!lastwaskey) { + if (!xstrlcat(curbuf, " ", sizeof(curbuf))) { /* append space */ + ErrorStatus = XpmFileInvalid; + goto error; + } + } + buf[l] = '\0'; + if (!xstrlcat(curbuf, buf, sizeof(curbuf))) { /* append buf */ + ErrorStatus = XpmFileInvalid; + goto error; + } + lastwaskey = 0; + } + } + if (!curkey) { /* key without value */ + ErrorStatus = XpmFileInvalid; + goto error; + } + len = strlen(curbuf) + 1; /* integer overflow just theoretically possible */ + s = defaults[curkey] = (char *) XpmMalloc(len); + if (!s) { + ErrorStatus = XpmNoMemory; + goto error; + } + memcpy(s, curbuf, len); + } + } else { /* XPM 1 */ + /* get to the beginning of the first string */ + data->Bos = '"'; + data->Eos = '\0'; + xpmNextString(data); + data->Eos = '"'; + for (a = 0, color = colorTable; a < ncolors; a++, color++) { + + /* + * read pixel value + */ + if (cpp >= UINT_MAX - 1) { + ErrorStatus = XpmNoMemory; + goto error; + } + color->string = (char *) XpmMalloc(cpp + 1); + if (!color->string) { + ErrorStatus = XpmNoMemory; + goto error; + } + for (b = 0, s = color->string; b < cpp; b++, s++) { + int c = xpmGetC(data); + if (c < 0) { + ErrorStatus = XpmFileInvalid; + goto error; + } + *s = (char) c; + } + *s = '\0'; + + /* + * store the string in the hashtable with its color index number + */ + if (USE_HASHTABLE) { + ErrorStatus = + xpmHashIntern(hashtable, color->string, HashAtomData(a)); + if (ErrorStatus != XpmSuccess) { + goto error; + } + } + + /* + * read color values + */ + xpmNextString(data); /* get to the next string */ + *curbuf = '\0'; /* init curbuf */ + while ((l = xpmNextWord(data, buf, BUFSIZ))) { + if (*curbuf != '\0') { + if (!xstrlcat(curbuf, " ", sizeof(curbuf))) { /* append space */ + ErrorStatus = XpmFileInvalid; + goto error; + } + } + buf[l] = '\0'; + if (!xstrlcat(curbuf, buf, sizeof(curbuf))) { /* append buf */ + ErrorStatus = XpmFileInvalid; + goto error; + } + } + len = strlen(curbuf) + 1; + s = (char *) XpmMalloc(len); + if (!s) { + ErrorStatus = XpmNoMemory; + goto error; + } + memcpy(s, curbuf, len); + color->c_color = s; + *curbuf = '\0'; /* reset curbuf */ + if (a < ncolors - 1) /* can we trust ncolors -> leave data's bounds */ + xpmNextString(data); /* get to the next string */ + } + } + *colorTablePtr = colorTable; + return (XpmSuccess); + +error: + xpmFreeColorTable(colorTable, ncolors); + return ErrorStatus; +} + +static int +ParsePixels( + xpmData *data, + unsigned int width, + unsigned int height, + unsigned int ncolors, + unsigned int cpp, + XpmColor *colorTable, + xpmHashTable *hashtable, + unsigned int **pixels) +{ + unsigned int *iptr, *iptr2 = NULL; /* found by Egbert Eich */ + unsigned int a, x, y; + + if ((height > 0 && width >= UINT_MAX / height) || + width * height >= UINT_MAX / sizeof(unsigned int)) + return XpmNoMemory; +#ifndef FOR_MSW + iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height); +#else + + /* + * special treatment to trick DOS malloc(size_t) where size_t is 16 bit!! + * XpmMalloc is defined to longMalloc(long) and checks the 16 bit boundary + */ + iptr2 = (unsigned int *) + XpmMalloc((long) sizeof(unsigned int) * (long) width * (long) height); +#endif + if (!iptr2) + return (XpmNoMemory); + + iptr = iptr2; + + switch (cpp) { + + case (1): /* Optimize for single character + * colors */ + { + unsigned short colidx[256]; + + if (ncolors > 256) { + XpmFree(iptr2); /* found by Egbert Eich */ + return (XpmFileInvalid); + } + + bzero((char *)colidx, 256 * sizeof(short)); + for (a = 0; a < ncolors; a++) + colidx[(unsigned char)colorTable[a].string[0]] = a + 1; + + for (y = 0; y < height; y++) { + xpmNextString(data); + for (x = 0; x < width; x++, iptr++) { + int c = xpmGetC(data); + + if (c > 0 && c < 256 && colidx[c] != 0) + *iptr = colidx[c] - 1; + else { + XpmFree(iptr2); + return (XpmFileInvalid); + } + } + } + } + break; + + case (2): /* Optimize for double character + * colors */ + { + +/* free all allocated pointers at all exits */ +#define FREE_CIDX \ +do \ +{ \ + int f; for (f = 0; f < 256; f++) \ + if (cidx[f]) XpmFree(cidx[f]); \ +} while(0) + + /* array of pointers malloced by need */ + unsigned short *cidx[256]; + unsigned int char1; + + bzero((char *)cidx, 256 * sizeof(unsigned short *)); /* init */ + for (a = 0; a < ncolors; a++) { + char1 = (unsigned char) colorTable[a].string[0]; + if (cidx[char1] == NULL) { /* get new memory */ + cidx[char1] = (unsigned short *) + XpmCalloc(256, sizeof(unsigned short)); + if (cidx[char1] == NULL) { /* new block failed */ + FREE_CIDX; + XpmFree(iptr2); + return (XpmNoMemory); + } + } + cidx[char1][(unsigned char)colorTable[a].string[1]] = a + 1; + } + + for (y = 0; y < height; y++) { + xpmNextString(data); + for (x = 0; x < width; x++, iptr++) { + int cc1 = xpmGetC(data); + if (cc1 > 0 && cc1 < 256) { + int cc2 = xpmGetC(data); + if (cc2 > 0 && cc2 < 256 && + cidx[cc1] && cidx[cc1][cc2] != 0) + *iptr = cidx[cc1][cc2] - 1; + else { + FREE_CIDX; + XpmFree(iptr2); + return (XpmFileInvalid); + } + } else { + FREE_CIDX; + XpmFree(iptr2); + return (XpmFileInvalid); + } + } + } + FREE_CIDX; + } + break; + + default: /* Non-optimized case of long color + * names */ + { + char *s; + char buf[BUFSIZ]; + + if (cpp >= sizeof(buf)) { + XpmFree(iptr2); /* found by Egbert Eich */ + return (XpmFileInvalid); + } + + buf[cpp] = '\0'; + if (USE_HASHTABLE) { + xpmHashAtom *slot; + + for (y = 0; y < height; y++) { + xpmNextString(data); + for (x = 0; x < width; x++, iptr++) { + for (a = 0, s = buf; a < cpp; a++, s++) { + int c = xpmGetC(data); + if (c < 0) { + XpmFree(iptr2); + return (XpmFileInvalid); + } + *s = (char) c; + } + slot = xpmHashSlot(hashtable, buf); + if (!*slot) { /* no color matches */ + XpmFree(iptr2); + return (XpmFileInvalid); + } + *iptr = HashColorIndex(slot); + } + } + } else { + for (y = 0; y < height; y++) { + xpmNextString(data); + for (x = 0; x < width; x++, iptr++) { + for (a = 0, s = buf; a < cpp; a++, s++) { + int c = xpmGetC(data); + if (c < 0) { + XpmFree(iptr2); + return (XpmFileInvalid); + } + *s = (char) c; + } + for (a = 0; a < ncolors; a++) + if (!strcmp(colorTable[a].string, buf)) + break; + if (a == ncolors) { /* no color matches */ + XpmFree(iptr2); + return (XpmFileInvalid); + } + *iptr = a; + } + } + } + } + break; + } + *pixels = iptr2; + return (XpmSuccess); +} + +int +xpmParseExtensions( + xpmData *data, + XpmExtension **extensions, + unsigned int *nextensions) +{ + XpmExtension *exts = NULL, *ext; + unsigned int num = 0; + unsigned int nlines, a, l, notstart, notend = 0; + int status; + char *string, *s, *s2, **sp; + + xpmNextString(data); + exts = (XpmExtension *) XpmMalloc(sizeof(XpmExtension)); + /* get the whole string */ + status = xpmGetString(data, &string, &l); + if (status != XpmSuccess) { + XpmFree(exts); + return (status); + } + /* look for the key word XPMEXT, skip lines before this */ + while ((notstart = strncmp("XPMEXT", string, 6)) + && (notend = strncmp("XPMENDEXT", string, 9))) { + XpmFree(string); + xpmNextString(data); + status = xpmGetString(data, &string, &l); + if (status != XpmSuccess) { + XpmFree(exts); + return (status); + } + } + if (!notstart) + notend = strncmp("XPMENDEXT", string, 9); + while (!notstart && notend) { + /* there starts an extension */ + ext = (XpmExtension *) + XpmRealloc(exts, (num + 1) * sizeof(XpmExtension)); /* can the loop be forced to iterate often enough to make "(num + 1) * sizeof(XpmExtension)" wrapping? */ + if (!ext) { + XpmFree(string); + XpmFreeExtensions(exts, num); + return (XpmNoMemory); + } + exts = ext; + ext += num; + /* skip whitespace and store its name */ + s2 = s = string + 6; + while (isspace(*s2)) + s2++; + a = s2 - s; + ext->name = (char *) XpmMalloc(l - a - 6); + if (!ext->name) { + XpmFree(string); + ext->lines = NULL; + ext->nlines = 0; + XpmFreeExtensions(exts, num + 1); + return (XpmNoMemory); + } + strncpy(ext->name, s + a, l - a - 6); + XpmFree(string); + /* now store the related lines */ + xpmNextString(data); + status = xpmGetString(data, &string, &l); + if (status != XpmSuccess) { + ext->lines = NULL; + ext->nlines = 0; + XpmFreeExtensions(exts, num + 1); + return (status); + } + ext->lines = (char **) XpmMalloc(sizeof(char *)); + nlines = 0; + while ((notstart = strncmp("XPMEXT", string, 6)) + && (notend = strncmp("XPMENDEXT", string, 9))) { + sp = (char **) + XpmRealloc(ext->lines, (nlines + 1) * sizeof(char *)); /* can we iterate enough for a wrapping? */ + if (!sp) { + XpmFree(string); + ext->nlines = nlines; + XpmFreeExtensions(exts, num + 1); + return (XpmNoMemory); + } + ext->lines = sp; + ext->lines[nlines] = string; + nlines++; + xpmNextString(data); + status = xpmGetString(data, &string, &l); + if (status != XpmSuccess) { + ext->nlines = nlines; + XpmFreeExtensions(exts, num + 1); + return (status); + } + } + if (!nlines) { + XpmFree(ext->lines); + ext->lines = NULL; + } + ext->nlines = nlines; + num++; + } + if (!num) { + XpmFree(string); + XpmFree(exts); + exts = NULL; + } else if (!notend) + XpmFree(string); + *nextensions = num; + *extensions = exts; + return (XpmSuccess); +} + + +/* function call in case of error */ +#undef RETURN +#define RETURN(status) \ +do { \ + goto error; \ +} while(0) + +/* + * This function parses an Xpm file or data and store the found informations + * in an an XpmImage structure which is returned. + */ +int +xpmParseData( + xpmData *data, + XpmImage *image, + XpmInfo *info) +{ + /* variables to return */ + unsigned int width, height, ncolors, cpp; + unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0; + XpmColor *colorTable = NULL; + unsigned int *pixelindex = NULL; + char *hints_cmt = NULL; + char *colors_cmt = NULL; + char *pixels_cmt = NULL; + + unsigned int cmts; + int ErrorStatus; + xpmHashTable hashtable; + + cmts = info && (info->valuemask & XpmReturnComments); + + /* + * parse the header + */ + ErrorStatus = xpmParseHeader(data); + if (ErrorStatus != XpmSuccess) + return (ErrorStatus); + + /* + * read values + */ + ErrorStatus = xpmParseValues(data, &width, &height, &ncolors, &cpp, + &x_hotspot, &y_hotspot, &hotspot, + &extensions); + if (ErrorStatus != XpmSuccess) + return (ErrorStatus); + + /* + * store the hints comment line + */ + if (cmts) + xpmGetCmt(data, &hints_cmt); + + /* + * init the hashtable + */ + if (USE_HASHTABLE) { + ErrorStatus = xpmHashTableInit(&hashtable); + if (ErrorStatus != XpmSuccess) + RETURN(ErrorStatus); + } + + /* + * read colors + */ + ErrorStatus = xpmParseColors(data, ncolors, cpp, &colorTable, &hashtable); + if (ErrorStatus != XpmSuccess) { + if (USE_HASHTABLE) + xpmHashTableFree(&hashtable); + RETURN(ErrorStatus); + } + + /* + * store the colors comment line + */ + if (cmts) + xpmGetCmt(data, &colors_cmt); + + /* + * read pixels and index them on color number + */ + ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable, + &hashtable, &pixelindex); + + /* + * free the hastable + */ + if (USE_HASHTABLE) + xpmHashTableFree(&hashtable); + + if (ErrorStatus != XpmSuccess) + RETURN(ErrorStatus); + + /* + * store the pixels comment line + */ + if (cmts) + xpmGetCmt(data, &pixels_cmt); + + /* + * parse extensions + */ + if (info && (info->valuemask & XpmReturnExtensions)) { + if (extensions) { + ErrorStatus = xpmParseExtensions(data, &info->extensions, + &info->nextensions); + if (ErrorStatus != XpmSuccess) + RETURN(ErrorStatus); + } else { + info->extensions = NULL; + info->nextensions = 0; + } + } + + /* + * store found informations in the XpmImage structure + */ + image->width = width; + image->height = height; + image->cpp = cpp; + image->ncolors = ncolors; + image->colorTable = colorTable; + image->data = pixelindex; + + if (info) { + if (cmts) { + info->hints_cmt = hints_cmt; + info->colors_cmt = colors_cmt; + info->pixels_cmt = pixels_cmt; + } + if (hotspot) { + info->x_hotspot = x_hotspot; + info->y_hotspot = y_hotspot; + info->valuemask |= XpmHotspot; + } + } + return (XpmSuccess); + +/* exit point in case of error, free only locally allocated variables */ +error: + if (colorTable) + xpmFreeColorTable(colorTable, ncolors); + if (pixelindex) + XpmFree(pixelindex); + if (hints_cmt) + XpmFree(hints_cmt); + if (colors_cmt) + XpmFree(colors_cmt); + if (pixels_cmt) + XpmFree(pixels_cmt); + + return(ErrorStatus); +} diff --git a/be_xpm/rgb.c b/be_xpm/rgb.c new file mode 100644 index 0000000000..83309df6ef --- /dev/null +++ b/be_xpm/rgb.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* rgb.c: * +* * +* XPM library * +* Rgb file utilities * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * The code related to FOR_MSW has been added by + * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 + */ + +/* + * Part of this code has been taken from the ppmtoxpm.c file written by Mark + * W. Snitily but has been modified for my special need + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" +#include + +#ifndef FOR_MSW /* normal part first, MSW part at + * the end, (huge ifdef!) */ +/* + * Read a rgb text file. It stores the rgb values (0->65535) + * and the rgb mnemonics (malloc'ed) into the "rgbn" array. Returns the + * number of entries stored. + */ +int +xpmReadRgbNames( + char *rgb_fname, + xpmRgbName rgbn[]) +{ + FILE *rgbf; + int n, items, red, green, blue; + char line[512], name[512], *rgbname, *s1, *s2; + xpmRgbName *rgb; + + /* Open the rgb text file. Abort if error. */ + if ((rgbf = fopen(rgb_fname, "r")) == NULL) + return 0; + + /* Loop reading each line in the file. */ + n = 0; + rgb = rgbn; + /* Quit if rgb text file has too many entries. */ + while (fgets(line, sizeof(line), rgbf) && n < MAX_RGBNAMES) { + + /* Skip silently if line is bad. */ + items = sscanf(line, "%d %d %d %[^\n]\n", &red, &green, &blue, name); + if (items != 4) + continue; + + /* + * Make sure rgb values are within 0->255 range. Skip silently if + * bad. + */ + if (red < 0 || red > 0xFF || + green < 0 || green > 0xFF || + blue < 0 || blue > 0xFF) + continue; + + /* Allocate memory for ascii name. If error give up here. */ + if (!(rgbname = (char *) XpmMalloc(strlen(name) + 1))) + break; + + /* Copy string to ascii name and lowercase it. */ + for (s1 = name, s2 = rgbname; *s1; s1++) + *s2++ = tolower(*s1); + *s2 = '\0'; + + /* Save the rgb values and ascii name in the array. */ + rgb->r = red * 257; /* 65535/255 = 257 */ + rgb->g = green * 257; + rgb->b = blue * 257; + rgb->name = rgbname; + rgb++; + n++; + } + + fclose(rgbf); + + /* Return the number of read rgb names. */ + return n < 0 ? 0 : n; +} + +/* + * Return the color name corresponding to the given rgb values + */ +char * +xpmGetRgbName( + xpmRgbName rgbn[], /* rgb mnemonics from rgb text file */ + int rgbn_max, /* number of rgb mnemonics in table */ + int red, /* rgb values */ + int green, + int blue) +{ + int i; + xpmRgbName *rgb; + + /* + * Just perform a dumb linear search over the rgb values of the color + * mnemonics. One could speed things up by sorting the rgb values and + * using a binary search, or building a hash table, etc... + */ + for (i = 0, rgb = rgbn; i < rgbn_max; i++, rgb++) + if (red == rgb->r && green == rgb->g && blue == rgb->b) + return rgb->name; + + /* if not found return NULL */ + return NULL; +} + +/* + * Free the strings which have been malloc'ed in xpmReadRgbNames + */ +void +xpmFreeRgbNames( + xpmRgbName rgbn[], + int rgbn_max) +{ + int i; + xpmRgbName *rgb; + + for (i = 0, rgb = rgbn; i < rgbn_max; i++, rgb++) + XpmFree(rgb->name); +} + +#else /* here comes the MSW part, the + * second part of the huge ifdef */ + +#include "rgbtab.h" /* hard coded rgb.txt table */ + +int +xpmReadRgbNames( + char *rgb_fname, + xpmRgbName rgbn[]) +{ + /* + * check for consistency??? + * table has to be sorted for calls on strcasecmp + */ + return (numTheRGBRecords); +} + +char * +xpmGetRgbName( + xpmRgbName rgbn[], /* rgb mnemonics from rgb text file + * not used */ + int rgbn_max, /* not used */ + int red, /* rgb values */ + int green, + int blue) + +{ + int i; + unsigned long rgbVal; + + i = 0; + while (i < numTheRGBRecords) { + rgbVal = theRGBRecords[i].rgb; + if ((rgbVal >> 16) & 0xff == red && + (rgbVal >> 8) & 0xff == green && + rgbVal & 0xff == blue) + return (theRGBRecords[i].name); + i++; + } + return (NULL); +} + +/* used in XParseColor in simx.c */ +int +xpmGetRGBfromName( + char *inname, + int *r, + int *g, + int *b) +{ + int left, right, middle; + int cmp; + unsigned long rgbVal; + char *name; + char *grey, *p; + + name = xpmstrdup(inname); + + /* + * the table in rgbtab.c has no names with spaces, and no grey, but a + * lot of gray + */ + /* so first extract ' ' */ + while (p = strchr(name, ' ')) { + while (*(p)) { /* till eof of string */ + *p = *(p + 1); /* copy to the left */ + p++; + } + } + /* fold to lower case */ + p = name; + while (*p) { + *p = tolower(*p); + p++; + } + + /* + * substitute Grey with Gray, else rgbtab.h would have more than 100 + * 'duplicate' entries + */ + if (grey = strstr(name, "grey")) + grey[2] = 'a'; + + /* binary search */ + left = 0; + right = numTheRGBRecords - 1; + do { + middle = (left + right) / 2; + cmp = xpmstrcasecmp(name, theRGBRecords[middle].name); + if (cmp == 0) { + rgbVal = theRGBRecords[middle].rgb; + *r = (rgbVal >> 16) & 0xff; + *g = (rgbVal >> 8) & 0xff; + *b = rgbVal & 0xff; + free(name); + return (1); + } else if (cmp < 0) { + right = middle - 1; + } else { /* > 0 */ + left = middle + 1; + } + } while (left <= right); + + /* + * I don't like to run in a ColorInvalid error and to see no pixmap at + * all, so simply return a red pixel. Should be wrapped in an #ifdef + * HeDu + */ + + *r = 255; + *g = 0; + *b = 0; /* red error pixel */ + + free(name); + return (1); +} + +void +xpmFreeRgbNames( + xpmRgbName rgbn[], + int rgbn_max) +{ + /* nothing to do */ +} + +#endif /* MSW part */ diff --git a/be_xpm/rgbtab.h b/be_xpm/rgbtab.h new file mode 100644 index 0000000000..dcfb7b10be --- /dev/null +++ b/be_xpm/rgbtab.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* rgbtab.h * +* * +* A hard coded rgb.txt. To keep it short I removed all colornames with * +* trailing numbers, Blue3 etc, except the GrayXX. Sorry Grey-lovers I prefer * +* Gray ;-). But Grey is recognized on lookups, only on save Gray will be * +* used, maybe you want to do some substitue there too. * +* * +* To save memory the RGBs are coded in one long value, as done by the RGB * +* macro. * +* * +* Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de) * +\*****************************************************************************/ + + +typedef struct { + char *name; + unsigned long rgb; /* it's unsigned long */ +} rgbRecord; + +#define myRGB(r,g,b) \ + ((unsigned long)r<<16|(unsigned long)g<<8|(unsigned long)b) + + +static rgbRecord theRGBRecords[] = +{ + {"AliceBlue", myRGB(240, 248, 255)}, + {"AntiqueWhite", myRGB(250, 235, 215)}, + {"Aquamarine", myRGB(50, 191, 193)}, + {"Azure", myRGB(240, 255, 255)}, + {"Beige", myRGB(245, 245, 220)}, + {"Bisque", myRGB(255, 228, 196)}, + {"Black", myRGB(0, 0, 0)}, + {"BlanchedAlmond", myRGB(255, 235, 205)}, + {"Blue", myRGB(0, 0, 255)}, + {"BlueViolet", myRGB(138, 43, 226)}, + {"Brown", myRGB(165, 42, 42)}, + {"burlywood", myRGB(222, 184, 135)}, + {"CadetBlue", myRGB(95, 146, 158)}, + {"chartreuse", myRGB(127, 255, 0)}, + {"chocolate", myRGB(210, 105, 30)}, + {"Coral", myRGB(255, 114, 86)}, + {"CornflowerBlue", myRGB(34, 34, 152)}, + {"cornsilk", myRGB(255, 248, 220)}, + {"Cyan", myRGB(0, 255, 255)}, + {"DarkGoldenrod", myRGB(184, 134, 11)}, + {"DarkGreen", myRGB(0, 86, 45)}, + {"DarkKhaki", myRGB(189, 183, 107)}, + {"DarkOliveGreen", myRGB(85, 86, 47)}, + {"DarkOrange", myRGB(255, 140, 0)}, + {"DarkOrchid", myRGB(139, 32, 139)}, + {"DarkSalmon", myRGB(233, 150, 122)}, + {"DarkSeaGreen", myRGB(143, 188, 143)}, + {"DarkSlateBlue", myRGB(56, 75, 102)}, + {"DarkSlateGray", myRGB(47, 79, 79)}, + {"DarkTurquoise", myRGB(0, 166, 166)}, + {"DarkViolet", myRGB(148, 0, 211)}, + {"DeepPink", myRGB(255, 20, 147)}, + {"DeepSkyBlue", myRGB(0, 191, 255)}, + {"DimGray", myRGB(84, 84, 84)}, + {"DodgerBlue", myRGB(30, 144, 255)}, + {"Firebrick", myRGB(142, 35, 35)}, + {"FloralWhite", myRGB(255, 250, 240)}, + {"ForestGreen", myRGB(80, 159, 105)}, + {"gainsboro", myRGB(220, 220, 220)}, + {"GhostWhite", myRGB(248, 248, 255)}, + {"Gold", myRGB(218, 170, 0)}, + {"Goldenrod", myRGB(239, 223, 132)}, + {"Gray", myRGB(126, 126, 126)}, + {"Gray0", myRGB(0, 0, 0)}, + {"Gray1", myRGB(3, 3, 3)}, + {"Gray10", myRGB(26, 26, 26)}, + {"Gray100", myRGB(255, 255, 255)}, + {"Gray11", myRGB(28, 28, 28)}, + {"Gray12", myRGB(31, 31, 31)}, + {"Gray13", myRGB(33, 33, 33)}, + {"Gray14", myRGB(36, 36, 36)}, + {"Gray15", myRGB(38, 38, 38)}, + {"Gray16", myRGB(41, 41, 41)}, + {"Gray17", myRGB(43, 43, 43)}, + {"Gray18", myRGB(46, 46, 46)}, + {"Gray19", myRGB(48, 48, 48)}, + {"Gray2", myRGB(5, 5, 5)}, + {"Gray20", myRGB(51, 51, 51)}, + {"Gray21", myRGB(54, 54, 54)}, + {"Gray22", myRGB(56, 56, 56)}, + {"Gray23", myRGB(59, 59, 59)}, + {"Gray24", myRGB(61, 61, 61)}, + {"Gray25", myRGB(64, 64, 64)}, + {"Gray26", myRGB(66, 66, 66)}, + {"Gray27", myRGB(69, 69, 69)}, + {"Gray28", myRGB(71, 71, 71)}, + {"Gray29", myRGB(74, 74, 74)}, + {"Gray3", myRGB(8, 8, 8)}, + {"Gray30", myRGB(77, 77, 77)}, + {"Gray31", myRGB(79, 79, 79)}, + {"Gray32", myRGB(82, 82, 82)}, + {"Gray33", myRGB(84, 84, 84)}, + {"Gray34", myRGB(87, 87, 87)}, + {"Gray35", myRGB(89, 89, 89)}, + {"Gray36", myRGB(92, 92, 92)}, + {"Gray37", myRGB(94, 94, 94)}, + {"Gray38", myRGB(97, 97, 97)}, + {"Gray39", myRGB(99, 99, 99)}, + {"Gray4", myRGB(10, 10, 10)}, + {"Gray40", myRGB(102, 102, 102)}, + {"Gray41", myRGB(105, 105, 105)}, + {"Gray42", myRGB(107, 107, 107)}, + {"Gray43", myRGB(110, 110, 110)}, + {"Gray44", myRGB(112, 112, 112)}, + {"Gray45", myRGB(115, 115, 115)}, + {"Gray46", myRGB(117, 117, 117)}, + {"Gray47", myRGB(120, 120, 120)}, + {"Gray48", myRGB(122, 122, 122)}, + {"Gray49", myRGB(125, 125, 125)}, + {"Gray5", myRGB(13, 13, 13)}, + {"Gray50", myRGB(127, 127, 127)}, + {"Gray51", myRGB(130, 130, 130)}, + {"Gray52", myRGB(133, 133, 133)}, + {"Gray53", myRGB(135, 135, 135)}, + {"Gray54", myRGB(138, 138, 138)}, + {"Gray55", myRGB(140, 140, 140)}, + {"Gray56", myRGB(143, 143, 143)}, + {"Gray57", myRGB(145, 145, 145)}, + {"Gray58", myRGB(148, 148, 148)}, + {"Gray59", myRGB(150, 150, 150)}, + {"Gray6", myRGB(15, 15, 15)}, + {"Gray60", myRGB(153, 153, 153)}, + {"Gray61", myRGB(156, 156, 156)}, + {"Gray62", myRGB(158, 158, 158)}, + {"Gray63", myRGB(161, 161, 161)}, + {"Gray64", myRGB(163, 163, 163)}, + {"Gray65", myRGB(166, 166, 166)}, + {"Gray66", myRGB(168, 168, 168)}, + {"Gray67", myRGB(171, 171, 171)}, + {"Gray68", myRGB(173, 173, 173)}, + {"Gray69", myRGB(176, 176, 176)}, + {"Gray7", myRGB(18, 18, 18)}, + {"Gray70", myRGB(179, 179, 179)}, + {"Gray71", myRGB(181, 181, 181)}, + {"Gray72", myRGB(184, 184, 184)}, + {"Gray73", myRGB(186, 186, 186)}, + {"Gray74", myRGB(189, 189, 189)}, + {"Gray75", myRGB(191, 191, 191)}, + {"Gray76", myRGB(194, 194, 194)}, + {"Gray77", myRGB(196, 196, 196)}, + {"Gray78", myRGB(199, 199, 199)}, + {"Gray79", myRGB(201, 201, 201)}, + {"Gray8", myRGB(20, 20, 20)}, + {"Gray80", myRGB(204, 204, 204)}, + {"Gray81", myRGB(207, 207, 207)}, + {"Gray82", myRGB(209, 209, 209)}, + {"Gray83", myRGB(212, 212, 212)}, + {"Gray84", myRGB(214, 214, 214)}, + {"Gray85", myRGB(217, 217, 217)}, + {"Gray86", myRGB(219, 219, 219)}, + {"Gray87", myRGB(222, 222, 222)}, + {"Gray88", myRGB(224, 224, 224)}, + {"Gray89", myRGB(227, 227, 227)}, + {"Gray9", myRGB(23, 23, 23)}, + {"Gray90", myRGB(229, 229, 229)}, + {"Gray91", myRGB(232, 232, 232)}, + {"Gray92", myRGB(235, 235, 235)}, + {"Gray93", myRGB(237, 237, 237)}, + {"Gray94", myRGB(240, 240, 240)}, + {"Gray95", myRGB(242, 242, 242)}, + {"Gray96", myRGB(245, 245, 245)}, + {"Gray97", myRGB(247, 247, 247)}, + {"Gray98", myRGB(250, 250, 250)}, + {"Gray99", myRGB(252, 252, 252)}, + {"Green", myRGB(0, 255, 0)}, + {"GreenYellow", myRGB(173, 255, 47)}, + {"honeydew", myRGB(240, 255, 240)}, + {"HotPink", myRGB(255, 105, 180)}, + {"IndianRed", myRGB(107, 57, 57)}, + {"ivory", myRGB(255, 255, 240)}, + {"Khaki", myRGB(179, 179, 126)}, + {"lavender", myRGB(230, 230, 250)}, + {"LavenderBlush", myRGB(255, 240, 245)}, + {"LawnGreen", myRGB(124, 252, 0)}, + {"LemonChiffon", myRGB(255, 250, 205)}, + {"LightBlue", myRGB(176, 226, 255)}, + {"LightCoral", myRGB(240, 128, 128)}, + {"LightCyan", myRGB(224, 255, 255)}, + {"LightGoldenrod", myRGB(238, 221, 130)}, + {"LightGoldenrodYellow", myRGB(250, 250, 210)}, + {"LightGray", myRGB(168, 168, 168)}, + {"LightPink", myRGB(255, 182, 193)}, + {"LightSalmon", myRGB(255, 160, 122)}, + {"LightSeaGreen", myRGB(32, 178, 170)}, + {"LightSkyBlue", myRGB(135, 206, 250)}, + {"LightSlateBlue", myRGB(132, 112, 255)}, + {"LightSlateGray", myRGB(119, 136, 153)}, + {"LightSteelBlue", myRGB(124, 152, 211)}, + {"LightYellow", myRGB(255, 255, 224)}, + {"LimeGreen", myRGB(0, 175, 20)}, + {"linen", myRGB(250, 240, 230)}, + {"Magenta", myRGB(255, 0, 255)}, + {"Maroon", myRGB(143, 0, 82)}, + {"MediumAquamarine", myRGB(0, 147, 143)}, + {"MediumBlue", myRGB(50, 50, 204)}, + {"MediumForestGreen", myRGB(50, 129, 75)}, + {"MediumGoldenrod", myRGB(209, 193, 102)}, + {"MediumOrchid", myRGB(189, 82, 189)}, + {"MediumPurple", myRGB(147, 112, 219)}, + {"MediumSeaGreen", myRGB(52, 119, 102)}, + {"MediumSlateBlue", myRGB(106, 106, 141)}, + {"MediumSpringGreen", myRGB(35, 142, 35)}, + {"MediumTurquoise", myRGB(0, 210, 210)}, + {"MediumVioletRed", myRGB(213, 32, 121)}, + {"MidnightBlue", myRGB(47, 47, 100)}, + {"MintCream", myRGB(245, 255, 250)}, + {"MistyRose", myRGB(255, 228, 225)}, + {"moccasin", myRGB(255, 228, 181)}, + {"NavajoWhite", myRGB(255, 222, 173)}, + {"Navy", myRGB(35, 35, 117)}, + {"NavyBlue", myRGB(35, 35, 117)}, + {"OldLace", myRGB(253, 245, 230)}, + {"OliveDrab", myRGB(107, 142, 35)}, + {"Orange", myRGB(255, 135, 0)}, + {"OrangeRed", myRGB(255, 69, 0)}, + {"Orchid", myRGB(239, 132, 239)}, + {"PaleGoldenrod", myRGB(238, 232, 170)}, + {"PaleGreen", myRGB(115, 222, 120)}, + {"PaleTurquoise", myRGB(175, 238, 238)}, + {"PaleVioletRed", myRGB(219, 112, 147)}, + {"PapayaWhip", myRGB(255, 239, 213)}, + {"PeachPuff", myRGB(255, 218, 185)}, + {"peru", myRGB(205, 133, 63)}, + {"Pink", myRGB(255, 181, 197)}, + {"Plum", myRGB(197, 72, 155)}, + {"PowderBlue", myRGB(176, 224, 230)}, + {"purple", myRGB(160, 32, 240)}, + {"Red", myRGB(255, 0, 0)}, + {"RosyBrown", myRGB(188, 143, 143)}, + {"RoyalBlue", myRGB(65, 105, 225)}, + {"SaddleBrown", myRGB(139, 69, 19)}, + {"Salmon", myRGB(233, 150, 122)}, + {"SandyBrown", myRGB(244, 164, 96)}, + {"SeaGreen", myRGB(82, 149, 132)}, + {"seashell", myRGB(255, 245, 238)}, + {"Sienna", myRGB(150, 82, 45)}, + {"SkyBlue", myRGB(114, 159, 255)}, + {"SlateBlue", myRGB(126, 136, 171)}, + {"SlateGray", myRGB(112, 128, 144)}, + {"snow", myRGB(255, 250, 250)}, + {"SpringGreen", myRGB(65, 172, 65)}, + {"SteelBlue", myRGB(84, 112, 170)}, + {"Tan", myRGB(222, 184, 135)}, + {"Thistle", myRGB(216, 191, 216)}, + {"tomato", myRGB(255, 99, 71)}, + {"Transparent", myRGB(0, 0, 1)}, + {"Turquoise", myRGB(25, 204, 223)}, + {"Violet", myRGB(156, 62, 206)}, + {"VioletRed", myRGB(243, 62, 150)}, + {"Wheat", myRGB(245, 222, 179)}, + {"White", myRGB(255, 255, 255)}, + {"WhiteSmoke", myRGB(245, 245, 245)}, + {"Yellow", myRGB(255, 255, 0)}, + {"YellowGreen", myRGB(50, 216, 56)}, + NULL +}; + +static int numTheRGBRecords = 234; diff --git a/be_xpm/scan.c b/be_xpm/scan.c new file mode 100644 index 0000000000..fcf10f15f9 --- /dev/null +++ b/be_xpm/scan.c @@ -0,0 +1,1023 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* scan.c: * +* * +* XPM library * +* Scanning utility for XPM file format * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * The code related to FOR_MSW has been added by + * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 + */ + +/* + * The code related to AMIGA has been added by + * Lorens Younes (d93-hyo@nada.kth.se) 4/96 + */ + +/* October 2004, source code review by Thomas Biege */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "XpmI.h" + +#define MAXPRINTABLE 92 /* number of printable ascii chars + * minus \ and " for string compat + * and ? to avoid ANSI trigraphs. */ + +static const char *printable = +" .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZ\ +ASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; + +/* + * printable begin with a space, so in most case, due to my algorithm, when + * the number of different colors is less than MAXPRINTABLE, it will give a + * char follow by "nothing" (a space) in the readable xpm file + */ + + +typedef struct { + Pixel *pixels; + unsigned int *pixelindex; + unsigned int size; + unsigned int ncolors; + unsigned int mask_pixel; /* whether there is or not */ +} PixelsMap; + +LFUNC(storePixel, int, (Pixel pixel, PixelsMap *pmap, + unsigned int *index_return)); + +LFUNC(storeMaskPixel, int, (Pixel pixel, PixelsMap *pmap, + unsigned int *index_return)); + +typedef int (*storeFuncPtr)(Pixel pixel, PixelsMap *pmap, + unsigned int *index_return); + +#ifndef FOR_MSW +# ifndef AMIGA +LFUNC(GetImagePixels, int, (XImage *image, unsigned int width, + unsigned int height, PixelsMap *pmap)); + +LFUNC(GetImagePixels32, int, (XImage *image, unsigned int width, + unsigned int height, PixelsMap *pmap)); + +LFUNC(GetImagePixels16, int, (XImage *image, unsigned int width, + unsigned int height, PixelsMap *pmap)); + +LFUNC(GetImagePixels8, int, (XImage *image, unsigned int width, + unsigned int height, PixelsMap *pmap)); + +LFUNC(GetImagePixels1, int, (XImage *image, unsigned int width, + unsigned int height, PixelsMap *pmap, + storeFuncPtr storeFunc)); +# else /* AMIGA */ +LFUNC(AGetImagePixels, int, (XImage *image, unsigned int width, + unsigned int height, PixelsMap *pmap, + storeFuncPtr storeFunc)); +# endif/* AMIGA */ +#else /* ndef FOR_MSW */ +LFUNC(MSWGetImagePixels, int, (Display *d, XImage *image, unsigned int width, + unsigned int height, PixelsMap *pmap, + storeFuncPtr storeFunc)); +#endif +LFUNC(ScanTransparentColor, int, (XpmColor *color, unsigned int cpp, + XpmAttributes *attributes)); + +LFUNC(ScanOtherColors, int, (Display *display, XpmColor *colors, + unsigned int ncolors, + Pixel *pixels, unsigned int mask, + unsigned int cpp, XpmAttributes *attributes)); + +/* + * This function stores the given pixel in the given arrays which are grown + * if not large enough. + */ +static int +storePixel( + Pixel pixel, + PixelsMap *pmap, + unsigned int *index_return) +{ + unsigned int i; + Pixel *p; + unsigned int ncolors; + + if (*index_return) { /* this is a transparent pixel! */ + *index_return = 0; + return 0; + } + ncolors = pmap->ncolors; + p = pmap->pixels + pmap->mask_pixel; + for (i = pmap->mask_pixel; i < ncolors; i++, p++) + if (*p == pixel) + break; + if (i == ncolors) { + if (ncolors >= pmap->size) { + pmap->size *= 2; + p = (Pixel *) XpmRealloc(pmap->pixels, sizeof(Pixel) * pmap->size); + if (!p) + return (1); + pmap->pixels = p; + + } + (pmap->pixels)[ncolors] = pixel; + pmap->ncolors++; + } + *index_return = i; + return 0; +} + +static int +storeMaskPixel( + Pixel pixel, + PixelsMap *pmap, + unsigned int *index_return) +{ + if (!pixel) { + if (!pmap->ncolors) { + pmap->ncolors = 1; + (pmap->pixels)[0] = 0; + pmap->mask_pixel = 1; + } + *index_return = 1; + } else + *index_return = 0; + return 0; +} + +/* function call in case of error */ +#undef RETURN +#define RETURN(status) \ +do { \ + ErrorStatus = status; \ + goto error; \ +} while(0) + +/* + * This function scans the given image and stores the found informations in + * the given XpmImage structure. + */ +int +XpmCreateXpmImageFromImage( + Display *display, + XImage *image, + XImage *shapeimage, + XpmImage *xpmimage, + XpmAttributes *attributes) +{ + /* variables stored in the XpmAttributes structure */ + unsigned int cpp; + + /* variables to return */ + PixelsMap pmap; + XpmColor *colorTable = NULL; + int ErrorStatus = 0; + + /* calculation variables */ + unsigned int width = 0; + unsigned int height = 0; + unsigned int cppm; /* minimum chars per pixel */ + unsigned int c; + + /* initialize pmap */ + pmap.pixels = NULL; + pmap.pixelindex = NULL; + pmap.size = 256; /* should be enough most of the time */ + pmap.ncolors = 0; + pmap.mask_pixel = 0; + + /* + * get geometry + */ + if (image) { + width = image->width; + height = image->height; + } else if (shapeimage) { + width = shapeimage->width; + height = shapeimage->height; + } + + /* + * retrieve information from the XpmAttributes + */ + if (attributes && (attributes->valuemask & XpmCharsPerPixel +/* 3.2 backward compatibility code */ + || attributes->valuemask & XpmInfos)) +/* end 3.2 bc */ + cpp = attributes->cpp; + else + cpp = 0; + + if ((height > 0 && width >= UINT_MAX / height) || + width * height >= UINT_MAX / sizeof(unsigned int)) + RETURN(XpmNoMemory); + pmap.pixelindex = + (unsigned int *) XpmCalloc(width * height, sizeof(unsigned int)); + if (!pmap.pixelindex) + RETURN(XpmNoMemory); + + if (pmap.size >= UINT_MAX / sizeof(Pixel)) + RETURN(XpmNoMemory); + + pmap.pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * pmap.size); + if (!pmap.pixels) + RETURN(XpmNoMemory); + + /* + * scan shape mask if any + */ + if (shapeimage) { +#ifndef FOR_MSW +# ifndef AMIGA + ErrorStatus = GetImagePixels1(shapeimage, width, height, &pmap, + storeMaskPixel); +# else + ErrorStatus = AGetImagePixels(shapeimage, width, height, &pmap, + storeMaskPixel); +# endif +#else + ErrorStatus = MSWGetImagePixels(display, shapeimage, width, height, + &pmap, storeMaskPixel); +#endif + if (ErrorStatus != XpmSuccess) + RETURN(ErrorStatus); + } + + /* + * scan the image data + * + * In case depth is 1 or bits_per_pixel is 4, 6, 8, 24 or 32 use optimized + * functions, otherwise use slower but sure general one. + * + */ + + if (image) { +#ifndef FOR_MSW +# ifndef AMIGA + if (((image->bits_per_pixel | image->depth) == 1) && + (image->byte_order == image->bitmap_bit_order)) + ErrorStatus = GetImagePixels1(image, width, height, &pmap, + storePixel); + else if (image->format == ZPixmap) { + if (image->bits_per_pixel == 8) + ErrorStatus = GetImagePixels8(image, width, height, &pmap); + else if (image->bits_per_pixel == 16) + ErrorStatus = GetImagePixels16(image, width, height, &pmap); + else if (image->bits_per_pixel == 32) + ErrorStatus = GetImagePixels32(image, width, height, &pmap); + } else + ErrorStatus = GetImagePixels(image, width, height, &pmap); +# else + ErrorStatus = AGetImagePixels(image, width, height, &pmap, + storePixel); +# endif +#else + ErrorStatus = MSWGetImagePixels(display, image, width, height, &pmap, + storePixel); +#endif + if (ErrorStatus != XpmSuccess) + RETURN(ErrorStatus); + } + + /* + * get rgb values and a string of char, and possibly a name for each + * color + */ + if (pmap.ncolors >= UINT_MAX / sizeof(XpmColor)) + RETURN(XpmNoMemory); + colorTable = (XpmColor *) XpmCalloc(pmap.ncolors, sizeof(XpmColor)); + if (!colorTable) + RETURN(XpmNoMemory); + + /* compute the minimal cpp */ + for (cppm = 1, c = MAXPRINTABLE; pmap.ncolors > c; cppm++) + c *= MAXPRINTABLE; + if (cpp < cppm) + cpp = cppm; + + if (pmap.mask_pixel) { + ErrorStatus = ScanTransparentColor(colorTable, cpp, attributes); + if (ErrorStatus != XpmSuccess) + RETURN(ErrorStatus); + } + + ErrorStatus = ScanOtherColors(display, colorTable, pmap.ncolors, + pmap.pixels, pmap.mask_pixel, cpp, + attributes); + if (ErrorStatus != XpmSuccess) + RETURN(ErrorStatus); + + /* + * store found informations in the XpmImage structure + */ + xpmimage->width = width; + xpmimage->height = height; + xpmimage->cpp = cpp; + xpmimage->ncolors = pmap.ncolors; + xpmimage->colorTable = colorTable; + xpmimage->data = pmap.pixelindex; + + XpmFree(pmap.pixels); + return (XpmSuccess); + +/* exit point in case of error, free only locally allocated variables */ +error: + if (pmap.pixelindex) + XpmFree(pmap.pixelindex); + if (pmap.pixels) + XpmFree(pmap.pixels); + if (colorTable) + xpmFreeColorTable(colorTable, pmap.ncolors); + + return (ErrorStatus); +} + +static int +ScanTransparentColor( + XpmColor *color, + unsigned int cpp, + XpmAttributes *attributes) +{ + char *s; + unsigned int a, b, c; + + /* first get a character string */ + a = 0; + if (cpp >= UINT_MAX - 1) + return (XpmNoMemory); + if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) + return (XpmNoMemory); + *s++ = printable[c = a % MAXPRINTABLE]; + for (b = 1; b < cpp; b++, s++) + *s = printable[c = ((a - c) / MAXPRINTABLE) % MAXPRINTABLE]; + *s = '\0'; + + /* then retreive related info from the attributes if any */ + if (attributes && (attributes->valuemask & XpmColorTable +/* 3.2 backward compatibility code */ + || attributes->valuemask & XpmInfos) +/* end 3.2 bc */ + && attributes->mask_pixel != XpmUndefPixel) { + + unsigned int key; + char **defaults = (char **) color; + char **mask_defaults; + +/* 3.2 backward compatibility code */ + if (attributes->valuemask & XpmColorTable) +/* end 3.2 bc */ + mask_defaults = (char **) ( + attributes->colorTable + attributes->mask_pixel); +/* 3.2 backward compatibility code */ + else + mask_defaults = (char **) + ((XpmColor **) attributes->colorTable)[attributes->mask_pixel]; +/* end 3.2 bc */ + for (key = 1; key <= NKEYS; key++) { + if ((s = mask_defaults[key])) { + defaults[key] = (char *) xpmstrdup(s); + if (!defaults[key]) + return (XpmNoMemory); + } + } + } else { + color->c_color = (char *) xpmstrdup(TRANSPARENT_COLOR); + if (!color->c_color) + return (XpmNoMemory); + } + return (XpmSuccess); +} + +static int +ScanOtherColors( + Display *display, + XpmColor *colors, + unsigned int ncolors, + Pixel *pixels, + unsigned int mask, + unsigned int cpp, + XpmAttributes *attributes) +{ + /* variables stored in the XpmAttributes structure */ + Colormap colormap; + char *rgb_fname; + +#ifndef FOR_MSW + xpmRgbName rgbn[MAX_RGBNAMES]; +#else + xpmRgbName *rgbn = NULL; +#endif + int rgbn_max = 0; + unsigned int i, j, c, i2; + XpmColor *color; + XColor *xcolors = NULL, *xcolor; + char *colorname, *s; + XpmColor *colorTable = NULL, **oldColorTable = NULL; + unsigned int ancolors = 0; + Pixel *apixels = NULL; + unsigned int mask_pixel = 0; + Bool found; + + /* retrieve information from the XpmAttributes */ + if (attributes && (attributes->valuemask & XpmColormap)) + colormap = attributes->colormap; + else + colormap = XDefaultColormap(display, XDefaultScreen(display)); + if (attributes && (attributes->valuemask & XpmRgbFilename)) + rgb_fname = attributes->rgb_fname; + else + rgb_fname = NULL; + + /* start from the right element */ + if (mask) { + colors++; + ncolors--; + pixels++; + } + + /* first get character strings and rgb values */ + if (ncolors >= UINT_MAX / sizeof(XColor) || cpp >= UINT_MAX - 1) + return (XpmNoMemory); + xcolors = (XColor *) XpmMalloc(sizeof(XColor) * ncolors); + if (!xcolors) + return (XpmNoMemory); + + for (i = 0, i2 = mask, color = colors, xcolor = xcolors; + i < ncolors; i++, i2++, color++, xcolor++, pixels++) { + + if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) { + XpmFree(xcolors); + return (XpmNoMemory); + } + *s++ = printable[c = i2 % MAXPRINTABLE]; + for (j = 1; j < cpp; j++, s++) + *s = printable[c = ((i2 - c) / MAXPRINTABLE) % MAXPRINTABLE]; + *s = '\0'; + + xcolor->pixel = *pixels; + } + XQueryColors(display, colormap, xcolors, ncolors); + +#ifndef FOR_MSW + /* read the rgb file if any was specified */ + if (rgb_fname) + rgbn_max = xpmReadRgbNames(attributes->rgb_fname, rgbn); +#else + /* FOR_MSW: rgb names and values are hardcoded in rgbtab.h */ + rgbn_max = xpmReadRgbNames(NULL, NULL); +#endif + + if (attributes && attributes->valuemask & XpmColorTable) { + colorTable = attributes->colorTable; + ancolors = attributes->ncolors; + apixels = attributes->pixels; + mask_pixel = attributes->mask_pixel; + } +/* 3.2 backward compatibility code */ + else if (attributes && attributes->valuemask & XpmInfos) { + oldColorTable = (XpmColor **) attributes->colorTable; + ancolors = attributes->ncolors; + apixels = attributes->pixels; + mask_pixel = attributes->mask_pixel; + } +/* end 3.2 bc */ + + for (i = 0, color = colors, xcolor = xcolors; i < ncolors; + i++, color++, xcolor++) { + + /* look for related info from the attributes if any */ + found = False; + if (ancolors) { + unsigned int offset = 0; + + for (j = 0; j < ancolors; j++) { + if (j == mask_pixel) { + offset = 1; + continue; + } + if (apixels[j - offset] == xcolor->pixel) + break; + } + if (j != ancolors) { + unsigned int key; + char **defaults = (char **) color; + char **adefaults; + +/* 3.2 backward compatibility code */ + if (oldColorTable) + adefaults = (char **) oldColorTable[j]; + else +/* end 3.2 bc */ + adefaults = (char **) (colorTable + j); + + found = True; + for (key = 1; key <= NKEYS; key++) { + if ((s = adefaults[key])) + defaults[key] = (char *) xpmstrdup(s); + } + } + } + if (!found) { + /* if nothing found look for a color name */ + colorname = NULL; + if (rgbn_max) + colorname = xpmGetRgbName(rgbn, rgbn_max, xcolor->red, + xcolor->green, xcolor->blue); + if (colorname) + color->c_color = (char *) xpmstrdup(colorname); + else { + /* at last store the rgb value */ + char buf[BUFSIZ]; +#ifndef FOR_MSW + sprintf(buf, "#%04X%04X%04X", + xcolor->red, xcolor->green, xcolor->blue); +#else + sprintf(buf, "#%02x%02x%02x", + xcolor->red, xcolor->green, xcolor->blue); +#endif + color->c_color = (char *) xpmstrdup(buf); + } + if (!color->c_color) { + XpmFree(xcolors); + xpmFreeRgbNames(rgbn, rgbn_max); + return (XpmNoMemory); + } + } + } + + XpmFree(xcolors); + xpmFreeRgbNames(rgbn, rgbn_max); + return (XpmSuccess); +} + +#ifndef FOR_MSW +# ifndef AMIGA +/* + * The functions below are written from X11R5 MIT's code (XImUtil.c) + * + * The idea is to have faster functions than the standard XGetPixel function + * to scan the image data. Indeed we can speed up things by suppressing tests + * performed for each pixel. We do exactly the same tests but at the image + * level. + */ + +static unsigned long const low_bits_table[] = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, + 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, + 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; + +/* + * Default method to scan pixels of an image data structure. + * The algorithm used is: + * + * copy the source bitmap_unit or Zpixel into temp + * normalize temp if needed + * extract the pixel bits into return value + * + */ + +static int +GetImagePixels( + XImage *image, + unsigned int width, + unsigned int height, + PixelsMap *pmap) +{ + char *src; + char *dst; + unsigned int *iptr; + char *data; + unsigned int x, y; + int bits, depth, ibu, ibpp, offset, i; + unsigned long lbt; + Pixel pixel, px; + + data = image->data; + iptr = pmap->pixelindex; + depth = image->depth; + lbt = low_bits_table[depth]; + ibpp = image->bits_per_pixel; + offset = image->xoffset; + + if (image->bitmap_unit < 0) + return (XpmNoMemory); + + if ((image->bits_per_pixel | image->depth) == 1) { + ibu = image->bitmap_unit; + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + src = &data[XYINDEX(x, y, image)]; + dst = (char *) &pixel; + pixel = 0; + for (i = ibu >> 3; --i >= 0;) + *dst++ = *src++; + XYNORMALIZE(&pixel, image); + bits = (x + offset) % ibu; + pixel = ((((char *) &pixel)[bits >> 3]) >> (bits & 7)) & 1; + if (ibpp != depth) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + } else if (image->format == XYPixmap) { + int nbytes, bpl, j; + long plane = 0; + ibu = image->bitmap_unit; + nbytes = ibu >> 3; + bpl = image->bytes_per_line; + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + pixel = 0; + plane = 0; + for (i = depth; --i >= 0;) { + src = &data[XYINDEX(x, y, image) + plane]; + dst = (char *) &px; + px = 0; + for (j = nbytes; --j >= 0;) + *dst++ = *src++; + XYNORMALIZE(&px, image); + bits = (x + offset) % ibu; + pixel = (pixel << 1) | + (((((char *) &px)[bits >> 3]) >> (bits & 7)) & 1); + plane = plane + (bpl * height); + } + if (ibpp != depth) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + } else if (image->format == ZPixmap) { + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + src = &data[ZINDEX(x, y, image)]; + dst = (char *) &px; + px = 0; + for (i = (ibpp + 7) >> 3; --i >= 0;) + *dst++ = *src++; + ZNORMALIZE(&px, image); + pixel = 0; + for (i = sizeof(unsigned long); --i >= 0;) + pixel = (pixel << 8) | ((unsigned char *) &px)[i]; + if (ibpp == 4) { + if (x & 1) + pixel >>= 4; + else + pixel &= 0xf; + } + if (ibpp != depth) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + } else + return (XpmColorError); /* actually a bad image */ + return (XpmSuccess); +} + +/* + * scan pixels of a 32-bits Z image data structure + */ + +#if !defined(WORD64) && !defined(LONG64) +static unsigned long byteorderpixel = MSBFirst << 24; +#endif + +static int +GetImagePixels32( + XImage *image, + unsigned int width, + unsigned int height, + PixelsMap *pmap) +{ + unsigned char *addr; + unsigned char *data; + unsigned int *iptr; + unsigned int x, y; + unsigned long lbt; + Pixel pixel; + int depth; + + data = (unsigned char *) image->data; + iptr = pmap->pixelindex; + depth = image->depth; + lbt = low_bits_table[depth]; +#if !defined(WORD64) && !defined(LONG64) + if (*((char *) &byteorderpixel) == image->byte_order) { + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + addr = &data[ZINDEX32(x, y, image)]; + pixel = *((unsigned long *) addr); + if (depth != 32) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + } else +#endif + if (image->byte_order == MSBFirst) + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + addr = &data[ZINDEX32(x, y, image)]; + pixel = ((unsigned long) addr[0] << 24 | + (unsigned long) addr[1] << 16 | + (unsigned long) addr[2] << 8 | + addr[3]); + if (depth != 32) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + else + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + addr = &data[ZINDEX32(x, y, image)]; + pixel = (addr[0] | + (unsigned long) addr[1] << 8 | + (unsigned long) addr[2] << 16 | + (unsigned long) addr[3] << 24); + if (depth != 32) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + return (XpmSuccess); +} + +/* + * scan pixels of a 16-bits Z image data structure + */ + +static int +GetImagePixels16( + XImage *image, + unsigned int width, + unsigned int height, + PixelsMap *pmap) +{ + unsigned char *addr; + unsigned char *data; + unsigned int *iptr; + unsigned int x, y; + unsigned long lbt; + Pixel pixel; + int depth; + + data = (unsigned char *) image->data; + iptr = pmap->pixelindex; + depth = image->depth; + lbt = low_bits_table[depth]; + if (image->byte_order == MSBFirst) + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + addr = &data[ZINDEX16(x, y, image)]; + pixel = addr[0] << 8 | addr[1]; + if (depth != 16) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + else + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + addr = &data[ZINDEX16(x, y, image)]; + pixel = addr[0] | addr[1] << 8; + if (depth != 16) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + return (XpmSuccess); +} + +/* + * scan pixels of a 8-bits Z image data structure + */ + +static int +GetImagePixels8( + XImage *image, + unsigned int width, + unsigned int height, + PixelsMap *pmap) +{ + unsigned int *iptr; + unsigned char *data; + unsigned int x, y; + unsigned long lbt; + Pixel pixel; + int depth; + + data = (unsigned char *) image->data; + iptr = pmap->pixelindex; + depth = image->depth; + lbt = low_bits_table[depth]; + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + pixel = data[ZINDEX8(x, y, image)]; + if (depth != 8) + pixel &= lbt; + if (storePixel(pixel, pmap, iptr)) + return (XpmNoMemory); + } + return (XpmSuccess); +} + +/* + * scan pixels of a 1-bit depth Z image data structure + */ + +static int +GetImagePixels1( + XImage *image, + unsigned int width, + unsigned int height, + PixelsMap *pmap, + storeFuncPtr storeFunc) +{ + unsigned int *iptr; + unsigned int x, y; + char *data; + Pixel pixel; + int xoff, yoff, offset, bpl; + + data = image->data; + iptr = pmap->pixelindex; + offset = image->xoffset; + bpl = image->bytes_per_line; + + if (image->bitmap_bit_order == MSBFirst) + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + xoff = x + offset; + yoff = y * bpl + (xoff >> 3); + xoff &= 7; + pixel = (data[yoff] & (0x80 >> xoff)) ? 1 : 0; + if ((*storeFunc) (pixel, pmap, iptr)) + return (XpmNoMemory); + } + else + for (y = 0; y < height; y++) + for (x = 0; x < width; x++, iptr++) { + xoff = x + offset; + yoff = y * bpl + (xoff >> 3); + xoff &= 7; + pixel = (data[yoff] & (1 << xoff)) ? 1 : 0; + if ((*storeFunc) (pixel, pmap, iptr)) + return (XpmNoMemory); + } + return (XpmSuccess); +} + +# else /* AMIGA */ + +#define CLEAN_UP(status) \ +do {\ + if (pixels) XpmFree (pixels);\ + if (tmp_img) FreeXImage (tmp_img);\ + return (status);\ +} while(0) + +static int +AGetImagePixels ( + XImage *image, + unsigned int width, + unsigned int height, + PixelsMap *pmap, + int (*storeFunc) (Pixel, PixelsMap *, unsigned int *)) +{ + unsigned int *iptr; + unsigned int x, y; + unsigned char *pixels; + XImage *tmp_img; + + pixels = XpmMalloc ((((width+15)>>4)<<4)*sizeof (*pixels)); + if (pixels == NULL) + return XpmNoMemory; + + tmp_img = AllocXImage ((((width+15)>>4)<<4), 1, image->rp->BitMap->Depth); + if (tmp_img == NULL) + CLEAN_UP (XpmNoMemory); + + iptr = pmap->pixelindex; + for (y = 0; y < height; ++y) + { + ReadPixelLine8 (image->rp, 0, y, width, pixels, tmp_img->rp); + for (x = 0; x < width; ++x, ++iptr) + { + if ((*storeFunc) (pixels[x], pmap, iptr)) + CLEAN_UP (XpmNoMemory); + } + } + + CLEAN_UP (XpmSuccess); +} + +#undef CLEAN_UP + +# endif/* AMIGA */ +#else /* ndef FOR_MSW */ +static int +MSWGetImagePixels( + Display *display, + XImage *image, + unsigned int width, + unsigned int height, + PixelsMap *pmap, + int (*storeFunc) (Pixel, PixelsMap*, unsigned int *)) +{ + unsigned int *iptr; + unsigned int x, y; + Pixel pixel; + + iptr = pmap->pixelindex; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++, iptr++) { + pixel = XGetPixel(image, x, y); + if ((*storeFunc) (pixel, pmap, iptr)) + return (XpmNoMemory); + } + } + return (XpmSuccess); +} + +#endif + +#ifndef FOR_MSW +# ifndef AMIGA +int +XpmCreateXpmImageFromPixmap( + Display *display, + Pixmap pixmap, + Pixmap shapemask, + XpmImage *xpmimage, + XpmAttributes *attributes) +{ + XImage *ximage = NULL; + XImage *shapeimage = NULL; + unsigned int width = 0; + unsigned int height = 0; + int ErrorStatus; + + /* get geometry */ + if (attributes && attributes->valuemask & XpmSize) { + width = attributes->width; + height = attributes->height; + } + /* get the ximages */ + if (pixmap) + xpmCreateImageFromPixmap(display, pixmap, &ximage, &width, &height); + if (shapemask) + xpmCreateImageFromPixmap(display, shapemask, &shapeimage, + &width, &height); + + /* create the related XpmImage */ + ErrorStatus = XpmCreateXpmImageFromImage(display, ximage, shapeimage, + xpmimage, attributes); + + /* destroy the ximages */ + if (ximage) + XDestroyImage(ximage); + if (shapeimage) + XDestroyImage(shapeimage); + + return (ErrorStatus); +} + +# endif/* not AMIGA */ +#endif /* ndef FOR_MSW */ diff --git a/be_xpm/simx.h b/be_xpm/simx.h new file mode 100644 index 0000000000..cf42fd26aa --- /dev/null +++ b/be_xpm/simx.h @@ -0,0 +1,116 @@ +/* Utilities and defines for using XPM without X on Haiku + +Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +/* Parts taken from libXpm simx.h, whose copyright notice is + reproduced below: */ + +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +#ifndef _SIMX_H +#define _SIMX_H + +#include + +#define _XFUNCPROTOBEGIN +#define _XFUNCPROTOEND + +typedef void *Window; +typedef void *Drawable; +typedef void *Pixmap; +typedef int Display; +typedef void *Screen; +typedef void *Visual; +typedef void *Colormap; +typedef uint32_t Pixel; + +#define PIXEL_ALREADY_TYPEDEFED + +typedef struct +{ + Pixel pixel; + uint8_t red, green, blue; +} XColor; + +typedef struct +{ + void *bitmap; + unsigned int width; + unsigned int height; + unsigned int depth; +} XImage; + +extern void *boundCheckingMalloc (long); +extern void *boundCheckingCalloc (long, long); +extern void *boundCheckingRealloc (void *, long); + +extern int XAllocColor (Display *, Colormap, XColor *); +extern void XPutPixel (XImage *, int, int, unsigned long); +extern unsigned long XGetPixel (XImage *, int, int); +extern Visual *XDefaultVisual (Display *, Screen *); +extern Screen *XDefaultScreen (Display *); +extern Colormap *XDefaultColormap (Display *, Screen *); +extern int XDefaultDepth (Display *, Screen *); +extern int XParseColor (Display *, Colormap *, char *, XColor *); +extern void XQueryColors (Display *, Colormap *, XColor *, int); +extern int XFreeColors (Display *, Colormap, Pixel *, int, unsigned long); +extern XImage *XCreateImage (Display *, Visual *, int, int, + int, int, int, int, int, int); +extern void XDestroyImage (XImage *); +extern void XImageFree (XImage *); + +#define ZPixmap 1 /* not really used */ +#define XYBitmap 1 /* not really used */ + +#define AllPlanes ((unsigned long)~0L) +#define GCForeground 0x01 +#define GCBackground 0x02 + + +#ifndef True +#define True 1 +#define False 0 +#endif +#ifndef Bool +typedef int Bool; +#endif + +#endif /* _SIMX_H */ diff --git a/be_xpm/xpm_be.h b/be_xpm/xpm_be.h new file mode 100644 index 0000000000..f108f1f6ea --- /dev/null +++ b/be_xpm/xpm_be.h @@ -0,0 +1,477 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* xpm.h: * +* * +* XPM library * +* Include file * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * The code related to FOR_MSW has been added by + * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 + */ + +/* + * The code related to AMIGA has been added by + * Lorens Younes (d93-hyo@nada.kth.se) 4/96 + */ + +#ifndef XPM_h +#define XPM_h + +/* + * first some identification numbers: + * the version and revision numbers are determined with the following rule: + * SO Major number = LIB minor version number. + * SO Minor number = LIB sub-minor version number. + * e.g: Xpm version 3.2f + * we forget the 3 which is the format number, 2 gives 2, and f gives 6. + * thus we have XpmVersion = 2 and XpmRevision = 6 + * which gives SOXPMLIBREV = 2.6 + * + * Then the XpmIncludeVersion number is built from these numbers. + */ +#define XpmFormat 3 +#define XpmVersion 4 +#define XpmRevision 11 +#define XpmIncludeVersion ((XpmFormat * 100 + XpmVersion) * 100 + XpmRevision) + +#ifndef XPM_NUMBERS + +#ifdef FOR_MSW +# define SYSV /* uses memcpy string.h etc. */ +# include +# include "simx.h" /* defines some X stuff using MSW types */ +#define NEED_STRCASECMP /* at least for MSVC++ */ +#else /* FOR_MSW */ +# ifdef AMIGA +# include "amigax.h" +# else /* not AMIGA */ +# include +# include +# endif /* not AMIGA */ +#endif /* FOR_MSW */ + +/* let's define Pixel if it is not done yet */ +#if ! defined(_XtIntrinsic_h) && ! defined(PIXEL_ALREADY_TYPEDEFED) +typedef unsigned long Pixel; /* Index into colormap */ +# define PIXEL_ALREADY_TYPEDEFED +#endif + +/* Return ErrorStatus codes: + * null if full success + * positive if partial success + * negative if failure + */ + +#define XpmColorError 1 +#define XpmSuccess 0 +#define XpmOpenFailed -1 +#define XpmFileInvalid -2 +#define XpmNoMemory -3 +#define XpmColorFailed -4 + +typedef struct { + char *name; /* Symbolic color name */ + char *value; /* Color value */ + Pixel pixel; /* Color pixel */ +} XpmColorSymbol; + +typedef struct { + char *name; /* name of the extension */ + unsigned int nlines; /* number of lines in this extension */ + char **lines; /* pointer to the extension array of strings */ +} XpmExtension; + +typedef struct { + char *string; /* characters string */ + char *symbolic; /* symbolic name */ + char *m_color; /* monochrom default */ + char *g4_color; /* 4 level grayscale default */ + char *g_color; /* other level grayscale default */ + char *c_color; /* color default */ +} XpmColor; + +typedef struct { + unsigned int width; /* image width */ + unsigned int height; /* image height */ + unsigned int cpp; /* number of characters per pixel */ + unsigned int ncolors; /* number of colors */ + XpmColor *colorTable; /* list of related colors */ + unsigned int *data; /* image data */ +} XpmImage; + +typedef struct { + unsigned long valuemask; /* Specifies which attributes are defined */ + char *hints_cmt; /* Comment of the hints section */ + char *colors_cmt; /* Comment of the colors section */ + char *pixels_cmt; /* Comment of the pixels section */ + unsigned int x_hotspot; /* Returns the x hotspot's coordinate */ + unsigned int y_hotspot; /* Returns the y hotspot's coordinate */ + unsigned int nextensions; /* number of extensions */ + XpmExtension *extensions; /* pointer to array of extensions */ +} XpmInfo; + +typedef int (*XpmAllocColorFunc)( + Display* /* display */, + Colormap /* colormap */, + char* /* colorname */, + XColor* /* xcolor */, + void* /* closure */ +); + +typedef int (*XpmFreeColorsFunc)( + Display* /* display */, + Colormap /* colormap */, + Pixel* /* pixels */, + int /* npixels */, + void* /* closure */ +); + +typedef struct { + unsigned long valuemask; /* Specifies which attributes are + defined */ + + Visual *visual; /* Specifies the visual to use */ + Colormap colormap; /* Specifies the colormap to use */ + unsigned int depth; /* Specifies the depth */ + unsigned int width; /* Returns the width of the created + pixmap */ + unsigned int height; /* Returns the height of the created + pixmap */ + unsigned int x_hotspot; /* Returns the x hotspot's + coordinate */ + unsigned int y_hotspot; /* Returns the y hotspot's + coordinate */ + unsigned int cpp; /* Specifies the number of char per + pixel */ + Pixel *pixels; /* List of used color pixels */ + unsigned int npixels; /* Number of used pixels */ + XpmColorSymbol *colorsymbols; /* List of color symbols to override */ + unsigned int numsymbols; /* Number of symbols */ + char *rgb_fname; /* RGB text file name */ + unsigned int nextensions; /* Number of extensions */ + XpmExtension *extensions; /* List of extensions */ + + unsigned int ncolors; /* Number of colors */ + XpmColor *colorTable; /* List of colors */ +/* 3.2 backward compatibility code */ + char *hints_cmt; /* Comment of the hints section */ + char *colors_cmt; /* Comment of the colors section */ + char *pixels_cmt; /* Comment of the pixels section */ +/* end 3.2 bc */ + unsigned int mask_pixel; /* Color table index of transparent + color */ + + /* Color Allocation Directives */ + Bool exactColors; /* Only use exact colors for visual */ + unsigned int closeness; /* Allowable RGB deviation */ + unsigned int red_closeness; /* Allowable red deviation */ + unsigned int green_closeness; /* Allowable green deviation */ + unsigned int blue_closeness; /* Allowable blue deviation */ + int color_key; /* Use colors from this color set */ + + Pixel *alloc_pixels; /* Returns the list of alloc'ed color + pixels */ + int nalloc_pixels; /* Returns the number of alloc'ed + color pixels */ + + Bool alloc_close_colors; /* Specify whether close colors should + be allocated using XAllocColor + or not */ + int bitmap_format; /* Specify the format of 1bit depth + images: ZPixmap or XYBitmap */ + + /* Color functions */ + XpmAllocColorFunc alloc_color; /* Application color allocator */ + XpmFreeColorsFunc free_colors; /* Application color de-allocator */ + void *color_closure; /* Application private data to pass to + alloc_color and free_colors */ + +} XpmAttributes; + +/* XpmAttributes value masks bits */ +#define XpmVisual (1L<<0) +#define XpmColormap (1L<<1) +#define XpmDepth (1L<<2) +#define XpmSize (1L<<3) /* width & height */ +#define XpmHotspot (1L<<4) /* x_hotspot & y_hotspot */ +#define XpmCharsPerPixel (1L<<5) +#define XpmColorSymbols (1L<<6) +#define XpmRgbFilename (1L<<7) +/* 3.2 backward compatibility code */ +#define XpmInfos (1L<<8) +#define XpmReturnInfos XpmInfos +/* end 3.2 bc */ +#define XpmReturnPixels (1L<<9) +#define XpmExtensions (1L<<10) +#define XpmReturnExtensions XpmExtensions + +#define XpmExactColors (1L<<11) +#define XpmCloseness (1L<<12) +#define XpmRGBCloseness (1L<<13) +#define XpmColorKey (1L<<14) + +#define XpmColorTable (1L<<15) +#define XpmReturnColorTable XpmColorTable + +#define XpmReturnAllocPixels (1L<<16) +#define XpmAllocCloseColors (1L<<17) +#define XpmBitmapFormat (1L<<18) + +#define XpmAllocColor (1L<<19) +#define XpmFreeColors (1L<<20) +#define XpmColorClosure (1L<<21) + + +/* XpmInfo value masks bits */ +#define XpmComments XpmInfos +#define XpmReturnComments XpmComments + +/* XpmAttributes mask_pixel value when there is no mask */ +#ifndef FOR_MSW +#define XpmUndefPixel 0x80000000 +#else +/* int is only 16 bit for MSW */ +#define XpmUndefPixel 0x8000 +#endif + +/* + * color keys for visual type, they must fit along with the number key of + * each related element in xpmColorKeys[] defined in XpmI.h + */ +#define XPM_MONO 2 +#define XPM_GREY4 3 +#define XPM_GRAY4 3 +#define XPM_GREY 4 +#define XPM_GRAY 4 +#define XPM_COLOR 5 + + +/* macros for forward declarations of functions with prototypes */ +#define FUNC(f, t, p) extern t f p +#define LFUNC(f, t, p) static t f p + + +/* + * functions declarations + */ + +_XFUNCPROTOBEGIN + +/* FOR_MSW, all ..Pixmap.. are excluded, only the ..XImage.. are used */ +/* Same for Amiga! */ + +#if !defined(FOR_MSW) && !defined(AMIGA) + FUNC(XpmCreatePixmapFromData, int, (Display *display, + Drawable d, + char **data, + Pixmap *pixmap_return, + Pixmap *shapemask_return, + XpmAttributes *attributes)); + + FUNC(XpmCreateDataFromPixmap, int, (Display *display, + char ***data_return, + Pixmap pixmap, + Pixmap shapemask, + XpmAttributes *attributes)); + + FUNC(XpmReadFileToPixmap, int, (Display *display, + Drawable d, + const char *filename, + Pixmap *pixmap_return, + Pixmap *shapemask_return, + XpmAttributes *attributes)); + + FUNC(XpmWriteFileFromPixmap, int, (Display *display, + const char *filename, + Pixmap pixmap, + Pixmap shapemask, + XpmAttributes *attributes)); +#endif + + FUNC(XpmCreateImageFromData, int, (Display *display, + char **data, + XImage **image_return, + XImage **shapemask_return, + XpmAttributes *attributes)); + + FUNC(XpmCreateDataFromImage, int, (Display *display, + char ***data_return, + XImage *image, + XImage *shapeimage, + XpmAttributes *attributes)); + + FUNC(XpmReadFileToImage, int, (Display *display, + const char *filename, + XImage **image_return, + XImage **shapeimage_return, + XpmAttributes *attributes)); + + FUNC(XpmWriteFileFromImage, int, (Display *display, + const char *filename, + XImage *image, + XImage *shapeimage, + XpmAttributes *attributes)); + + FUNC(XpmCreateImageFromBuffer, int, (Display *display, + char *buffer, + XImage **image_return, + XImage **shapemask_return, + XpmAttributes *attributes)); +#if !defined(FOR_MSW) && !defined(AMIGA) + FUNC(XpmCreatePixmapFromBuffer, int, (Display *display, + Drawable d, + char *buffer, + Pixmap *pixmap_return, + Pixmap *shapemask_return, + XpmAttributes *attributes)); + + FUNC(XpmCreateBufferFromImage, int, (Display *display, + char **buffer_return, + XImage *image, + XImage *shapeimage, + XpmAttributes *attributes)); + + FUNC(XpmCreateBufferFromPixmap, int, (Display *display, + char **buffer_return, + Pixmap pixmap, + Pixmap shapemask, + XpmAttributes *attributes)); +#endif + FUNC(XpmReadFileToBuffer, int, (const char *filename, char **buffer_return)); + FUNC(XpmWriteFileFromBuffer, int, (const char *filename, char *buffer)); + + FUNC(XpmReadFileToData, int, (const char *filename, char ***data_return)); + FUNC(XpmWriteFileFromData, int, (const char *filename, char **data)); + + FUNC(XpmAttributesSize, int, (void)); + FUNC(XpmFreeAttributes, void, (XpmAttributes *attributes)); + FUNC(XpmFreeExtensions, void, (XpmExtension *extensions, + int nextensions)); + + FUNC(XpmFreeXpmImage, void, (XpmImage *image)); + FUNC(XpmFreeXpmInfo, void, (XpmInfo *info)); + FUNC(XpmGetErrorString, char *, (int errcode)); + FUNC(XpmLibraryVersion, int, (void)); + + /* XpmImage functions */ + FUNC(XpmReadFileToXpmImage, int, (const char *filename, + XpmImage *image, + XpmInfo *info)); + + FUNC(XpmWriteFileFromXpmImage, int, (const char *filename, + XpmImage *image, + XpmInfo *info)); +#if !defined(FOR_MSW) && !defined(AMIGA) + FUNC(XpmCreatePixmapFromXpmImage, int, (Display *display, + Drawable d, + XpmImage *image, + Pixmap *pixmap_return, + Pixmap *shapemask_return, + XpmAttributes *attributes)); +#endif + FUNC(XpmCreateImageFromXpmImage, int, (Display *display, + XpmImage *image, + XImage **image_return, + XImage **shapeimage_return, + XpmAttributes *attributes)); + + FUNC(XpmCreateXpmImageFromImage, int, (Display *display, + XImage *image, + XImage *shapeimage, + XpmImage *xpmimage, + XpmAttributes *attributes)); +#if !defined(FOR_MSW) && !defined(AMIGA) + FUNC(XpmCreateXpmImageFromPixmap, int, (Display *display, + Pixmap pixmap, + Pixmap shapemask, + XpmImage *xpmimage, + XpmAttributes *attributes)); +#endif + FUNC(XpmCreateDataFromXpmImage, int, (char ***data_return, + XpmImage *image, + XpmInfo *info)); + + FUNC(XpmCreateXpmImageFromData, int, (char **data, + XpmImage *image, + XpmInfo *info)); + + FUNC(XpmCreateXpmImageFromBuffer, int, (char *buffer, + XpmImage *image, + XpmInfo *info)); + + FUNC(XpmCreateBufferFromXpmImage, int, (char **buffer_return, + XpmImage *image, + XpmInfo *info)); + + FUNC(XpmGetParseError, int, (char *filename, + int *linenum_return, + int *charnum_return)); + + FUNC(XpmFree, void, (void *ptr)); + +_XFUNCPROTOEND + +/* backward compatibility */ + +/* for version 3.0c */ +#define XpmPixmapColorError XpmColorError +#define XpmPixmapSuccess XpmSuccess +#define XpmPixmapOpenFailed XpmOpenFailed +#define XpmPixmapFileInvalid XpmFileInvalid +#define XpmPixmapNoMemory XpmNoMemory +#define XpmPixmapColorFailed XpmColorFailed + +#define XpmReadPixmapFile(dpy, d, file, pix, mask, att) \ + XpmReadFileToPixmap(dpy, d, file, pix, mask, att) +#define XpmWritePixmapFile(dpy, file, pix, mask, att) \ + XpmWriteFileFromPixmap(dpy, file, pix, mask, att) + +/* for version 3.0b */ +#define PixmapColorError XpmColorError +#define PixmapSuccess XpmSuccess +#define PixmapOpenFailed XpmOpenFailed +#define PixmapFileInvalid XpmFileInvalid +#define PixmapNoMemory XpmNoMemory +#define PixmapColorFailed XpmColorFailed + +#define ColorSymbol XpmColorSymbol + +#define XReadPixmapFile(dpy, d, file, pix, mask, att) \ + XpmReadFileToPixmap(dpy, d, file, pix, mask, att) +#define XWritePixmapFile(dpy, file, pix, mask, att) \ + XpmWriteFileFromPixmap(dpy, file, pix, mask, att) +#define XCreatePixmapFromData(dpy, d, data, pix, mask, att) \ + XpmCreatePixmapFromData(dpy, d, data, pix, mask, att) +#define XCreateDataFromPixmap(dpy, data, pix, mask, att) \ + XpmCreateDataFromPixmap(dpy, data, pix, mask, att) + +#endif /* XPM_NUMBERS */ +#endif diff --git a/configure.ac b/configure.ac index 418a62fd5e..96d2c0c8f6 100644 --- a/configure.ac +++ b/configure.ac @@ -508,6 +508,12 @@ AC_DEFUN OPTION_DEFAULT_OFF([xwidgets], [enable use of xwidgets in Emacs buffers (requires gtk3 or macOS Cocoa)]) +OPTION_DEFAULT_OFF([be-app], + [enable use of Haiku's Application Kit as a window system]) + +OPTION_DEFAULT_OFF([be-freetype], + [enable use of FreeType under Haiku's Application Kit]) + ## Makefile.in needs the cache file name. AC_SUBST(cache_file) @@ -784,6 +790,10 @@ AC_DEFUN LDFLAGS="-N2M $LDFLAGS" ;; + *-haiku ) + opsys=haiku + ;; + ## Intel 386 machines where we don't care about the manufacturer. i[3456]86-*-* ) case "${canonical}" in @@ -905,7 +915,9 @@ AC_DEFUN if test $emacs_cv_prog_cc_g3 != yes; then CFLAGS=$emacs_save_CFLAGS fi - if test $opsys = mingw32; then + # Haiku also needs -gdwarf-2 because its GDB is too old + # to understand newer formats. + if test $opsys = mingw32 || test $opsys = haiku; then CFLAGS="$CFLAGS -gdwarf-2" fi fi @@ -1572,6 +1584,8 @@ AC_DEFUN ## Motif needs -lgen. unixware) LIBS_SYSTEM="-lsocket -lnsl -lelf -lgen" ;; + + haiku) LIBS_SYSTEM="-lnetwork" ;; esac AC_SUBST(LIBS_SYSTEM) @@ -2077,6 +2091,26 @@ AC_DEFUN fi fi +HAVE_BE_APP=no +if test "${opsys}" = "haiku" && test "${with_be_app}" = "yes"; then + dnl Only GCC and Clang work for now + AC_PROG_CXX([gcc cl CC cxx cc++ c++ g++ clang clang++]) + CXXFLAGS="$CXXFLAGS $emacs_g3_CFLAGS" + AC_LANG_PUSH([C++]) + AC_CHECK_HEADER([Application.h], [HAVE_BE_APP=yes], + [AC_MSG_ERROR([The Application Kit headers required for building +with the Application Kit were not found or cannot be compiled. Either fix this, or +re-configure with the option '--without-be-app'.])]) + AC_LANG_POP([C++]) +fi + +AC_SUBST(HAVE_BE_APP) + +HAVE_BE_FREETYPE=no +if test "${HAVE_BE_APP}" = "yes" && test "${with_be_freetype}" = "yes"; then + HAVE_BE_FREETYPE=yes +fi + HAVE_W32=no W32_OBJ= W32_LIBS= @@ -2198,6 +2232,30 @@ AC_DEFUN with_xft=no fi +HAIKU_OBJ= +HAIKU_CXX_OBJ= +HAIKU_LIBS= +HAIKU_CFLAGS= + +if test "${HAVE_BE_APP}" = "yes"; then + AC_DEFINE([HAVE_HAIKU], 1, + [Define if Emacs will be built with Haiku windowing support]) +fi + +if test "${HAVE_BE_APP}" = "yes"; then + window_system=haiku + with_xft=no + HAIKU_OBJ="$HAIKU_OBJ haikufns.o haikuterm.o haikumenu.o haikufont.o haikuselect.o haiku_io.o" + HAIKU_CXX_OBJ="haiku_support.o haiku_font_support.o haiku_draw_support.o haiku_select.o" + HAIKU_LIBS="-lbe -lgame -ltranslation" # -lgame is needed for set_mouse_position. + HAIKU_CFLAGS="-I$srcdir/../be_xpm" +fi + +AC_SUBST(HAIKU_LIBS) +AC_SUBST(HAIKU_OBJ) +AC_SUBST(HAIKU_CXX_OBJ) +AC_SUBST(HAIKU_CFLAGS) + ## $window_system is now set to the window system we will ## ultimately use. @@ -2237,6 +2295,9 @@ AC_DEFUN w32 ) term_header=w32term.h ;; + haiku ) + term_header=haikuterm.h + ;; esac if test "$window_system" = none && test "X$with_x" != "Xno"; then @@ -2568,7 +2629,8 @@ AC_DEFUN ### Use -lrsvg-2 if available, unless '--with-rsvg=no' is specified. HAVE_RSVG=no -if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${opsys}" = "mingw32"; then +if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" \ + || test "${opsys}" = "mingw32" || test "${HAVE_BE_APP}" = "yes"; then if test "${with_rsvg}" != "no"; then RSVG_REQUIRED=2.14.0 RSVG_MODULE="librsvg-2.0 >= $RSVG_REQUIRED" @@ -2589,7 +2651,8 @@ AC_DEFUN fi HAVE_IMAGEMAGICK=no -if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${HAVE_W32}" = "yes"; then +if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${HAVE_W32}" = "yes" || \ + test "${HAVE_BE_APP}" = "yes"; then if test "${with_imagemagick}" != "no"; then if test -n "$BREW"; then # Homebrew doesn't link ImageMagick 6 by default, so make sure @@ -3239,6 +3302,9 @@ AC_DEFUN elif test "${HAVE_W32}" = "yes"; then AC_DEFINE(USE_TOOLKIT_SCROLL_BARS) USE_TOOLKIT_SCROLL_BARS=yes + elif test "${HAVE_BE_APP}" = "yes"; then + AC_DEFINE(USE_TOOLKIT_SCROLL_BARS) + USE_TOOLKIT_SCROLL_BARS=yes fi fi @@ -3477,6 +3543,67 @@ AC_DEFUN fi fi +### Start of font-backend (under Haiku) selectionn. +if test "${HAVE_BE_APP}" = "yes"; then + if test $HAVE_BE_FREETYPE = "yes"; then + EMACS_CHECK_MODULES([FREETYPE], [freetype2]) + test "$HAVE_FREETYPE" = "no" && AC_MSG_ERROR(freetype on Haiku requires libfreetype) + EMACS_CHECK_MODULES([FONTCONFIG], [fontconfig >= 2.2.0]) + test "$HAVE_FONTCONFIG" = "no" && AC_MSG_ERROR(freetype on Haiku requires libfontconfig) + HAVE_XFT=no + fi + HAVE_LIBOTF=no + if test "${HAVE_FREETYPE}" = "yes"; then + AC_DEFINE(HAVE_FREETYPE, 1, + [Define to 1 if using the freetype and fontconfig libraries.]) + OLD_CFLAGS=$CFLAGS + OLD_LIBS=$LIBS + CFLAGS="$CFLAGS $FREETYPE_CFLAGS" + LIBS="$FREETYPE_LIBS $LIBS" + AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex) + CFLAGS=$OLD_CFLAGS + LIBS=$OLD_LIBS + if test "${with_libotf}" != "no"; then + EMACS_CHECK_MODULES([LIBOTF], [libotf]) + if test "$HAVE_LIBOTF" = "yes"; then + AC_DEFINE(HAVE_LIBOTF, 1, [Define to 1 if using libotf.]) + AC_CHECK_LIB(otf, OTF_get_variation_glyphs, + HAVE_OTF_GET_VARIATION_GLYPHS=yes, + HAVE_OTF_GET_VARIATION_GLYPHS=no) + if test "${HAVE_OTF_GET_VARIATION_GLYPHS}" = "yes"; then + AC_DEFINE(HAVE_OTF_GET_VARIATION_GLYPHS, 1, + [Define to 1 if libotf has OTF_get_variation_glyphs.]) + fi + if ! $PKG_CONFIG --atleast-version=0.9.16 libotf; then + AC_DEFINE(HAVE_OTF_KANNADA_BUG, 1, +[Define to 1 if libotf is affected by https://debbugs.gnu.org/28110.]) + fi + fi + fi + dnl FIXME should there be an error if HAVE_FREETYPE != yes? + dnl Does the new font backend require it, or can it work without it? + fi + + HAVE_M17N_FLT=no + if test "${HAVE_LIBOTF}" = yes; then + if test "${with_m17n_flt}" != "no"; then + EMACS_CHECK_MODULES([M17N_FLT], [m17n-flt]) + if test "$HAVE_M17N_FLT" = "yes"; then + AC_DEFINE(HAVE_M17N_FLT, 1, [Define to 1 if using libm17n-flt.]) + fi + fi + fi +fi + +if test "${HAVE_BE_APP}" = "yes" && test "${HAVE_FREETYPE}" = "yes"; then + if test "${with_harfbuzz}" != "no"; then + EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver]) + if test "$HAVE_HARFBUZZ" = "yes"; then + AC_DEFINE(HAVE_HARFBUZZ, 1, [Define to 1 if using HarfBuzz.]) + fi + fi +fi + ### End of font-backend section. AC_SUBST(FREETYPE_CFLAGS) @@ -3592,13 +3719,26 @@ AC_DEFUN fi fi +if test "${HAVE_BE_APP}" = "yes"; then + if test "${with_xpm}" != "no"; then + HAVE_XPM=yes + fi + + if test "${HAVE_XPM}" = "yes"; then + AC_DEFINE(HAVE_XPM, 1, [Define to 1 if you have the Xpm library (-lXpm).]) + HAIKU_OBJ="$HAIKU_OBJ haiku_simx.o" + LIBXPM='$(be_xpmdir)/libXpmBe.a' + AUTODEPEND_PARENTS="$AUTODEPEND_PARENTS be_xpm" + fi +fi + AC_SUBST(LIBXPM) ### Use -ljpeg if available, unless '--with-jpeg=no'. HAVE_JPEG=no LIBJPEG= if test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \ - || test "${HAVE_NS}" = "yes"; then + || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes"; then if test "${with_jpeg}" != "no"; then AC_CACHE_CHECK([for jpeglib 6b or later], [emacs_cv_jpeglib], @@ -3896,7 +4036,7 @@ AC_DEFUN if test "$opsys" = mingw32; then AC_CHECK_HEADER([png.h], [HAVE_PNG=yes]) elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \ - || test "${HAVE_NS}" = "yes"; then + || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes"; then EMACS_CHECK_MODULES([PNG], [libpng >= 1.0.0]) if test $HAVE_PNG = yes; then LIBPNG=$PNG_LIBS @@ -3971,7 +4111,7 @@ AC_DEFUN AC_DEFINE(HAVE_TIFF, 1, [Define to 1 if you have the tiff library (-ltiff).]) fi elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \ - || test "${HAVE_NS}" = "yes"; then + || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes"; then if test "${with_tiff}" != "no"; then AC_CHECK_HEADER(tiffio.h, [tifflibs="-lz -lm" @@ -4000,7 +4140,8 @@ AC_DEFUN AC_DEFINE(HAVE_GIF, 1, [Define to 1 if you have a gif (or ungif) library.]) fi elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \ - || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes"; then + || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \ + || test "${HAVE_BE_APP}" = "yes"; then AC_CHECK_HEADER(gif_lib.h, # EGifPutExtensionLast only exists from version libungif-4.1.0b1. # Earlier versions can crash Emacs, but version 5.0 removes EGifPutExtensionLast. @@ -4417,6 +4558,13 @@ AC_DEFUN [AC_MSG_ERROR([Non-ELF systems are not supported on this platform.])]);; esac +if test "$with_unexec" = yes && test "$opsys" = "haiku"; then + dnl A serious attempt was actually made to port unexec to Haiku. + dnl Something in libstdc++ seems to prevent it from working. + AC_MSG_ERROR([Haiku is not supported by the legacy unexec dumper. +Please use the portable dumper instead.]) +fi + # Dump loading AC_CHECK_FUNCS([posix_madvise]) @@ -4753,7 +4901,7 @@ AC_DEFUN LIBS="$OLDLIBS"]) if test "${emacs_cv_links_glib}" = "yes"; then AC_DEFINE(HAVE_GLIB, 1, [Define to 1 if GLib is linked in.]) - if test "$HAVE_NS" = no;then + if test "$HAVE_NS" = no ; then XGSELOBJ=xgselect.o fi fi @@ -5008,7 +5156,7 @@ AC_DEFUN dnl to read the input and send it to the true Emacs process dnl through a pipe. case $opsys in - darwin | gnu-linux | gnu-kfreebsd ) + darwin | gnu-linux | gnu-kfreebsd) AC_DEFINE(INTERRUPT_INPUT, 1, [Define to read input using SIGIO.]) ;; esac @@ -5104,6 +5252,14 @@ AC_DEFUN AC_DEFINE(PTY_OPEN, [fd = open (pty_name, O_RDWR | O_NONBLOCK)]) AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptsname (int), *ptyname; int grantpt_result; sigset_t blocked; sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 0); grantpt_result = grantpt (fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1) fatal("could not grant slave pty"); if (unlockpt(fd) == -1) fatal("could not unlock slave pty"); if (!(ptyname = ptsname(fd))) fatal ("could not enable slave pty"); snprintf (pty_name, PTY_NAME_SIZE, "%s", ptyname); }]) ;; + + haiku*) + AC_DEFINE(FIRST_PTY_LETTER, ['s']) + AC_DEFINE(PTY_NAME_SPRINTF, []) + dnl on Haiku pty names aren't distinctive, thus the use of posix_openpt + AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_NONBLOCK)]) + AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptyname; int grantpt_result; sigset_t blocked; sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 0); grantpt_result = grantpt (fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1) fatal("could not grant slave pty"); if (unlockpt(fd) == -1) fatal("could not unlock slave pty"); if (!(ptyname = ptsname(fd))) fatal ("could not enable slave pty"); snprintf (pty_name, PTY_NAME_SIZE, "%s", ptyname); }]) + ;; esac @@ -5325,8 +5481,25 @@ AC_DEFUN AC_DEFINE(USG, []) AC_DEFINE(USG5_4, []) ;; + + haiku) + AC_DEFINE(HAIKU, [], [Define if the system is Haiku.]) + ;; esac +AC_SYS_POSIX_TERMIOS +if test $ac_cv_sys_posix_termios = yes; then + AC_CHECK_SIZEOF([speed_t], [], [#include ]) + dnl on Haiku, and possibly other platforms, speed_t is defined to + dnl unsigned char, even when speeds greater than 200 baud are + dnl defined. + + if test ${ac_cv_sizeof_speed_t} -lt 2; then + AC_DEFINE([HAVE_TINY_SPEED_T], [1], + [Define to 1 if speed_t has some sort of nonsensically tiny size.]) + fi +fi + AC_CACHE_CHECK([for usable FIONREAD], [emacs_cv_usable_FIONREAD], [case $opsys in aix4-2 | nacl) @@ -5369,6 +5542,22 @@ AC_DEFUN AC_DEFINE([USABLE_SIGIO], [1], [Define to 1 if SIGIO is usable.]) fi fi + + if test $emacs_cv_usable_SIGIO = no; then + AC_CACHE_CHECK([for usable SIGPOLL], [emacs_cv_usable_SIGPOLL], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include + #include + ]], + [[int foo = SIGPOLL | F_SETFL;]])], + [emacs_cv_usable_SIGPOLL=yes], + [emacs_cv_usable_SIGPOLL=no])], + [emacs_cv_usable_SIGPOLL=yes], + [emacs_cv_usable_SIGPOLL=no]) + if test $emacs_cv_usable_SIGPOLL = yes; then + AC_DEFINE([USABLE_SIGPOLL], [1], [Define to 1 if SIGPOLL is usable but SIGIO is not.]) + fi + fi fi case $opsys in @@ -5481,6 +5670,14 @@ AC_DEFUN FONT_OBJ="$FONT_OBJ ftfont.o" fi fi + +if test "${HAVE_BE_APP}" = "yes" ; then + if test "${HAVE_FREETYPE}" = "yes"; then + FONT_OBJ="$FONT_OBJ ftfont.o ftbefont.o" + HAIKU_CXX_OBJ="$HAIKU_CXX_OBJ haiku_freetype.o" + fi +fi + if test "${HAVE_HARFBUZZ}" = "yes" ; then FONT_OBJ="$FONT_OBJ hbfont.o" fi @@ -5868,7 +6065,7 @@ AC_DEFUN #### Please respect alphabetical ordering when making additions. optsep= emacs_config_features= -for opt in ACL CAIRO DBUS FREETYPE GCONF GIF GLIB GMP GNUTLS GPM GSETTINGS \ +for opt in ACL BE_APP CAIRO DBUS FREETYPE GCONF GIF GLIB GMP GNUTLS GPM GSETTINGS \ HARFBUZZ IMAGEMAGICK JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 \ M17N_FLT MODULES NATIVE_COMP NOTIFY NS OLDXMENU PDUMPER PNG RSVG SECCOMP \ SOUND THREADS TIFF \ @@ -6012,7 +6209,7 @@ AC_DEFUN AC_CONFIG_FILES([$srcdir/doc/man/emacs.1]) m4_define([subdir_makefiles], - [lib/Makefile lib-src/Makefile oldXMenu/Makefile doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile doc/lispref/Makefile src/Makefile lwlib/Makefile lisp/Makefile leim/Makefile nextstep/Makefile nt/Makefile]) + [lib/Makefile lib-src/Makefile oldXMenu/Makefile doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile doc/lispref/Makefile src/Makefile lwlib/Makefile lisp/Makefile leim/Makefile nextstep/Makefile nt/Makefile be_xpm/Makefile]) SUBDIR_MAKEFILES="subdir_makefiles" AC_CONFIG_FILES(subdir_makefiles) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index ca438c10ce..8ae810101c 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2696,8 +2696,9 @@ Defining Faces @item type The kind of window system the terminal uses---either @code{graphic} (any graphics-capable display), @code{x}, @code{pc} (for the MS-DOS -console), @code{w32} (for MS Windows 9X/NT/2K/XP), or @code{tty} (a -non-graphics-capable display). @xref{Window Systems, window-system}. +console), @code{w32} (for MS Windows 9X/NT/2K/XP), @code{haiku} (for +Haiku), or @code{tty} (a non-graphics-capable display). +@xref{Window Systems, window-system}. @item class What kinds of colors the terminal supports---either @code{color}, @@ -8021,6 +8022,8 @@ Window Systems GNUstep and macOS). @item pc Emacs is displaying the frame using MS-DOS direct screen writes. +@item haiku +Emacs is displaying the frame using the Application Kit on Haiku. @item nil Emacs is displaying the frame on a character-based terminal. @end table diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 477c105a95..169fcdc749 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -213,7 +213,8 @@ Multiple Terminals @item The kind of display associated with the terminal. This is the symbol returned by the function @code{terminal-live-p} (i.e., @code{x}, -@code{t}, @code{w32}, @code{ns}, or @code{pc}). @xref{Frames}. +@code{t}, @code{w32}, @code{ns}, @code{pc}, or @code{haiku}). +@xref{Frames}. @item A list of terminal parameters. @xref{Terminal Parameters}. @@ -669,7 +670,7 @@ Frame Layout @itemize @w{} @item (1) non-toolkit and terminal frames -@item (2) Lucid, Motif and MS-Windows frames +@item (2) Lucid, Motif, MS-Windows, and Haiku frames @item (3) GTK+ and NS frames @end itemize @@ -1745,6 +1746,9 @@ Size Parameters both will be displayed if the mouse pointer is moved to the top of the screen. +Full-screen is not supported on Haiku builds, owing to a limitation of +Haiku's window system. + @vindex fullscreen-restore@r{, a frame parameter} @item fullscreen-restore This parameter specifies the desired fullscreen state of the frame @@ -2173,7 +2177,8 @@ Management Parameters @code{mouse-autoselect-window} (@pxref{Mouse Window Auto-selection}). This may have the unwanted side-effect that a user cannot scroll a non-selected frame with the mouse. Some window managers may not honor -this parameter. +this parameter. On Haiku, it also has the side-effect that the window +will not be able to receive any keyboard input from the user. @vindex undecorated@r{, a frame parameter} @item undecorated @@ -3125,6 +3130,9 @@ Raising and Lowering below all other frames belonging to the same or a higher z-group as @var{frame}. If @var{frame} is a child frame (@pxref{Child Frames}), this lowers @var{frame} below all other child frames of its parent. + +Lowering frames is not supported on Haiku, due to limitations imposed +by the system. @end deffn @defun frame-restack frame1 frame2 &optional above @@ -3145,6 +3153,9 @@ Raising and Lowering @var{frame1} remains unaltered. Some window managers may refuse to restack windows. + +Restacking frames is not supported on Haiku, due to limitations +imposed by the system. @end defun Note that the effect of restacking will only hold as long as neither of @@ -3254,6 +3265,12 @@ Child Frames allowing them to be positioned so they do not obscure the parent frame while still being visible themselves. + On Haiku, child frames are only visible when a parent frame is +visible, owing to a limitation of the Haiku windowing system. Owing +to the same limitation, child frames are only guaranteed to appear +above their top-level parent; that is to say, the top-most frame in +the hierarchy, which does not have a parent frame. + Usually, moving a parent frame moves along all its child frames and their descendants as well, keeping their relative positions unaltered. Note that the hook @code{move-frame-functions} (@pxref{Frame Position}) diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 12ddaf04b6..3adb5c3e06 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -947,6 +947,9 @@ System Environment @item gnu/kfreebsd A GNU (glibc-based) system with a FreeBSD kernel. +@item haiku +The Haiku operating system, a derivative of the Be Operating System. + @item hpux Hewlett-Packard HPUX operating system. diff --git a/etc/MACHINES b/etc/MACHINES index d8d0b86fb4..b827d19f10 100644 --- a/etc/MACHINES +++ b/etc/MACHINES @@ -103,6 +103,22 @@ the list at the end of this file. ./configure CC='gcc -m64' # GCC ./configure CC='cc -m64' # Oracle Developer Studio +** Haiku + + On 32-bit Haiku it is recommended that the newer GCC 8 be used, in + place of the legacy GCC 2 shipped by default. While the older GCC + works, in many cases it generates very slow code leading to degraded + Emacs performance. + + Haiku running non-x86 systems has not been tested. It is + anticipated that Haiku running on big-endian systems will experience + problems when Emacs is built with Haiku windowing support, but there + doesn't seem to be any reliable way to get Haiku running on a + big-endian system at present. + + The earliest release of Haiku that will successfully compile Emacs + is R1/Beta2. For windowing support, R1/Beta3 or later is required. + * Obsolete platforms diff --git a/etc/NEWS b/etc/NEWS index 506eaab0fc..8ce8a7ae30 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -34,6 +34,26 @@ more details. --- ** Support for building with Motif has been removed. +** Emacs has been ported to the Haiku operating system. +The configuration process should automatically detect and build for Haiku. +There is also an optional window-system port to Haiku, which can be enabled +by configuring Emacs with the option '--with-be-app', which will require +the Haiku Application Kit development headers and a C++ compiler to be present +on your system. If Emacs is not built with the option '--with-be-app', the +resulting Emacs will only run in text-mode terminals. + +** FreeType and HarfBuzz support has been ported to the Haiku operating system. +To enable FreeType support, ensure that the FreeType development headers are +present on your system, and configure Emacs with '--with-be-freetype'. If Emacs +is not configured for FreeType, a fallback font driver will be enabled which will +not have HarfBuzz support. + +--- +** Double buffering is now enabled on the Haiku operating system. +Unlike X, there is no compile-time option to enable or disable double-buffering. +If you wish to disable double-buffering, change the frame parameter +`inhibit-double-buffering' instead. + ** The Cairo graphics library is now used by default if present. '--with-cairo' is now the default, if the appropriate development files are found by 'configure'. Note that building with Cairo means using @@ -1956,6 +1976,10 @@ symbol property to the browsing commands. With a new command 'browse-url-with-browser-kind', an URL can explicitly be browsed with either an internal or external browser. +--- +*** Added support for the WebPositive web browser +WebPosisitve is the default browser on Haiku, and is based on WebKit. + --- *** Support for browsing of remote files. If a remote file is taken, a local temporary copy of that file is diff --git a/etc/PROBLEMS b/etc/PROBLEMS index f90418798d..6d33e88c22 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -989,6 +989,15 @@ modern fonts are used, such as Noto Emoji or Ebrima. The solution is to switch to a configuration that uses HarfBuzz as its shaping engine, where these problems don't exist. +** On Haiku, some proportionally-spaced fonts display with artifacting. + +This is a Haiku bug: https://dev.haiku-os.org/ticket/17229, which can +be remedied by using a different font that does not exhibit this +problem, or by compiling Emacs with the FreeType font driver. + +So far, Bitstream Charter and Noto Sans have been known to exhibit +this problem, while Noto Sans Display is known to not do so. + * Internationalization problems ** M-{ does not work on a Spanish PC keyboard. diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in index e6cda73367..7c9f6bbf04 100644 --- a/lib-src/Makefile.in +++ b/lib-src/Makefile.in @@ -27,7 +27,9 @@ EMACSOPT = # ==================== Things 'configure' will edit ==================== CC=@CC@ +CXX=@CXX@ CFLAGS=@CFLAGS@ +CXXFLAGS=@CXXFLAGS@ CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ @@ -130,6 +132,11 @@ MKDIR_P = # ========================== Lists of Files =========================== +## Haiku build-time support +HAVE_BE_APP=@HAVE_BE_APP@ +HAIKU_LIBS=@HAIKU_LIBS@ +HAIKU_CFLAGS=@HAIKU_CFLAGS@ + # emacsclientw.exe for MinGW, empty otherwise CLIENTW = @CLIENTW@ @@ -143,7 +150,11 @@ UTILITIES = $(if $(with_mailutils), , movemail${EXEEXT}) \ $(and $(use_gamedir), update-game-score${EXEEXT}) +ifneq (,$(HAVE_BE_APP)) +DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT} be-resources +else DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT} +endif # Like UTILITIES, but they're not system-dependent, and should not be # deleted by the distclean target. @@ -230,6 +241,10 @@ WINDRES = ## Some systems define this to request special libraries. LIBS_SYSTEM = @LIBS_SYSTEM@ +# Flags that could be in WARN_CFLAGS, but are invalid for C++. +NON_CXX_CFLAGS = -Wmissing-prototypes -Wnested-externs -Wold-style-definition \ + -Wstrict-prototypes -Wno-override-init + BASE_CFLAGS = $(C_SWITCH_SYSTEM) $(C_SWITCH_MACHINE) \ $(WARN_CFLAGS) $(WERROR_CFLAGS) \ -I. -I../src -I../lib \ @@ -238,6 +253,9 @@ BASE_CFLAGS = ALL_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS} CPP_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${CPPFLAGS} ${CFLAGS} +ALL_CXXFLAGS = $(filter-out ${NON_CXX_CFLAGS},${BASE_CFLAGS}) \ + ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS} ${CXXFLAGS} ${HAIKU_CFLAGS} + # Configuration files for .o files to depend on. config_h = ../src/config.h $(srcdir)/../src/conf_post.h @@ -407,6 +425,9 @@ emacsclientw${EXEEXT}: $(LOADLIBES) \ $(LIB_WSOCK32) $(LIB_EACCESS) $(LIBS_ECLIENT) -o $@ +be-resources: ${srcdir}/be_resources.cc ${config_h} + $(AM_V_CXX)$(CXX) ${ALL_CXXFLAGS} ${HAIKU_LIBS} $< -o $@ + NTINC = ${srcdir}/../nt/inc NTDEPS = $(NTINC)/ms-w32.h $(NTINC)/sys/stat.h $(NTINC)/inttypes.h \ $(NTINC)/stdint.h $(NTINC)/pwd.h $(NTINC)/sys/time.h $(NTINC)/stdbool.h \ diff --git a/lib-src/be_resources.cc b/lib-src/be_resources.cc new file mode 100644 index 0000000000..f8cde834cd --- /dev/null +++ b/lib-src/be_resources.cc @@ -0,0 +1,137 @@ +/* Haiku window system support + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +static void +be_perror (status_t code, char *arg) +{ + if (code != B_OK) + { + switch (code) + { + case B_BAD_VALUE: + fprintf (stderr, "%s: Bad value\n", arg); + break; + case B_ENTRY_NOT_FOUND: + fprintf (stderr, "%s: Not found\n", arg); + break; + case B_PERMISSION_DENIED: + fprintf (stderr, "%s: Permission denied\n", arg); + break; + case B_NO_MEMORY: + fprintf (stderr, "%s: No memory\n", arg); + break; + case B_LINK_LIMIT: + fprintf (stderr, "%s: Link limit reached\n", arg); + break; + case B_BUSY: + fprintf (stderr, "%s: Busy\n", arg); + break; + case B_NO_MORE_FDS: + fprintf (stderr, "%s: No more file descriptors\n", arg); + break; + case B_FILE_ERROR: + fprintf (stderr, "%s: File error\n", arg); + break; + default: + fprintf (stderr, "%s: Unknown error (%d)\n", arg, code); + } + } + else + { + abort (); + } +} + +int +main (int argc, char **argv) +{ + BApplication app ("application/x-vnd.GNU-emacs-resource-helper"); + BFile file; + BBitmap *icon; + BAppFileInfo info; + status_t code; + struct version_info vinfo; + char *v = strdup (PACKAGE_VERSION); + + if (argc != 3) + { + printf ("be-resources ICON FILE: make FILE appropriate for Emacs.\n"); + return EXIT_FAILURE; + } + + code = file.SetTo (argv[2], B_READ_WRITE); + if (code != B_OK) + { + be_perror (code, argv[2]); + return EXIT_FAILURE; + } + code = info.SetTo (&file); + if (code != B_OK) + { + be_perror (code, argv[2]); + return EXIT_FAILURE; + } + + icon = BTranslationUtils::GetBitmapFile (argv[1], NULL); + + if (!icon) + { + be_perror (B_ERROR, argv[1]); + return EXIT_FAILURE; + } + + info.SetIcon (icon, B_MINI_ICON); + info.SetIcon (icon, B_LARGE_ICON); + info.SetSignature ("application/x-vnd.GNU-emacs"); + + v = strtok (v, "."); + vinfo.major = atoi (v); + + v = strtok (NULL, "."); + vinfo.middle = atoi (v); + + v = strtok (NULL, "."); + vinfo.minor = v ? atoi (v) : 0; + + vinfo.variety = 0; + vinfo.internal = 0; + + strncpy ((char *) &vinfo.short_info, PACKAGE_VERSION, + sizeof vinfo.short_info - 1); + strncpy ((char *) &vinfo.long_info, PACKAGE_STRING, + sizeof vinfo.long_info - 1); + + info.SetVersionInfo (&vinfo, B_APP_VERSION_KIND); + + return EXIT_SUCCESS; +} diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 018e81e422..ca81ac2b08 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -601,6 +601,8 @@ decode_options (int argc, char **argv) alt_display = "ns"; #elif defined (HAVE_NTGUI) alt_display = "w32"; +#elif defined (HAVE_HAIKU) + alt_display = "be"; #endif display = egetenv ("DISPLAY"); diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 7eae2e416b..e2c5ee35cf 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -2176,7 +2176,7 @@ custom-magic-reset ;;; The `custom' Widget. (defface custom-button - '((((type x w32 ns) (class color)) ; Like default mode line + '((((type x w32 ns haiku) (class color)) ; Like default mode line :box (:line-width 2 :style released-button) :background "lightgrey" :foreground "black")) "Face for custom buffer buttons if `custom-raised-buttons' is non-nil." @@ -2184,7 +2184,7 @@ custom-button :group 'custom-faces) (defface custom-button-mouse - '((((type x w32 ns) (class color)) + '((((type x w32 ns haiku) (class color)) :box (:line-width 2 :style released-button) :background "grey90" :foreground "black") (t @@ -2209,7 +2209,7 @@ custom-button-unraised (if custom-raised-buttons 'custom-button-mouse 'highlight)) (defface custom-button-pressed - '((((type x w32 ns) (class color)) + '((((type x w32 ns haiku) (class color)) :box (:line-width 2 :style pressed-button) :background "lightgrey" :foreground "black") (t :inverse-video t)) diff --git a/lisp/faces.el b/lisp/faces.el index a5aef757b1..ac7c544c04 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -1171,7 +1171,7 @@ face-valid-attribute-values (:height 'integerp) (:stipple - (and (memq (window-system frame) '(x ns)) ; No stipple on w32 + (and (memq (window-system frame) '(x ns)) ; No stipple on w32 or haiku (mapcar #'list (apply #'nconc (mapcar (lambda (dir) @@ -2819,7 +2819,7 @@ tool-bar '((default :box (:line-width 1 :style released-button) :foreground "black") - (((type x w32 ns) (class color)) + (((type x w32 ns haiku) (class color)) :background "grey75") (((type x) (class mono)) :background "grey")) diff --git a/lisp/frame.el b/lisp/frame.el index 60234fc2ae..de24d35eb8 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1633,6 +1633,7 @@ frame-current-scroll-bars (declare-function x-frame-geometry "xfns.c" (&optional frame)) (declare-function w32-frame-geometry "w32fns.c" (&optional frame)) (declare-function ns-frame-geometry "nsfns.m" (&optional frame)) +(declare-function haiku-frame-geometry "haikufns.c" (&optional frame)) (defun frame-geometry (&optional frame) "Return geometric attributes of FRAME. @@ -1682,6 +1683,8 @@ frame-geometry (w32-frame-geometry frame)) ((eq frame-type 'ns) (ns-frame-geometry frame)) + ((eq frame-type 'haiku) + (haiku-frame-geometry frame)) (t (list '(outer-position 0 . 0) @@ -1806,6 +1809,7 @@ frame--size-history (declare-function x-frame-edges "xfns.c" (&optional frame type)) (declare-function w32-frame-edges "w32fns.c" (&optional frame type)) (declare-function ns-frame-edges "nsfns.m" (&optional frame type)) +(declare-function haiku-frame-edges "haikufns.c" (&optional frame type)) (defun frame-edges (&optional frame type) "Return coordinates of FRAME's edges. @@ -1829,6 +1833,8 @@ frame-edges (w32-frame-edges frame type)) ((eq frame-type 'ns) (ns-frame-edges frame type)) + ((eq frame-type 'haiku) + (haiku-frame-edges frame type)) (t (list 0 0 (frame-width frame) (frame-height frame)))))) @@ -1855,6 +1861,7 @@ mouse-absolute-pixel-position (declare-function ns-set-mouse-absolute-pixel-position "nsfns.m" (x y)) (declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y)) (declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y)) +(declare-function haiku-set-mouse-absolute-pixel-position "haikufns.c" (x y)) (defun set-mouse-absolute-pixel-position (x y) "Move mouse pointer to absolute pixel position (X, Y). @@ -1867,7 +1874,9 @@ set-mouse-absolute-pixel-position ((eq frame-type 'x) (x-set-mouse-absolute-pixel-position x y)) ((eq frame-type 'w32) - (w32-set-mouse-absolute-pixel-position x y))))) + (w32-set-mouse-absolute-pixel-position x y)) + ((eq frame-type 'haiku) + (haiku-set-mouse-absolute-pixel-position x y))))) (defun frame-monitor-attributes (&optional frame) "Return the attributes of the physical monitor dominating FRAME. @@ -2060,8 +2069,8 @@ display-mouse-p ((eq frame-type 'w32) (with-no-warnings (> w32-num-mouse-buttons 0))) - ((memq frame-type '(x ns)) - t) ;; We assume X and NeXTstep *always* have a pointing device + ((memq frame-type '(x ns haiku)) + t) ;; We assume X, NeXTstep and Haiku *always* have a pointing device (t (or (and (featurep 'xt-mouse) xterm-mouse-mode) @@ -2086,7 +2095,7 @@ display-graphic-p that use a window system such as X, and false for text-only terminals. DISPLAY can be a display name, a frame, or nil (meaning the selected frame's display)." - (not (null (memq (framep-on-display display) '(x w32 ns))))) + (not (null (memq (framep-on-display display) '(x w32 ns haiku))))) (defun display-images-p (&optional display) "Return non-nil if DISPLAY can display images. @@ -2157,7 +2166,7 @@ display-pixel-height `display-monitor-attributes-list'." (let ((frame-type (framep-on-display display))) (cond - ((memq frame-type '(x w32 ns)) + ((memq frame-type '(x w32 ns haiku)) (x-display-pixel-height display)) (t (frame-height (if (framep display) display (selected-frame))))))) @@ -2177,7 +2186,7 @@ display-pixel-width `display-monitor-attributes-list'." (let ((frame-type (framep-on-display display))) (cond - ((memq frame-type '(x w32 ns)) + ((memq frame-type '(x w32 ns haiku)) (x-display-pixel-width display)) (t (frame-width (if (framep display) display (selected-frame))))))) @@ -2215,7 +2224,7 @@ display-mm-height refers to the height in millimeters for all physical monitors associated with DISPLAY. To get information for each physical monitor, use `display-monitor-attributes-list'." - (and (memq (framep-on-display display) '(x w32 ns)) + (and (memq (framep-on-display display) '(x w32 ns haiku)) (or (cddr (assoc (or display (frame-parameter nil 'display)) display-mm-dimensions-alist)) (cddr (assoc t display-mm-dimensions-alist)) @@ -2236,7 +2245,7 @@ display-mm-width refers to the width in millimeters for all physical monitors associated with DISPLAY. To get information for each physical monitor, use `display-monitor-attributes-list'." - (and (memq (framep-on-display display) '(x w32 ns)) + (and (memq (framep-on-display display) '(x w32 ns haiku)) (or (cadr (assoc (or display (frame-parameter nil 'display)) display-mm-dimensions-alist)) (cadr (assoc t display-mm-dimensions-alist)) @@ -2254,7 +2263,7 @@ display-backing-store If DISPLAY is omitted or nil, it defaults to the selected frame's display." (let ((frame-type (framep-on-display display))) (cond - ((memq frame-type '(x w32 ns)) + ((memq frame-type '(x w32 ns haiku)) (x-display-backing-store display)) (t 'not-useful)))) @@ -2280,7 +2289,7 @@ display-planes If DISPLAY is omitted or nil, it defaults to the selected frame's display." (let ((frame-type (framep-on-display display))) (cond - ((memq frame-type '(x w32 ns)) + ((memq frame-type '(x w32 ns haiku)) (x-display-planes display)) ((eq frame-type 'pc) 4) @@ -2295,7 +2304,7 @@ display-color-cells If DISPLAY is omitted or nil, it defaults to the selected frame's display." (let ((frame-type (framep-on-display display))) (cond - ((memq frame-type '(x w32 ns)) + ((memq frame-type '(x w32 ns haiku)) (x-display-color-cells display)) ((eq frame-type 'pc) 16) @@ -2314,6 +2323,8 @@ display-visual-class (cond ((memq frame-type '(x w32 ns)) (x-display-visual-class display)) + ((eq frame-type 'haiku) + 'direct-color) ((and (memq frame-type '(pc t)) (tty-display-color-p display)) 'static-color) diff --git a/lisp/loadup.el b/lisp/loadup.el index 158c02ecea..deec90662a 100644 --- a/lisp/loadup.el +++ b/lisp/loadup.el @@ -303,6 +303,13 @@ (load "term/common-win") (load "term/x-win"))) +(if (featurep 'haiku) + (progn + (load "term/common-win") + (load "term/haiku-win") + (load "international/mule-util") + (load "international/ucs-normalize"))) + (if (or (eq system-type 'windows-nt) (featurep 'w32)) (progn @@ -546,6 +553,7 @@ (delete-file output))))) ;; Recompute NAME now, so that it isn't set when we dump. (if (not (or (eq system-type 'ms-dos) + (eq system-type 'haiku) ;; BFS doesn't support hard links ;; Don't bother adding another name if we're just ;; building bootstrap-emacs. (member dump-mode '("pbootstrap" "bootstrap")))) diff --git a/lisp/mwheel.el b/lisp/mwheel.el index def7758774..7c34931055 100644 --- a/lisp/mwheel.el +++ b/lisp/mwheel.el @@ -55,7 +55,8 @@ mouse-wheel-change-button (mouse-wheel-mode 1))) (defcustom mouse-wheel-down-event - (if (or (featurep 'w32-win) (featurep 'ns-win)) + (if (or (featurep 'w32-win) (featurep 'ns-win) + (featurep 'haiku-win)) 'wheel-up 'mouse-4) "Event used for scrolling down." @@ -64,7 +65,8 @@ mouse-wheel-down-event :set 'mouse-wheel-change-button) (defcustom mouse-wheel-up-event - (if (or (featurep 'w32-win) (featurep 'ns-win)) + (if (or (featurep 'w32-win) (featurep 'ns-win) + (featurep 'haiku-win)) 'wheel-down 'mouse-5) "Event used for scrolling up." diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index 73b8c439f2..0e0579ab28 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -39,6 +39,7 @@ ;; browse-url-chrome Chrome 47.0.2526.111 ;; browse-url-chromium Chromium 3.0 ;; browse-url-epiphany Epiphany Don't know +;; browse-url-webpositive WebPositive 1.2-alpha (Haiku R1/beta3) ;; browse-url-w3 w3 0 ;; browse-url-text-* Any text browser 0 ;; browse-url-generic arbitrary @@ -156,6 +157,7 @@ browse-url--browser-defcustom-type (function-item :tag "Google Chrome" :value browse-url-chrome) (function-item :tag "Chromium" :value browse-url-chromium) (function-item :tag "Epiphany" :value browse-url-epiphany) + (function-item :tag "WebPositive" :value browse-url-webpositive) (function-item :tag "Text browser in an xterm window" :value browse-url-text-xterm) (function-item :tag "Text browser in an Emacs window" @@ -366,6 +368,11 @@ browse-url-epiphany-startup-arguments `browse-url' is loaded." :type '(repeat (string :tag "Argument"))) +(defcustom browse-url-webpositive-program "WebPositive" + "The name by which to invoke WebPositive." + :type 'string + :version "28.1") + ;; GNOME means of invoking either Mozilla or Netscape. (defvar browse-url-gnome-moz-program "gnome-moz-remote") @@ -1053,6 +1060,7 @@ browse-url-default-browser ((executable-find browse-url-kde-program) 'browse-url-kde) ;;; ((executable-find browse-url-netscape-program) 'browse-url-netscape) ((executable-find browse-url-chrome-program) 'browse-url-chrome) + ((executable-find browse-url-webpositive-program) 'browse-url-webpositive) ((executable-find browse-url-xterm-program) 'browse-url-text-xterm) ((locate-library "w3") 'browse-url-w3) (t @@ -1379,6 +1387,18 @@ browse-url-epiphany-sentinel (defvar url-handler-regexp) +;;;###autoload +(defun browse-url-webpositive (url &optional _new-window) + "Ask the WebPositive WWW browser to load URL. +Default to the URL around or before point. +The optional argument NEW-WINDOW is not used." + (interactive (browse-url-interactive-arg "URL: ")) + (setq url (browse-url-encode-url url)) + (let* ((process-environment (browse-url-process-environment))) + (start-process (concat "WebPositive " url) nil "WebPositive" url))) + +(function-put 'browse-url-webpositive 'browse-url-browser-kind 'external) + ;;;###autoload (defun browse-url-emacs (url &optional same-window) "Ask Emacs to load URL into a buffer and show it in another window. diff --git a/lisp/term/haiku-win.el b/lisp/term/haiku-win.el new file mode 100644 index 0000000000..7d200a0a63 --- /dev/null +++ b/lisp/term/haiku-win.el @@ -0,0 +1,97 @@ +;;; haiku-win.el --- set up windowing on Haiku -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +;;; Commentary: + +;; Support for using Haiku's BeOS derived windowing system. + +;;; Code: + +(eval-when-compile (require 'cl-lib)) +(unless (featurep 'haiku) + (error "%s: Loading haiku-win without having Haiku" + invocation-name)) + +;; Documentation-purposes only: actually loaded in loadup.el. +(require 'frame) +(require 'mouse) +(require 'scroll-bar) +(require 'menu-bar) +(require 'fontset) +(require 'dnd) + +(add-to-list 'display-format-alist '(".*" . haiku-win)) + +;;;; Command line argument handling. + +(defvar x-invocation-args) +(defvar x-command-line-resources) + +(defvar haiku-initialized) + +(declare-function x-open-connection "haikufns.c") +(declare-function x-handle-args "common-win") +(declare-function haiku-selection-data "haikuselect.c") +(declare-function haiku-selection-put "haikuselect.c") + +(cl-defmethod window-system-initialization (&context (window-system haiku) + &optional display) + "Set up the window system. WINDOW-SYSTEM must be HAIKU. +DISPLAY may be set to the name of a display that will be initialized." + (cl-assert (not haiku-initialized)) + + (create-default-fontset) + (x-open-connection (or display "be") x-command-line-resources t) + (setq haiku-initialized t)) + +(cl-defmethod frame-creation-function (params &context (window-system haiku)) + (x-create-frame-with-faces params)) + +(cl-defmethod handle-args-function (args &context (window-system haiku)) + (x-handle-args args)) + +(defun haiku--selection-type-to-mime (type) + "Convert symbolic selection type TYPE to its MIME equivalent. +If TYPE is nil, return \"text/plain\"." + (cond + ((memq type '(TEXT COMPOUND_TEXT STRING UTF8_STRING)) "text/plain") + ((stringp type) type) + (t "text/plain"))) + +(cl-defmethod gui-backend-get-selection (type data-type + &context (window-system haiku)) + (haiku-selection-data type (haiku--selection-type-to-mime data-type))) + +(cl-defmethod gui-backend-set-selection (type value + &context (window-system haiku)) + (haiku-selection-put type "text/plain" value)) + +(cl-defmethod gui-backend-selection-exists-p (selection + &context (window-system haiku)) + (haiku-selection-data selection "text/plain")) + +(cl-defmethod gui-backend-selection-owner-p (_ + &context (window-system haiku)) + t) + + +(provide 'haiku-win) +(provide 'term/haiku-win) + +;;; haiku-win.el ends here diff --git a/lisp/version.el b/lisp/version.el index 3a3093fdd4..5d0a1ae37d 100644 --- a/lisp/version.el +++ b/lisp/version.el @@ -53,6 +53,8 @@ gtk-version-string (defvar ns-version-string) (defvar cairo-version-string) +(declare-function haiku-get-version-string "haikufns.c") + (defun emacs-version (&optional here) "Return string describing the version of Emacs that is running. If optional argument HERE is non-nil, insert string at point. @@ -71,6 +73,8 @@ emacs-version ((featurep 'x-toolkit) ", X toolkit") ((featurep 'ns) (format ", NS %s" ns-version-string)) + ((featurep 'haiku) + (format ", Haiku %s" (haiku-get-version-string))) (t "")) (if (featurep 'cairo) (format ", cairo version %s" cairo-version-string) diff --git a/src/Makefile.in b/src/Makefile.in index 732cd8f099..253732e615 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -34,6 +34,7 @@ top_builddir = abs_top_srcdir=@abs_top_srcdir@ VPATH = $(srcdir) CC = @CC@ +CXX = @CXX@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ @@ -50,6 +51,7 @@ lib = libsrc = ../lib-src etc = ../etc oldXMenudir = ../oldXMenu +be_xpmdir = ../be_xpm lwlibdir = ../lwlib # Configuration files for .o files to depend on. @@ -339,10 +341,23 @@ BUILD_DETAILS = UNEXEC_OBJ = @UNEXEC_OBJ@ +HAIKU_OBJ = @HAIKU_OBJ@ +HAIKU_CXX_OBJ = @HAIKU_CXX_OBJ@ +HAIKU_LIBS = @HAIKU_LIBS@ +HAIKU_CFLAGS = @HAIKU_CFLAGS@ + DUMPING=@DUMPING@ CHECK_STRUCTS = @CHECK_STRUCTS@ HAVE_PDUMPER = @HAVE_PDUMPER@ +HAVE_BE_APP = @HAVE_BE_APP@ + +ifeq ($(HAVE_BE_APP),yes) +HAIKU_LIBXPM = @LIBXPM@ +else +HAIKU_LIBXPM = +endif + ## ARM Macs require that all code have a valid signature. Since pdump ## invalidates the signature, we must re-sign to fix it. DO_CODESIGN=$(patsubst aarch64-apple-darwin%,yes,@configuration@) @@ -360,6 +375,9 @@ pdmp := # Flags that might be in WARN_CFLAGS but are not valid for Objective C. NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd +# Ditto, but for C++. +NON_CXX_CFLAGS = -Wmissing-prototypes -Wnested-externs -Wold-style-definition \ + -Wstrict-prototypes -Wno-override-init # -Demacs makes some files produce the correct version for use in Emacs. # MYCPPFLAGS is for by-hand Emacs-specific overrides, e.g., @@ -375,17 +393,21 @@ EMACS_CFLAGS= $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \ $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ - $(WERROR_CFLAGS) + $(WERROR_CFLAGS) $(HAIKU_CFLAGS) ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ $(GNU_OBJC_CFLAGS) +ALL_CXX_CFLAGS = $(EMACS_CFLAGS) \ + $(filter-out $(NON_CXX_CFLAGS),$(WARN_CFLAGS)) $(CXXFLAGS) -.SUFFIXES: .m +.SUFFIXES: .m .cc .c.o: $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $< .m.o: $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $< +.cc.o: + $(AM_V_CXX)$(CXX) -c $(CPPFLAGS) $(ALL_CXX_CFLAGS) $(PROFILING_CFLAGS) $< ## lastfile must follow all files whose initialized data areas should ## be dumped as pure by dump-emacs. @@ -407,8 +429,10 @@ base_obj = thread.o systhread.o \ $(if $(HYBRID_MALLOC),sheap.o) \ $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ - $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) -obj = $(base_obj) $(NS_OBJC_OBJ) + $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \ + $(HAIKU_OBJ) +doc_obj = $(base_obj) $(NS_OBJC_OBJ) +obj = $(doc_obj) $(HAIKU_CXX_OBJ) ## Object files used on some machine or other. ## These go in the DOC file on all machines in case they are needed. @@ -422,7 +446,8 @@ SOME_MACHINE_OBJECTS = w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \ w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ - xsettings.o xgselect.o termcap.o hbfont.o + xsettings.o xgselect.o termcap.o hbfont.o \ + haikuterm.o haikufns.o haikumenu.o haikufont.o ## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty. GMALLOC_OBJ=@GMALLOC_OBJ@ @@ -448,7 +473,12 @@ FIRSTFILE_OBJ= ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) # Must be first, before dep inclusion! +ifneq ($(HAVE_BE_APP),yes) all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) +else +all: Emacs Emacs.pdmp $(OTHER_FILES) +endif + .PHONY: all dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \ @@ -517,7 +547,7 @@ LIBES = $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ - $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) + $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(HAIKU_LIBS) ## FORCE it so that admin/unidata can decide whether this file is ## up-to-date. Although since charprop depends on bootstrap-emacs, @@ -565,6 +595,18 @@ emacs$(EXEEXT): rm -f $@ && cp -f temacs$(EXEEXT) $@ endif +## On Haiku, also produce a binary named Emacs with the appropriate +## icon set. + +ifeq ($(HAVE_BE_APP),yes) +Emacs: emacs$(EXEEXT) + cp -f emacs$(EXEEXT) $@ + $(AM_V_GEN) $(libsrc)/be-resources \ + $(etc)/images/icons/hicolor/32x32/apps/emacs.png $@ +Emacs.pdmp: $(pdmp) + $(AM_V_GEN) cp -f $(pdmp) $@ +endif + ifeq ($(DUMPING),pdumper) $(pdmp): emacs$(EXEEXT) LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \ @@ -583,11 +625,11 @@ $(pdmp): ## for the first time, this prevents any variation between configurations ## in the contents of the DOC file. ## -$(etc)/DOC: lisp.mk $(libsrc)/make-docfile$(EXEEXT) $(obj) $(lisp) +$(etc)/DOC: lisp.mk $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) $(lisp) $(AM_V_GEN)$(MKDIR_P) $(etc) $(AM_V_at)rm -f $(etc)/DOC $(AM_V_at)$(libsrc)/make-docfile -d $(srcdir) \ - $(SOME_MACHINE_OBJECTS) $(obj) > $(etc)/DOC + $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC $(AM_V_at)$(libsrc)/make-docfile -a $(etc)/DOC -d $(lispsource) \ $(shortlisp) @@ -605,7 +647,7 @@ buildobj.h: GLOBAL_SOURCES = $(base_obj:.o=.c) $(NS_OBJC_OBJ:.o=.m) gl-stamp: $(libsrc)/make-docfile$(EXEEXT) $(GLOBAL_SOURCES) - $(AM_V_GLOBALS)$(libsrc)/make-docfile -d $(srcdir) -g $(obj) > globals.tmp + $(AM_V_GLOBALS)$(libsrc)/make-docfile -d $(srcdir) -g $(doc_obj) > globals.tmp $(AM_V_at)$(top_srcdir)/build-aux/move-if-change globals.tmp globals.h $(AM_V_at)echo timestamp > $@ @@ -629,10 +671,16 @@ $(LIBEGNU_ARCHIVE): ## This goes on to affect various things, and the emacs binary fails ## to start if Vinstallation_directory has the wrong value. temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ - $(charsets) $(charscript) $(MAKE_PDUMPER_FINGERPRINT) - $(AM_V_CCLD)$(CC) -o $@.tmp \ + $(charsets) $(charscript) $(MAKE_PDUMPER_FINGERPRINT) $(HAIKU_LIBXPM) +ifeq ($(HAVE_BE_APP),yes) + $(AM_V_CCLD)$(CXX) -o $@.tmp \ $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ + $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) -lstdc++ +else + $(AM_V_CCLD)$(CC) -o $@.tmp \ + $(ALL_CFLAGS) $(CXXFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) +endif ifeq ($(HAVE_PDUMPER),yes) $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@.tmp ifeq ($(DO_CODESIGN),yes) @@ -653,6 +701,12 @@ $(lwlibdir)/liblw.a: $(MAKE) -C $(dir $@) $(notdir $@) $(oldXMenudir)/libXMenu11.a: FORCE $(MAKE) -C $(dir $@) $(notdir $@) + +# Similarly, the following rule is only used if Xpm is to be used on Haiku, +# but there's also no harm in keeping it defined +$(be_xpmdir)/libXpmBe.a: FORCE + $(MAKE) -C $(dir $@) $(notdir $@) + FORCE: .PHONY: FORCE diff --git a/src/alloc.c b/src/alloc.c index 4ea337ddba..2c2434feaa 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -6141,6 +6141,10 @@ garbage_collect (void) xg_mark_data (); #endif +#ifdef HAVE_HAIKU + mark_haiku_display (); +#endif + #ifdef HAVE_WINDOW_SYSTEM mark_fringe_data (); #endif diff --git a/src/dispextern.h b/src/dispextern.h index 33fcaa4c07..8794721df1 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -134,6 +134,13 @@ #define FACE_COLOR_TO_PIXEL(face_color, frame) (FRAME_NS_P (frame) \ #define FACE_COLOR_TO_PIXEL(face_color, frame) face_color #endif +#ifdef HAVE_HAIKU +#include "haikugui.h" +typedef struct haiku_display_info Display_Info; +typedef Emacs_Pixmap Emacs_Pix_Container; +typedef Emacs_Pixmap Emacs_Pix_Context; +#endif + #ifdef HAVE_WINDOW_SYSTEM # include # include "fontset.h" @@ -3009,7 +3016,7 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo) #ifdef HAVE_WINDOW_SYSTEM # if (defined USE_CAIRO || defined HAVE_XRENDER \ - || defined HAVE_NS || defined HAVE_NTGUI) + || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU) # define HAVE_NATIVE_TRANSFORMS # endif @@ -3048,6 +3055,14 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo) #ifdef HAVE_NTGUI XFORM xform; #endif +#ifdef HAVE_HAIKU + /* Non-zero if the image has not yet been transformed for display. */ + int have_be_transforms_p; + + double be_rotate; + double be_scale_x; + double be_scale_y; +#endif /* Colors allocated for this image, if any. Allocated via xmalloc. */ unsigned long *colors; @@ -3487,7 +3502,8 @@ #define TRY_WINDOW_IGNORE_FONTS_CHANGE (1 << 1) void prepare_image_for_display (struct frame *, struct image *); ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); -#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS +#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS \ + || defined HAVE_HAIKU #define RGB_PIXEL_COLOR unsigned long #endif diff --git a/src/dispnew.c b/src/dispnew.c index 0c31319917..113174af04 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -6151,7 +6151,7 @@ sit_for (Lisp_Object timeout, bool reading, int display_option) wrong_type_argument (Qnumberp, timeout); -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) gobble_input (); #endif @@ -6458,6 +6458,15 @@ init_display_interactive (void) } #endif +#ifdef HAVE_HAIKU + if (!inhibit_window_system && !will_dump_p ()) + { + Vinitial_window_system = Qhaiku; + Vwindow_system_version = make_fixnum (1); + return; + } +#endif + /* If no window system has been specified, try to use the terminal. */ if (! isatty (STDIN_FILENO)) fatal ("standard input is not a tty"); diff --git a/src/emacs.c b/src/emacs.c index 866e43fda9..015512e629 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -2177,6 +2177,15 @@ main (int argc, char **argv) syms_of_fontset (); #endif /* HAVE_NS */ +#ifdef HAVE_HAIKU + syms_of_haikuterm (); + syms_of_haikufns (); + syms_of_haikumenu (); + syms_of_haikufont (); + syms_of_haikuselect (); + syms_of_fontset (); +#endif /* HAVE_HAIKU */ + syms_of_gnutls (); #ifdef HAVE_INOTIFY @@ -2231,6 +2240,10 @@ main (int argc, char **argv) #if defined WINDOWSNT || defined HAVE_NTGUI globals_of_w32select (); #endif + +#ifdef HAVE_HAIKU + init_haiku_select (); +#endif } init_charset (); @@ -2715,6 +2728,15 @@ shut_down_emacs (int sig, Lisp_Object stuff) } } } +#ifdef HAVE_HAIKU + /* Wait for the application thread to finish, or else we won't + be able to start the Haiku debugger. */ + if (app_thread_id) + { + pthread_kill (app_thread_id, SIGKILL); + pthread_join (app_thread_id, NULL); + } +#endif #else fflush (stdout); reset_all_sys_modes (); diff --git a/src/filelock.c b/src/filelock.c index cc185d96cd..c12776246b 100644 --- a/src/filelock.c +++ b/src/filelock.c @@ -65,7 +65,7 @@ Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2021 Free Software #define BOOT_TIME_FILE "/var/run/random-seed" #endif -#if !defined WTMP_FILE && !defined WINDOWSNT +#if !defined WTMP_FILE && !defined WINDOWSNT && defined BOOT_TIME #define WTMP_FILE "/var/log/wtmp" #endif diff --git a/src/floatfns.c b/src/floatfns.c index aadae4fd9d..a0620ad7c4 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -347,6 +347,13 @@ DEFUN ("logb", Flogb, Slogb, 1, 1, 0, double_integer_scale (double d) { int exponent = ilogb (d); +#if defined (HAIKU) && FP_ILOGB0 == FP_ILOGBNAN == INT_MAX + /* On Haiku, the values of FP_ILOGB0 and FP_ILOGBNAN are identical. + To top it all, both are also identical to INT_MAX. */ + if (exponent == FP_ILOGB0) + return (DBL_MANT_DIG - DBL_MIN_EXP) + + (isnan (d) ? 2 : isinf (d) ? 1 : 0); +#endif return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX ? DBL_MANT_DIG - 1 - exponent : (DBL_MANT_DIG - DBL_MIN_EXP diff --git a/src/font.c b/src/font.c index e043ef8d01..ffab700c57 100644 --- a/src/font.c +++ b/src/font.c @@ -5607,6 +5607,9 @@ syms_of_font (void) #ifdef HAVE_WINDOW_SYSTEM #ifdef HAVE_FREETYPE syms_of_ftfont (); +#ifdef HAVE_HAIKU + syms_of_ftbefont (); +#endif #ifdef HAVE_X_WINDOWS syms_of_xfont (); #ifdef USE_CAIRO diff --git a/src/frame.c b/src/frame.c index f95566818a..ee12f638b9 100644 --- a/src/frame.c +++ b/src/frame.c @@ -226,6 +226,7 @@ DEFUN ("framep", Fframep, Sframep, 1, 1, 0, `w32' for an Emacs frame that is a window on MS-Windows display, `ns' for an Emacs frame on a GNUstep or Macintosh Cocoa display, `pc' for a direct-write MS-DOS frame. + `haiku` for an Emacs frame running in Haiku. See also `frame-live-p'. */) (Lisp_Object object) { @@ -244,6 +245,8 @@ DEFUN ("framep", Fframep, Sframep, 1, 1, 0, return Qpc; case output_ns: return Qns; + case output_haiku: + return Qhaiku; default: emacs_abort (); } @@ -6024,6 +6027,7 @@ syms_of_frame (void) DEFSYM (Qw32, "w32"); DEFSYM (Qpc, "pc"); DEFSYM (Qns, "ns"); + DEFSYM (Qhaiku, "haiku"); DEFSYM (Qvisible, "visible"); DEFSYM (Qbuffer_predicate, "buffer-predicate"); DEFSYM (Qbuffer_list, "buffer-list"); diff --git a/src/frame.h b/src/frame.h index a8ad011889..a9b3042dcc 100644 --- a/src/frame.h +++ b/src/frame.h @@ -585,6 +585,7 @@ #define EMACS_FRAME_H struct x_output *x; /* From xterm.h. */ struct w32_output *w32; /* From w32term.h. */ struct ns_output *ns; /* From nsterm.h. */ + struct haiku_output *haiku; /* From haikuterm.h. */ } output_data; @@ -852,6 +853,11 @@ #define FRAME_NS_P(f) false #else #define FRAME_NS_P(f) ((f)->output_method == output_ns) #endif +#ifndef HAVE_HAIKU +#define FRAME_HAIKU_P(f) false +#else +#define FRAME_HAIKU_P(f) ((f)->output_method == output_haiku) +#endif /* FRAME_WINDOW_P tests whether the frame is a graphical window system frame. */ @@ -864,6 +870,9 @@ #define FRAME_WINDOW_P(f) FRAME_W32_P (f) #ifdef HAVE_NS #define FRAME_WINDOW_P(f) FRAME_NS_P(f) #endif +#ifdef HAVE_HAIKU +#define FRAME_WINDOW_P(f) FRAME_HAIKU_P (f) +#endif #ifndef FRAME_WINDOW_P #define FRAME_WINDOW_P(f) ((void) (f), false) #endif diff --git a/src/ftbefont.c b/src/ftbefont.c new file mode 100644 index 0000000000..243d097b6e --- /dev/null +++ b/src/ftbefont.c @@ -0,0 +1,266 @@ +/* FreeType font driver for Haiku + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include "blockinput.h" +#include "haiku_support.h" +#include "lisp.h" +#include "dispextern.h" +#include "font.h" +#include "pdumper.h" +#include "frame.h" +#include "haikuterm.h" +#include "termchar.h" +#include "math.h" +#include "ftfont.h" + +#ifdef HAVE_HARFBUZZ +#include +#include +#endif + +static Lisp_Object +ftbefont_list (struct frame *f, Lisp_Object spec) +{ + return ftfont_list2 (f, spec, Qftbe); +} + +static Lisp_Object +ftbefont_match (struct frame *f, Lisp_Object spec) +{ + return ftfont_match2 (f, spec, Qftbe); +} + +#ifdef HAVE_HARFBUZZ + +static Lisp_Object +ftbehbfont_list (struct frame *f, Lisp_Object spec) +{ + return ftfont_list2 (f, spec, Qftbehb); +} + +static Lisp_Object +ftbehbfont_match (struct frame *f, Lisp_Object spec) +{ + return ftfont_match2 (f, spec, Qftbehb); +} + +#endif + +static int +ftbefont_draw (struct glyph_string *s, + int from, int to, int x, int y, bool with_background) +{ + struct frame *f = s->f; + struct face *face = s->face; + struct font_info *info = (struct font_info *) s->font; + void *view = FRAME_HAIKU_VIEW (f); + + if (s->hl == DRAW_MOUSE_FACE) + face = FACE_FROM_ID_OR_NULL (s->f, + MOUSE_HL_INFO (s->f)->mouse_face_face_id); + if (!face) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + + block_input (); + prepare_face_for_display (s->f, face); + + if (info->ft_size != info->face->size) + FT_Activate_Size (info->ft_size); + + BView_draw_lock (view); + BView_StartClip (view); + + if (with_background && !s->background_filled_p) + { + int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); + int vx, vy, width, height; + vx = s->x; + vy = s->y; + width = s->width; + height = FONT_HEIGHT (face->font); + if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) + vx += max (s->face->box_vertical_line_width, 0); + + + int mbox_line_width = max (s->face->box_vertical_line_width, 0); + + if (s->row->full_width_p) + { + if (vx <= fibw + 1 + mbox_line_width) + { + width += vx - mbox_line_width; + vx = mbox_line_width; + } + if (FRAME_PIXEL_WIDTH (s->f) - (vx + width) + <= fibw + 1) + width += fibw; + } + if (s->face->box == FACE_NO_BOX) + { + /* Expand unboxed top row over internal border. */ + if (vy <= fibw + 1 + mbox_line_width) + { + height += vy; + vy = 0; + } + } + else + { + int correction = abs (s->face->box_horizontal_line_width) + 1; + vy += correction; + height -= 2 * correction; + correction = abs (s->face->box_vertical_line_width) + 1; + vx += correction; + width -= 2 * correction; + } + BView_SetHighColor (view, s->hl == DRAW_CURSOR ? + FRAME_CURSOR_COLOR (s->f).pixel : face->background); + + BView_FillRectangle (view, vx, vy, width, height); + s->background_filled_p = 1; + } + + if (s->left_overhang && s->clip_head && !s->for_overlaps) + { + /* XXX: Why is this neccessary? */ + BView_ClipToRect (view, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); + } + + if (s->hl == DRAW_CURSOR) + BView_FT_render_glyphs (info->face, &s->char2b[from], to - from, + FRAME_OUTPUT_DATA (s->f)->cursor_fg, x, y, view, + s->width, s->height, s->x, s->y); + else + BView_FT_render_glyphs (info->face, &s->char2b[from], to - from, + face->foreground, x, y, view, + s->width, s->height, s->x, s->y); + + BView_EndClip (view); + BView_draw_unlock (view); + unblock_input (); + return 0; +} + +static Lisp_Object +ftbefont_open (struct frame *f, Lisp_Object entity, int pixel_size) +{ + Lisp_Object ft = ftfont_open (f, entity, pixel_size); + if (FONT_OBJECT_P (ft)) + { + ASET (ft, FONT_TYPE_INDEX, Qftbe); + XFONT_OBJECT (ft)->driver = &ftbefont_driver; + } + return ft; +} + +#ifdef HAVE_HARFBUZZ +static hb_font_t * +ftbehbfont_begin_hb_font (struct font *font, double *position_unit) +{ + struct font_info *ftfont_info = (struct font_info *) font; + FT_Face ft_face = ftfont_info->face; + + ftfont_info->ft_size = ft_face->size; + return fthbfont_begin_hb_font (font, position_unit); +} + +static void +ftbehbfont_end_hb_font (struct font *font, hb_font_t *hb_font) +{ + struct font_info *ftfont_info = (struct font_info *) font; + ftfont_info->ft_size = NULL; +} + +static Lisp_Object +ftbehbfont_open (struct frame *f, Lisp_Object entity, int pixel_size) +{ + Lisp_Object ft = ftfont_open (f, entity, pixel_size); + if (FONT_OBJECT_P (ft)) + { + ASET (ft, FONT_TYPE_INDEX, Qftbehb); + XFONT_OBJECT (ft)->driver = &ftbehbfont_driver; + } + return ft; +} +#endif + +struct font_driver const ftbefont_driver = + { + .type = LISPSYM_INITIALLY (Qftbe), + .get_cache = ftfont_get_cache, + .list = ftbefont_list, + .match = ftbefont_match, + .draw = ftbefont_draw, + .list_family = ftfont_list_family, + .open_font = ftbefont_open, + .close_font = ftfont_close, + .has_char = ftfont_has_char, + .encode_char = ftfont_encode_char, + .text_extents = ftfont_text_extents, + .get_bitmap = ftfont_get_bitmap, + .anchor_point = ftfont_anchor_point, +#ifdef HAVE_LIBOTF + .otf_capability = ftfont_otf_capability, +#endif +#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF + .shape = ftfont_shape, +#endif +#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX + .get_variation_glyphs = ftfont_variation_glyphs, +#endif + .filter_properties = ftfont_filter_properties, + .combining_capability = ftfont_combining_capability + }; + +#ifdef HAVE_HARFBUZZ +struct font_driver ftbehbfont_driver; +#endif + +static void +syms_of_ftbefont_for_pdumper (void) +{ + register_font_driver (&ftbefont_driver, NULL); +#ifdef HAVE_HARFBUZZ + ftbehbfont_driver = ftbefont_driver; + ftbehbfont_driver.type = Qftbehb; + ftbehbfont_driver.list = ftbehbfont_list; + ftbehbfont_driver.match = ftbehbfont_match; + ftbehbfont_driver.otf_capability = hbfont_otf_capability; + ftbehbfont_driver.shape = hbfont_shape; + ftbehbfont_driver.open_font = ftbehbfont_open; + ftbehbfont_driver.combining_capability = hbfont_combining_capability; + ftbehbfont_driver.begin_hb_font = ftbehbfont_begin_hb_font; + ftbehbfont_driver.end_hb_font = ftbehbfont_end_hb_font; + + register_font_driver (&ftbehbfont_driver, NULL); +#endif +} + +void +syms_of_ftbefont (void) +{ + DEFSYM (Qftbe, "ftbe"); +#ifdef HAVE_HARFBUZZ + DEFSYM (Qftbehb, "ftbehb"); + Fput (Qftbe, Qfont_driver_superseded_by, Qftbehb); +#endif + pdumper_do_now_and_after_load (syms_of_ftbefont_for_pdumper); +} diff --git a/src/ftfont.c b/src/ftfont.c index 12d0d72d27..81feaaad23 100644 --- a/src/ftfont.c +++ b/src/ftfont.c @@ -1336,6 +1336,9 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) ftfont_info = (struct font_info *) font; ftfont_info->ft_size = ft_face->size; ftfont_info->index = XFIXNUM (idx); +#ifdef HAVE_HAIKU + ftfont_info->face = ft_face; +#endif #ifdef HAVE_LIBOTF ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0; ftfont_info->otf = NULL; @@ -3110,6 +3113,10 @@ syms_of_ftfont (void) Fput (Qfreetype, Qfont_driver_superseded_by, Qfreetypehb); #endif /* HAVE_HARFBUZZ */ +#ifdef HAVE_HAIKU + DEFSYM (Qmono, "mono"); +#endif + /* Fontconfig's generic families and their aliases. */ DEFSYM (Qmonospace, "monospace"); DEFSYM (Qsans_serif, "sans-serif"); diff --git a/src/ftfont.h b/src/ftfont.h index f771dc159b..4e3bba33f8 100644 --- a/src/ftfont.h +++ b/src/ftfont.h @@ -71,6 +71,8 @@ #define EMACS_FTFONT_H /* Font metrics cache. */ struct font_metrics **metrics; short metrics_nrows; +#elif defined (HAVE_HAIKU) + FT_Face face; #else /* These are used by the XFT backend. */ Display *display; diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc new file mode 100644 index 0000000000..fb3069a6b0 --- /dev/null +++ b/src/haiku_draw_support.cc @@ -0,0 +1,531 @@ +/* Haiku window system support. Hey, Emacs, this is -*- C++ -*- + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "haiku_support.h" + +#define RGB_TO_UINT32(r, g, b) ((255 << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) +#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) +#define BLUE_FROM_ULONG(color) ((color) & 0xff) + +extern "C" void emacs_abort (); + +static void +rgb32_to_rgb_color (uint32_t rgb, rgb_color *color) +{ + color->red = RED_FROM_ULONG (rgb); + color->green = GREEN_FROM_ULONG (rgb); + color->blue = BLUE_FROM_ULONG (rgb); + color->alpha = 255; +} + +static BView * +get_view (void *vw) +{ + BView *view = (BView *) find_appropriate_view_for_draw (vw); + return view; +} + +void +BView_StartClip (void *view) +{ + BView *vw = get_view (view); + BView_draw_lock (vw); + vw->PushState (); +} + +void +BView_EndClip (void *view) +{ + BView *vw = get_view (view); + vw->PopState (); + BView_draw_unlock (vw); +} + +void +BView_SetHighColor (void *view, uint32_t color) +{ + BView *vw = get_view (view); + rgb_color col; + rgb32_to_rgb_color (color, &col); + + vw->SetHighColor (col); +} + +void +BView_SetLowColor (void *view, uint32_t color) +{ + BView *vw = get_view (view); + rgb_color col; + rgb32_to_rgb_color (color, &col); + + vw->SetLowColor (col); +} + +void +BView_SetPenSize (void *view, int u) +{ + BView *vw = get_view (view); + vw->SetPenSize (u); +} + +void +BView_FillRectangle (void *view, int x, int y, int width, int height) +{ + BView *vw = get_view (view); + BRect rect = BRect (x, y, x + width - 1, y + height - 1); + + vw->FillRect (rect); +} + +void +BView_FillRectangleAbs (void *view, int x, int y, int x1, int y1) +{ + BView *vw = get_view (view); + BRect rect = BRect (x, y, x1, y1); + + vw->FillRect (rect); +} + +void +BView_StrokeRectangle (void *view, int x, int y, int width, int height) +{ + BView *vw = get_view (view); + BRect rect = BRect (x, y, x + width - 1, y + height - 1); + + vw->StrokeRect (rect); +} + +void +BView_SetViewColor (void *view, uint32_t color) +{ + BView *vw = get_view (view); + rgb_color col; + rgb32_to_rgb_color (color, &col); + + vw->SetViewColor (col); +} + +void +BView_ClipToRect (void *view, int x, int y, int width, int height) +{ + BView *vw = get_view (view); + BRect rect = BRect (x, y, x + width - 1, y + height - 1); + + vw->ClipToRect (rect); +} + +void +BView_ClipToInverseRect (void *view, int x, int y, int width, int height) +{ + BView *vw = get_view (view); + BRect rect = BRect (x, y, x + width - 1, y + height - 1); + + vw->ClipToInverseRect (rect); +} + +void +BView_StrokeLine (void *view, int sx, int sy, int tx, int ty) +{ + BView *vw = get_view (view); + BPoint from = BPoint (sx, sy); + BPoint to = BPoint (tx, ty); + + vw->StrokeLine (from, to); +} + +void +BView_SetFont (void *view, void *font) +{ + BView *vw = get_view (view); + + vw->SetFont ((BFont *) font); +} + +void +BView_MovePenTo (void *view, int x, int y) +{ + BView *vw = get_view (view); + BPoint pt = BPoint (x, y); + + vw->MovePenTo (pt); +} + +void +BView_DrawString (void *view, const char *chr, ptrdiff_t len) +{ + BView *vw = get_view (view); + + vw->DrawString (chr, len); +} + +void +BView_DrawChar (void *view, char chr) +{ + BView *vw = get_view (view); + + vw->DrawChar (chr); +} + +void +BView_CopyBits (void *view, int x, int y, int width, int height, + int tox, int toy, int towidth, int toheight) +{ + BView *vw = get_view (view); + + vw->CopyBits (BRect (x, y, x + width - 1, y + height - 1), + BRect (tox, toy, tox + towidth - 1, toy + toheight - 1)); + vw->Sync (); +} + +void +rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l) +{ + rgb_color col; + rgb32_to_rgb_color (rgb, &col); + + double red = col.red / 255.0; + double green = col.green / 255.0; + double blue = col.blue / 255.0; + + double max = std::fmax (std::fmax (red, blue), green); + double min = std::fmin (std::fmin (red, blue), green); + double delta = max - min; + *l = (max + min) / 2.0; + + if (!delta) + { + *h = 0; + *s = 0; + return; + } + + *s = (*l < 0.5) ? delta / (max + min) : + delta / (20 - max - min); + double rc = (max - red) / delta; + double gc = (max - green) / delta; + double bc = (max - blue) / delta; + + if (red == max) + *h = bc - gc; + else if (green == max) + *h = 2.0 + rc + -bc; + else + *h = 4.0 + gc + -rc; + *h = std::fmod (*h / 6, 1.0); +} + +static double +hue_to_rgb (double v1, double v2, double h) +{ + if (h < 1 / 6) + return v1 + (v2 - v1) * h * 6.0; + else if (h < 0.5) + return v2; + else if (h < 2.0 / 3) + return v1 + (v2 - v1) * (2.0 / 3 - h) * 6.0; + return v1; +} + +void +hsl_color_rgb (double h, double s, double l, uint32_t *rgb) +{ + if (!s) + *rgb = RGB_TO_UINT32 (std::lrint (l * 255), + std::lrint (l * 255), + std::lrint (l * 255)); + else + { + double m2 = l <= 0.5 ? l * (1 + s) : l + s - l * s; + double m1 = 2.0 * l - m2; + + *rgb = RGB_TO_UINT32 + (std::lrint (hue_to_rgb (m1, m2, + std::fmod (h + 1 / 3.0, 1)) * 255), + std::lrint (hue_to_rgb (m1, m2, h) * 255), + std::lrint (hue_to_rgb (m1, m2, + std::fmod (h - 1 / 3.0, 1)) * 255)); + } +} + +void +BView_Draw (void *view, int x, int y, int width, int height) +{ + BView *vw = get_view (view); + if (vw->LockLooper ()) + { + vw->Draw (BRect (x, y, x + width, y + height)); + vw->UnlockLooper (); + } +} + +void +BView_DrawBitmap (void *view, void *bitmap, int x, int y, + int width, int height, int vx, int vy, int vwidth, + int vheight) +{ + BView *vw = get_view (view); + BBitmap *bm = (BBitmap *) bitmap; + + vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1), + BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1)); +} + +void +BView_DrawBitmapWithEraseOpAbs (void *view, void *bitmap, int x, int y, + int width, int height, int vx, int vy, int vwidth, + int vheight) +{ + BView *vw = get_view (view); + BBitmap *bm = (BBitmap *) bitmap; + + drawing_mode dm = vw->DrawingMode (); + vw->SetDrawingMode (B_OP_ERASE); + vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1), + BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1)); + vw->SetDrawingMode (dm); +} + +void +BView_BeginLayer (void *view, float opacity) +{ + BView *vw = get_view (view); + vw->BeginLayer (opacity * 255); +} + +void +BView_EndLayer (void *view) +{ + BView *vw = get_view (view); + vw->EndLayer (); +} + +void +BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x, + int y, int width, int height) +{ + BView *vw = get_view (view); + BBitmap *bm = (BBitmap *) bitmap; + + drawing_mode dm = vw->DrawingMode (); + vw->SetDrawingMode (B_OP_ERASE); + vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1)); + vw->SetDrawingMode (dm); +} + +void +BView_BeginTransaction (void *view) +{ + BView *vw = get_view (view); + if (!vw->Window ()->LockLooper ()) + emacs_abort (); + vw->Window ()->BeginViewTransaction (); + vw->Window ()->Sync (); + vw->Window ()->UnlockLooper (); +} + +void +BView_EndTransaction (void *view) +{ + BView *vw = get_view (view); + if (!vw->Window ()->LockLooper ()) + emacs_abort (); + vw->Window ()->EndViewTransaction (); + vw->Window ()->Sync (); + vw->Window ()->UnlockLooper (); +} + +/* Potential Haiku bug: the Be Book says B_OP_ERASE ought to treat + monochrome BBitmaps as patterns, but that isn't the case here, so + we have to do everything manually. */ +void +BView_DrawFringeBitmap (void *src, void *view, + int x, int y, int width, int height, + uint32_t color) +{ + BBitmap *source = (BBitmap *) src; + BBitmap bm = BBitmap (source->Bounds (), B_RGBA32); + memset (bm.Bits (), 0, bm.BitsLength ()); + for (int y = 0; y < source->Bounds ().Height (); ++y) + { + for (int x = 0; x < source->Bounds ().Width (); ++x) + { + int byte = y * source->BytesPerRow () + x / 8; + uint8_t *bits = (uint8_t *) source->Bits (); + int bit = bits[byte] & (1 << (x % 8)); + + uint32_t *row = (uint32_t *) + &((uint8_t *) bm.Bits ())[y * bm.BytesPerRow ()]; + + if (!bit) + row[x] = color; + else + row[x] = 0; + } + } + + BView *vw = get_view (view); + vw->SetDrawingMode (B_OP_OVER); + vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1)); +} + +void +BView_DrawMask (void *src, void *view, + int x, int y, int width, int height, + int vx, int vy, int vwidth, int vheight, + uint32_t color) +{ + BBitmap *source = (BBitmap *) src; + BBitmap bm = BBitmap (source->Bounds (), B_RGBA32); + for (int y = 0; y < bm.Bounds ().Height (); ++y) + { + for (int x = 0; x < bm.Bounds ().Width (); ++x) + { + int bit = haiku_get_pixel ((void *) source, x, y); + + if (!bit) + haiku_put_pixel ((void *) &bm, x, y, ((uint32_t) 255 << 24) | color); + else + haiku_put_pixel ((void *) &bm, x, y, 0); + } + } + BView *vw = get_view (view); + vw->SetDrawingMode (B_OP_OVER); + vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1), + BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1)); +} + +void +BView_DisableWindowUpdates (void *view) +{ + BView *vw = get_view (view); + vw->Window ()->DisableUpdates (); +} + +void +BView_EnableWindowUpdates (void *view) +{ + BView *vw = get_view (view); + vw->Window ()->EnableUpdates (); +} + +static BBitmap * +rotate_bitmap_270 (BBitmap *bmp) +{ + BRect r = bmp->Bounds (); + BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right), + bmp->ColorSpace (), true); + int w = bmp->Bounds ().Width (); + int h = bmp->Bounds ().Height (); + + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) + haiku_put_pixel ((void *) bm, y, w - x - 1, + haiku_get_pixel ((void *) bmp, x, y)); + + return bm; +} + +static BBitmap * +rotate_bitmap_90 (BBitmap *bmp) +{ + BRect r = bmp->Bounds (); + BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right), + bmp->ColorSpace (), true); + int w = bmp->Bounds ().Width (); + int h = bmp->Bounds ().Height (); + + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) + haiku_put_pixel ((void *) bm, h - y - 1, x, + haiku_get_pixel ((void *) bmp, x, y)); + + return bm; +} + +void * +BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color, + double rot, int desw, int desh) +{ + BBitmap *bm = (BBitmap *) bitmap; + BBitmap *mk = (BBitmap *) mask; + int copied_p = 0; + + if (rot == 90) + { + copied_p = 1; + bm = rotate_bitmap_90 (bm); + if (mk) + mk = rotate_bitmap_90 (mk); + } + + if (rot == 270) + { + copied_p = 1; + bm = rotate_bitmap_270 (bm); + if (mk) + mk = rotate_bitmap_270 (mk); + } + + BRect r = bm->Bounds (); + if (r.Width () != desw || r.Height () != desh) + { + BRect n = BRect (0, 0, desw - 1, desh - 1); + BView vw (n, NULL, B_FOLLOW_NONE, 0); + BBitmap *dst = new BBitmap (n, bm->ColorSpace (), true); + dst->AddChild (&vw); + + if (!vw.LockLooper ()) + emacs_abort (); + + if (rot != 90 && rot != 270) + { + BAffineTransform tr; + tr.RotateBy (BPoint (desw / 2, desh / 2), rot * M_PI / 180.0); + vw.SetTransform (tr); + } + + vw.MovePenTo (0, 0); + vw.DrawBitmap (bm, n); + if (mk) + BView_DrawMask ((void *) mk, (void *) &vw, + 0, 0, mk->Bounds ().Width (), + mk->Bounds ().Height (), + 0, 0, desw, desh, m_color); + vw.Sync (); + vw.RemoveSelf (); + + if (copied_p) + delete bm; + if (copied_p && mk) + delete mk; + return dst; + } + + return bm; +} diff --git a/src/haiku_font_support.cc b/src/haiku_font_support.cc new file mode 100644 index 0000000000..e381ac310d --- /dev/null +++ b/src/haiku_font_support.cc @@ -0,0 +1,633 @@ +/* Haiku window system support. Hey, Emacs, this is -*- C++ -*- + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include +#include +#include + +#include +#include + +#include "haiku_support.h" + +/* Haiku doesn't expose font language data in BFont objects. Thus, we + select a few representative characters for each supported `:lang' + (currently Chinese, Korean and Japanese,) and test for those + instead. */ + +static uint32_t language_code_points[MAX_LANGUAGE][4] = + {{20154, 20754, 22996, 0}, /* Chinese. */ + {51312, 49440, 44544, 0}, /* Korean. */ + {26085, 26412, 12371, 0}, /* Japanese. */}; + +static void +estimate_font_ascii (BFont *font, int *max_width, + int *min_width, int *avg_width) +{ + char ch[2]; + bool tems[1]; + int total = 0; + int count = 0; + int min = 0; + int max = 0; + + std::memset (ch, 0, sizeof ch); + for (ch[0] = 1; ch[0] < 127; ++ch[0]) + { + tems[0] = false; + font->GetHasGlyphs (ch, 1, tems); + if (tems[0]) + { + int w = font->StringWidth (ch); + ++count; + total += w; + + if (!min || min > w) + min = w; + if (max < w) + max = w; + } + } + + *min_width = min; + *max_width = max; + *avg_width = total / count; +} + +void * +BFont_open_default (double size, int plain_or_bold_or_fixed) +{ + BFont *ft; + if (!plain_or_bold_or_fixed) + ft = new BFont (be_fixed_font); + else if (plain_or_bold_or_fixed > 0) + ft = new BFont (be_plain_font); + else + ft = new BFont (be_bold_font); + ft->SetSize (size); + ft->SetEncoding (B_UNICODE_UTF8); + return ft; +} + +void +BFont_close (void *font) +{ + if (font != (void *) be_fixed_font && + font != (void *) be_plain_font && + font != (void *) be_bold_font) + delete (BFont *) font; +} + +void +BFont_dat (void *font, int *px_size, int *min_width, int *max_width, + int *avg_width, int *height, int *space_width, int *ascent, + int *descent, int *underline_position, int *underline_thickness) +{ + BFont *ft = (BFont *) font; + struct font_height fheight; + bool have_space_p; + + char atem[1]; + bool otem[1]; + + ft->GetHeight (&fheight); + atem[0] = ' '; + otem[0] = false; + ft->GetHasGlyphs (atem, 1, otem); + have_space_p = otem[0]; + + estimate_font_ascii (ft, max_width, min_width, avg_width); + *ascent = std::lrint (fheight.ascent); + *descent = std::lrint (fheight.descent); + *height = *ascent + *descent; + + *space_width = have_space_p ? ft->StringWidth (" ") : 0; + + *px_size = std::lrint (ft->Size ()); + *underline_position = 0; + *underline_thickness = 0; +} + +int +BFont_have_char_p (void *font, int32_t chr) +{ + BFont *ft = (BFont *) font; + return ft->IncludesBlock (chr, chr); +} + +void +BFont_char_bounds (void *font, const char *mb_str, int *advance, + int *lb, int *rb) +{ + BFont *ft = (BFont *) font; + edge_info edge_info; + font_height height; + float size, escapement; + size = ft->Size (); + + ft->GetEdges (mb_str, 1, &edge_info); + ft->GetEscapements (mb_str, 1, &escapement); + ft->GetHeight (&height); + *advance = std::lrint (escapement * size); + *lb = std::lrint (edge_info.left * size); + *rb = *advance + std::lrint (edge_info.right * size); +} + +void +BFont_nchar_bounds (void *font, const char *mb_str, int *advance, + int *lb, int *rb, int32_t n) +{ + BFont *ft = (BFont *) font; + edge_info edge_info[n]; + float size; + float escapement[n]; + + size = ft->Size (); + + ft->GetEdges (mb_str, n, edge_info); + ft->GetEscapements (mb_str, n, (float *) escapement); + + for (int32_t i = 0; i < n; ++i) + { + advance[i] = std::lrint (escapement[i] * size); + lb[i] = advance[i] - std::lrint (edge_info[i].left * size); + rb[i] = advance[i] + std::lrint (edge_info[i].right * size); + } +} + +void * +BFont_new (void) +{ + return new BFont (); +} + +int +BFont_family_has_style_p (haiku_font_family_or_style family, + haiku_font_family_or_style style) +{ + int sc = count_font_styles (family); + for (int idx = 0; idx < sc; ++idx) + { + font_style s; + if (get_font_style (family, idx, &s) == B_OK) + { + if (!strcmp (s, style)) + return 1; + } + } + return 0; +} + +int +BFont_family (int idx, char *f, int *fixed_p) +{ + uint32_t flags; + if (get_font_family (idx, (char (*)[64]) f, &flags) != B_OK) + return 1; + *fixed_p = flags & B_IS_FIXED; + return 0; +} + +int +BFont_set_family_and_style (void *font, haiku_font_family_or_style family, + haiku_font_family_or_style style) +{ + BFont *ft = (BFont *) font; + return ft->SetFamilyAndStyle (family, style) != B_OK; +} + +int +BFont_set_family_face (void *font, haiku_font_family_or_style family, + int italic_p, int bold_p) +{ + BFont *ft = (BFont *) font; + return ft->SetFamilyAndFace (family, (italic_p ? B_ITALIC_FACE : 0) | + (bold_p == HAIKU_BOLD ? B_BOLD_FACE : 0)); + +} + +static void +font_style_to_flags (char *st, struct haiku_font_pattern *pattern) +{ + char *style = strdup (st); + char *token; + pattern->weight = -1; + pattern->width = NO_WIDTH; + pattern->slant = NO_SLANT; + int tok = 0; + + while ((token = std::strtok (!tok ? style : NULL, " ")) && tok < 3) + { + if (token && !strcmp (token, "Thin")) + pattern->weight = HAIKU_THIN; + else if (token && !strcmp (token, "UltraLight")) + pattern->weight = HAIKU_ULTRALIGHT; + else if (token && !strcmp (token, "ExtraLight")) + pattern->weight = HAIKU_EXTRALIGHT; + else if (token && !strcmp (token, "Light")) + pattern->weight = HAIKU_LIGHT; + else if (token && !strcmp (token, "SemiLight")) + pattern->weight = HAIKU_SEMI_LIGHT; + else if (token && !strcmp (token, "Regular")) + { + if (pattern->slant == NO_SLANT) + pattern->slant = SLANT_REGULAR; + + if (pattern->width == NO_WIDTH) + pattern->width = NORMAL_WIDTH; + + if (pattern->weight == -1) + pattern->weight = HAIKU_REGULAR; + } + else if (token && !strcmp (token, "SemiBold")) + pattern->weight = HAIKU_SEMI_BOLD; + else if (token && !strcmp (token, "Bold")) + pattern->weight = HAIKU_BOLD; + else if (token && (!strcmp (token, "ExtraBold") || + /* This has actually been seen in the wild. */ + !strcmp (token, "Extrabold"))) + pattern->weight = HAIKU_EXTRA_BOLD; + else if (token && !strcmp (token, "UltraBold")) + pattern->weight = HAIKU_ULTRA_BOLD; + else if (token && !strcmp (token, "Oblique")) + pattern->slant = SLANT_OBLIQUE; + else if (token && !strcmp (token, "Italic")) + pattern->slant = SLANT_ITALIC; + else if (token && !strcmp (token, "UltraCondensed")) + pattern->width = ULTRA_CONDENSED; + else if (token && !strcmp (token, "ExtraCondensed")) + pattern->width = EXTRA_CONDENSED; + else if (token && !strcmp (token, "Condensed")) + pattern->width = CONDENSED; + else if (token && !strcmp (token, "SemiCondensed")) + pattern->width = SEMI_CONDENSED; + else if (token && !strcmp (token, "SemiExpanded")) + pattern->width = SEMI_EXPANDED; + else if (token && !strcmp (token, "Expanded")) + pattern->width = EXPANDED; + else if (token && !strcmp (token, "ExtraExpanded")) + pattern->width = EXTRA_EXPANDED; + else if (token && !strcmp (token, "UltraExpanded")) + pattern->width = ULTRA_EXPANDED; + else + { + tok = 1000; + break; + } + tok++; + } + + if (pattern->weight != -1) + pattern->specified |= FSPEC_WEIGHT; + if (pattern->slant != NO_SLANT) + pattern->specified |= FSPEC_SLANT; + if (pattern->width != NO_WIDTH) + pattern->specified |= FSPEC_WIDTH; + + if (tok > 3) + { + pattern->specified &= ~FSPEC_SLANT; + pattern->specified &= ~FSPEC_WEIGHT; + pattern->specified &= ~FSPEC_WIDTH; + pattern->specified |= FSPEC_STYLE; + std::strncpy ((char *) &pattern->style, st, + sizeof pattern->style - 1); + } + + free (style); +} + +static bool +font_check_wanted_chars (struct haiku_font_pattern *pattern, font_family family, + char *style) +{ + BFont ft; + + if (ft.SetFamilyAndStyle (family, style) != B_OK) + return false; + + for (int i = 0; i < pattern->want_chars_len; ++i) + if (!ft.IncludesBlock (pattern->wanted_chars[i], + pattern->wanted_chars[i])) + return false; + + return true; +} + +static bool +font_check_one_of (struct haiku_font_pattern *pattern, font_family family, + char *style) +{ + BFont ft; + + if (ft.SetFamilyAndStyle (family, style) != B_OK) + return false; + + for (int i = 0; i < pattern->need_one_of_len; ++i) + if (ft.IncludesBlock (pattern->need_one_of[i], + pattern->need_one_of[i])) + return true; + + return false; +} + +static bool +font_check_language (struct haiku_font_pattern *pattern, font_family family, + char *style) +{ + BFont ft; + + if (ft.SetFamilyAndStyle (family, style) != B_OK) + return false; + + if (pattern->language == MAX_LANGUAGE) + return false; + + for (uint32_t *ch = (uint32_t *) + &language_code_points[pattern->language]; *ch; ch++) + if (!ft.IncludesBlock (*ch, *ch)) + return false; + + return true; +} + +static bool +font_family_style_matches_p (font_family family, char *style, uint32_t flags, + struct haiku_font_pattern *pattern, + int ignore_flags_p = 0) +{ + struct haiku_font_pattern m; + m.specified = 0; + + if (style) + font_style_to_flags (style, &m); + + if ((pattern->specified & FSPEC_FAMILY) && + strcmp ((char *) &pattern->family, family)) + return false; + + if (!ignore_flags_p && (pattern->specified & FSPEC_SPACING) && + !(pattern->mono_spacing_p) != !(flags & B_IS_FIXED)) + return false; + + if (pattern->specified & FSPEC_STYLE) + return style && !strcmp (style, pattern->style); + + if ((pattern->specified & FSPEC_WEIGHT) && + pattern->weight != ((m.specified & FSPEC_WEIGHT) ? m.weight : HAIKU_REGULAR)) + return false; + + if ((pattern->specified & FSPEC_SLANT) && + pattern->slant != ((m.specified & FSPEC_SLANT) ? m.slant : SLANT_REGULAR)) + return false; + + if ((pattern->specified & FSPEC_WANTED) && + !font_check_wanted_chars (pattern, family, style)) + return false; + + if ((pattern->specified & FSPEC_WIDTH) && + pattern->width != ((m.specified & FSPEC_WIDTH) ? m.width : NORMAL_WIDTH)) + return false; + + if ((pattern->specified & FSPEC_NEED_ONE_OF) && + !font_check_one_of (pattern, family, style)) + return false; + + if ((pattern->specified & FSPEC_LANGUAGE) && + !font_check_language (pattern, family, style)) + return false; + + return true; +} + +static void +haiku_font_fill_pattern (struct haiku_font_pattern *pattern, + font_family family, char *style, + uint32_t flags) +{ + if (style) + font_style_to_flags (style, pattern); + + pattern->specified |= FSPEC_FAMILY; + std::strncpy (pattern->family, family, + sizeof pattern->family - 1); + pattern->specified |= FSPEC_SPACING; + pattern->mono_spacing_p = flags & B_IS_FIXED; +} + +void +haiku_font_pattern_free (struct haiku_font_pattern *pt) +{ + struct haiku_font_pattern *tem = pt; + while (tem) + { + struct haiku_font_pattern *t = tem; + tem = t->next; + delete t; + } +} + +struct haiku_font_pattern * +BFont_find (struct haiku_font_pattern *pt) +{ + struct haiku_font_pattern *r = NULL; + font_family name; + font_style sname; + uint32_t flags; + int sty_count; + int fam_count = count_font_families (); + + for (int fi = 0; fi < fam_count; ++fi) + { + if (get_font_family (fi, &name, &flags) == B_OK) + { + sty_count = count_font_styles (name); + if (!sty_count && + font_family_style_matches_p (name, NULL, flags, pt)) + { + struct haiku_font_pattern *p = new struct haiku_font_pattern; + p->specified = 0; + p->oblique_seen_p = 1; + haiku_font_fill_pattern (p, name, NULL, flags); + p->next = r; + if (p->next) + p->next->last = p; + p->last = NULL; + p->next_family = r; + r = p; + } + else if (sty_count) + { + for (int si = 0; si < sty_count; ++si) + { + int oblique_seen_p = 0; + struct haiku_font_pattern *head = r; + struct haiku_font_pattern *p = NULL; + + if (get_font_style (name, si, &sname, &flags) == B_OK) + { + if (font_family_style_matches_p (name, (char *) &sname, flags, pt)) + { + p = new struct haiku_font_pattern; + p->specified = 0; + haiku_font_fill_pattern (p, name, (char *) &sname, flags); + if (p->specified & FSPEC_SLANT && + ((p->slant == SLANT_OBLIQUE) || (p->slant == SLANT_ITALIC))) + oblique_seen_p = 1; + + p->next = r; + if (p->next) + p->next->last = p; + r = p; + p->next_family = head; + } + } + + if (p) + p->last = NULL; + + for (; head; head = head->last) + { + head->oblique_seen_p = oblique_seen_p; + } + } + } + } + } + + /* There's a very good chance that this result will get cached if no + slant is specified. Thus, we look through each font that hasn't + seen an oblique style, and add one. */ + + if (!(pt->specified & FSPEC_SLANT)) + { + /* r->last is invalid from here onwards. */ + for (struct haiku_font_pattern *p = r; p;) + { + if (!p->oblique_seen_p) + { + struct haiku_font_pattern *n = new haiku_font_pattern; + *n = *p; + n->slant = SLANT_OBLIQUE; + p->next = n; + p = p->next_family; + } + else + p = p->next_family; + } + } + + return r; +} + +int +BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size) +{ + int sty_count; + font_family name; + font_style sname; + uint32_t flags = 0; + if (!(pat->specified & FSPEC_FAMILY)) + return 1; + strncpy (name, pat->family, sizeof name - 1); + sty_count = count_font_styles (name); + + if (!sty_count && + font_family_style_matches_p (name, NULL, flags, pat, 1)) + { + BFont *ft = new BFont; + if (ft->SetFamilyAndStyle (name, NULL) != B_OK) + { + delete ft; + return 1; + } + ft->SetSize (size); + ft->SetEncoding (B_UNICODE_UTF8); + ft->SetSpacing (B_BITMAP_SPACING); + *font = (void *) ft; + return 0; + } + else if (sty_count) + { + for (int si = 0; si < sty_count; ++si) + { + if (get_font_style (name, si, &sname, &flags) == B_OK && + font_family_style_matches_p (name, (char *) &sname, flags, pat)) + { + BFont *ft = new BFont; + if (ft->SetFamilyAndStyle (name, sname) != B_OK) + { + delete ft; + return 1; + } + ft->SetSize (size); + ft->SetEncoding (B_UNICODE_UTF8); + ft->SetSpacing (B_BITMAP_SPACING); + *font = (void *) ft; + return 0; + } + } + } + + if (pat->specified & FSPEC_SLANT && pat->slant == SLANT_OBLIQUE) + { + struct haiku_font_pattern copy = *pat; + copy.slant = SLANT_REGULAR; + int code = BFont_open_pattern (©, font, size); + if (code) + return code; + BFont *ft = (BFont *) *font; + /* XXX Font measurements don't respect shear. Haiku bug? + This apparently worked in BeOS. + ft->SetShear (100.0); */ + ft->SetFace (B_ITALIC_FACE); + return 0; + } + + return 1; +} + +void +BFont_populate_fixed_family (struct haiku_font_pattern *ptn) +{ + font_family f; + font_style s; + be_fixed_font->GetFamilyAndStyle (&f, &s); + + ptn->specified |= FSPEC_FAMILY; + strncpy (ptn->family, f, sizeof ptn->family - 1); +} + +void +BFont_populate_plain_family (struct haiku_font_pattern *ptn) +{ + font_family f; + font_style s; + be_plain_font->GetFamilyAndStyle (&f, &s); + + ptn->specified |= FSPEC_FAMILY; + strncpy (ptn->family, f, sizeof ptn->family - 1); +} + +int +BFont_string_width (void *font, const char *utf8) +{ + return ((BFont *) font)->StringWidth (utf8); +} diff --git a/src/haiku_freetype.cc b/src/haiku_freetype.cc new file mode 100644 index 0000000000..abb47220e9 --- /dev/null +++ b/src/haiku_freetype.cc @@ -0,0 +1,142 @@ +/* FreeType font driver for Haiku + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include "haiku_support.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include FT_FREETYPE_H +#include FT_SIZES_H +#include FT_BITMAP_H + +#define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) +#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) +#define BLUE_FROM_ULONG(color) ((color) & 0xff) + +extern "C" +{ + extern void emacs_abort (void); +} + +static void +render_g8 (FT_Bitmap *bitmap, uint32_t color, int dx, int dy, BBitmap *bm, + int max_x, int max_y, BRegion *region) +{ + if (!bitmap->width || !bitmap->rows) + return; + + for (int y = 0; y < bitmap->rows; ++y) + { + if (y + dy >= max_y) + continue; + + uint8_t *row_start_glyph = + (uint8_t *) &bitmap->buffer[y * bitmap->pitch]; + uint32_t *row_start_bitmap = ((uint32_t *) bm->Bits ()) + + (y + dy) * bm->BytesPerRow () / 4; + + for (int x = 0; x < bitmap->width; ++x) + { + if (x + dx > max_x || region->Contains (x, y)) + continue; + + int existing = (int) (row_start_bitmap[x + dx] >> 24); + + row_start_bitmap[x + dx] = + ARGB_TO_ULONG (std::min (255, existing + + (int) std::lrint ((double) row_start_glyph[x] / + (double) bitmap->num_grays * 255)), + RED_FROM_ULONG (color), + GREEN_FROM_ULONG (color), + BLUE_FROM_ULONG (color)); + } + } +} + +extern void +BView_FT_render_glyphs (FT_Face face, unsigned int *codes, + int len, uint32_t color, int x, int y, + void *view, int width, int height, + int sx, int sy) +{ + FT_Error error = FT_Err_Ok; + BView *vw = (BView *) view; + static BBitmap *canvas = NULL; + BRegion reg; + + int view_width, view_height; + view_width = vw->Bounds ().Width (); + view_height = vw->Bounds ().Height (); + + vw->GetClippingRegion (®); + + if (canvas && (canvas->Bounds () != vw->Bounds ())) + { + delete canvas; + canvas = NULL; + } + + if (!canvas) + canvas = new BBitmap (vw->Bounds (), B_RGBA32); + + if (!canvas->InitCheck ()) + emacs_abort (); + + memset (canvas->Bits (), 0, canvas->BitsLength ()); + + for (int i = 0; i < len; ++i) + { + error = FT_Load_Glyph (face, codes[i], FT_LOAD_DEFAULT); + + if (error != FT_Err_Ok) + continue; + + if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) + { + error = FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL); + if (error) + { + x += face->glyph->advance.x >> 6; + y += face->glyph->advance.y >> 6; + continue; + } + + render_g8 (&face->glyph->bitmap, color, + x + face->glyph->bitmap_left, + y - face->glyph->bitmap_top, + canvas, view_width, view_height, ®); + } + x += face->glyph->advance.x >> 6; + y += face->glyph->advance.y >> 6; + } + + vw->SetDrawingMode (B_OP_OVER); + vw->DrawBitmap (canvas); +} diff --git a/src/haiku_io.c b/src/haiku_io.c new file mode 100644 index 0000000000..c9a9983136 --- /dev/null +++ b/src/haiku_io.c @@ -0,0 +1,138 @@ +/* Haiku window system support. + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include +#include +#include +#include + +#include + +#include "haiku_support.h" +#include "lisp.h" +#include "haikuterm.h" + +#define PORT_CAP 1200 + +port_id port_emacs_to_application; +port_id port_application_to_emacs; + +void +haiku_io_init (void) +{ + port_emacs_to_application = create_port (PORT_CAP, "emacs application port"); + port_application_to_emacs = create_port (PORT_CAP, "application emacs port"); +} + +static ssize_t +haiku_len (enum haiku_event_type type) +{ + switch (type) + { + case QUIT_REQUESTED: + return sizeof (struct haiku_quit_requested_event); + case FRAME_RESIZED: + return sizeof (struct haiku_resize_event); + case FRAME_EXPOSED: + return sizeof (struct haiku_expose_event); + case KEY_DOWN: + case KEY_UP: + return sizeof (struct haiku_key_event); + case ACTIVATION: + return sizeof (struct haiku_activation_event); + case MOUSE_MOTION: + return sizeof (struct haiku_mouse_motion_event); + case BUTTON_DOWN: + case BUTTON_UP: + return sizeof (struct haiku_button_event); + case ICONIFICATION: + return sizeof (struct haiku_iconification_event); + case MOVE_EVENT: + return sizeof (struct haiku_move_event); + case SCROLL_BAR_VALUE_EVENT: + return sizeof (struct haiku_scroll_bar_value_event); + case SCROLL_BAR_DRAG_EVENT: + return sizeof (struct haiku_scroll_bar_drag_event); + case WHEEL_MOVE_EVENT: + return sizeof (struct haiku_wheel_move_event); + case MENU_BAR_RESIZE: + return sizeof (struct haiku_menu_bar_resize_event); + case MENU_BAR_OPEN: + case MENU_BAR_CLOSE: + return sizeof (struct haiku_menu_bar_state_event); + case MENU_BAR_SELECT_EVENT: + return sizeof (struct haiku_menu_bar_select_event); + } + + emacs_abort (); +} + +void +haiku_read_size (ssize_t *len) +{ + port_id from = port_application_to_emacs; + ssize_t size; + + size = port_buffer_size_etc (from, B_TIMEOUT, 0); + + if (size < B_OK) + *len = -1; + else + *len = size; +} + +int +haiku_read (enum haiku_event_type *type, void *buf, ssize_t len) +{ + int32_t typ; + port_id from = port_application_to_emacs; + + if (read_port (from, &typ, buf, len) < B_OK) + return -1; + + *type = (enum haiku_event_type) typ; + eassert (len == haiku_len (typ)); + return 0; +} + +int +haiku_write (enum haiku_event_type type, void *buf) +{ + port_id to = port_application_to_emacs; + + if (write_port (to, (int32_t) type, buf, haiku_len (type)) < B_OK) + return -1; + + kill (getpid (), SIGPOLL); + + return 0; +} + +void +haiku_io_init_in_app_thread (void) +{ + sigset_t set; + sigemptyset (&set); + sigaddset (&set, SIGUSR2); + sigaddset (&set, SIGUSR1); + + if (pthread_sigmask (SIG_BLOCK, &set, NULL)) + perror ("pthread_sigmask"); +} diff --git a/src/haiku_select.cc b/src/haiku_select.cc new file mode 100644 index 0000000000..8d345ca661 --- /dev/null +++ b/src/haiku_select.cc @@ -0,0 +1,155 @@ +/* Haiku window system selection support. Hey Emacs, this is -*- C++ -*- + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include + +#include +#include + +#include "haikuselect.h" + + +static BClipboard *primary = NULL; +static BClipboard *secondary = NULL; +static BClipboard *system_clipboard = NULL; + +int selection_state_flag; + +static char * +BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len) +{ + if (!cb->Lock ()) + return 0; + + BMessage *dat = cb->Data (); + if (!dat) + { + cb->Unlock (); + return 0; + } + + const char *ptr; + ssize_t bt; + dat->FindData (type, B_MIME_TYPE, (const void **) &ptr, &bt); + + if (!ptr) + { + cb->Unlock (); + return NULL; + } + + if (len) + *len = bt; + + cb->Unlock (); + + return strndup (ptr, bt); +} + +static void +BClipboard_set_data (BClipboard *cb, const char *type, const char *dat, + ssize_t len) +{ + if (!cb->Lock ()) + return; + cb->Clear (); + BMessage *mdat = cb->Data (); + if (!mdat) + { + cb->Unlock (); + return; + } + + if (dat) + mdat->AddData (type, B_MIME_TYPE, dat, len); + cb->Commit (); + cb->Unlock (); +} + +char * +BClipboard_find_system_data (const char *type, ssize_t *len) +{ + if (!system_clipboard) + return 0; + + return BClipboard_find_data (system_clipboard, type, len); +} + +char * +BClipboard_find_primary_selection_data (const char *type, ssize_t *len) +{ + if (!primary) + return 0; + + return BClipboard_find_data (primary, type, len); +} + +char * +BClipboard_find_secondary_selection_data (const char *type, ssize_t *len) +{ + if (!secondary) + return 0; + + return BClipboard_find_data (secondary, type, len); +} + +void +BClipboard_set_system_data (const char *type, const char *data, + ssize_t len) +{ + if (!system_clipboard) + return; + + BClipboard_set_data (system_clipboard, type, data, len); +} + +void +BClipboard_set_primary_selection_data (const char *type, const char *data, + ssize_t len) +{ + if (!primary) + return; + + BClipboard_set_data (primary, type, data, len); +} + +void +BClipboard_set_secondary_selection_data (const char *type, const char *data, + ssize_t len) +{ + if (!secondary) + return; + + BClipboard_set_data (secondary, type, data, len); +} + +void +BClipboard_free_data (void *ptr) +{ + std::free (ptr); +} + +void +init_haiku_select (void) +{ + system_clipboard = new BClipboard ("system"); + primary = new BClipboard ("primary"); + secondary = new BClipboard ("secondary"); +} diff --git a/src/haiku_simx.c b/src/haiku_simx.c new file mode 100644 index 0000000000..bd1d6c88f0 --- /dev/null +++ b/src/haiku_simx.c @@ -0,0 +1,185 @@ +/* Utilities and defines for using XPM without X on Haiku + +Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include +#include +#include +#include + +#include "dispextern.h" +#include "haiku_support.h" +#define FOR_MSW +#include "xpm_be.h" +#undef FOR_MSW + +/* Defined in haikufns.c. */ +extern int haiku_get_color (const char *name, Emacs_Color *color); +extern unsigned long haiku_get_pixel (haiku bitmap, int x, int y); +extern void haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel); + +Visual * +XDefaultVisual (Display *dpy, Screen *screen) +{ + return NULL; +} + +Screen * +XDefaultScreen (Display *d) +{ + return NULL; +} + +int +XDefaultDepth (Display *display, Screen *screen) +{ + return 24; +} + +Colormap * +XDefaultColormap (Display *display, Screen *screen) +{ + return NULL; +} + +int +XParseColor (Display *d, Colormap *cmap, char *name, XColor *color) +{ + int r, g, b; + int okay; + + if (name == NULL) + return (0); + + Emacs_Color ecol; + + okay = !haiku_get_color (name, &ecol); + if (okay) + { + r = ecol.red / 256; + g = ecol.green / 256; + b = ecol.blue / 256; + } + + if (okay) + { + color->red = (uint8_t) r; + color->green = (uint8_t) g; + color->blue = (uint8_t) b; + color->pixel = ((color->red << 16) | + (color->green << 8) | + color->blue); + return 1; + } + else + return 0; +} + +int +XAllocColor (Display *d, Colormap cmap, XColor *color) +{ + return 1; +} + +void +XQueryColors (Display *display, Colormap *colormap, + XColor *xcolors, int ncolors) +{ + for (int i = 0; i < ncolors; ++i) + { + xcolors[i].red = xcolors[i].pixel >> 16 & 0xff; + xcolors[i].green = xcolors[i].pixel >> 8 & 0xff; + xcolors[i].blue = xcolors[i].pixel & 0xff; + } +} + +XImage * +XCreateImage (Display *d, Visual *v, + int depth, int format, + int x, int y, int width, int height, + int pad, int foo) +{ + XImage *img = (XImage *) malloc (sizeof (XImage)); + + if (img) + { + img->bitmap = BBitmap_new (width + 1, height + 1, depth == 1); + img->width = width + 1; + img->height = height + 1; + img->depth = depth == 1 ? 1 : 32; + } + + return img; +} + +int +XFreeColors (Display *d, Colormap cmap, + Pixel *pixels, int npixels, unsigned long planes) +{ + return 0; +} + +void +XImageFree (XImage *img) +{ + if (img) + free (img); +} + +void +XDestroyImage (XImage *img) +{ + if (img) + { + BBitmap_free (img->bitmap); + XImageFree (img); + } +} + +void * +boundCheckingMalloc (long size) +{ + return malloc (size); +} + +void * +boundCheckingCalloc (long n, long s) +{ + return calloc (n, s); +} + +void * +boundCheckingRealloc (void *p, long s) +{ + return realloc (p, s); +} + +void +XPutPixel (XImage *img, int x, int y, unsigned long p) +{ + if (img->depth == 1) + haiku_put_pixel (img->bitmap, x, y, p); + else + haiku_put_pixel (img->bitmap, x, y, p | ((unsigned long) 255) << 24); +} + +unsigned long +XGetPixel (XImage *img, int x, int y) +{ + return haiku_get_pixel (img->bitmap, x, y); +} diff --git a/src/haiku_support.cc b/src/haiku_support.cc new file mode 100644 index 0000000000..e0800b2245 --- /dev/null +++ b/src/haiku_support.cc @@ -0,0 +1,1803 @@ +/* Haiku window system support. Hey, Emacs, this is -*- C++ -*- + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "haiku_support.h" + +#define SCROLL_BAR_UPDATE 3000 + +static color_space dpy_color_space = B_NO_COLOR_SPACE; +static key_map *key_map = NULL; +static char *key_chars = NULL; + +extern "C" +{ + extern void emacs_abort (void); + pthread_t app_thread_id; +} + +static void +map_key (char *chars, int32 offset, uint32_t *c) +{ + int size = chars[offset++]; + switch (size) + { + case 0: + break; + + case 1: + *c = chars[offset]; + break; + + default: + { + char str[5]; + int i = (size <= 4) ? size : 4; + strncpy (str, &(chars[offset]), i); + str[i] = '0'; + *c = BUnicodeChar::FromUTF8 ((char *) &str); + break; + } + } +} + +static void +map_shift (uint32_t kc, uint32_t *ch) +{ + if (!key_map) + get_key_map (&key_map, &key_chars); + if (!key_map) + return; + if (kc >= 128) + return; + + int32_t m = key_map->shift_map[kc]; + map_key (key_chars, m, ch); +} + +class Emacs : public BApplication +{ +public: + Emacs () : BApplication ("application/x-vnd.GNU-emacs") + { + } +}; + +class EmacsWindow : public BDirectWindow +{ +public: + struct child_frame + { + struct child_frame *next; + int xoff, yoff; + EmacsWindow *window; + } *subset_windows = NULL; + + EmacsWindow *parent = NULL; + + EmacsWindow () : BDirectWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK, + B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS) + { + + } + + ~EmacsWindow () + { + struct child_frame *next; + for (struct child_frame *f = subset_windows; f; f = next) + { + f->window->Unparent (); + next = f->next; + delete f; + } + + if (this->parent) + UnparentAndUnlink (); + } + + void + UpwardsSubset (EmacsWindow *w) + { + for (; w; w = w->parent) + AddToSubset (w); + } + + void + UpwardsSubsetChildren (EmacsWindow *w) + { + UpwardsSubset (w); + for (struct child_frame *f = subset_windows; f; + f = f->next) + f->window->UpwardsSubsetChildren (w); + } + + void + UpwardsUnSubset (EmacsWindow *w) + { + for (; w; w = w->parent) + RemoveFromSubset (w); + } + + void + UpwardsUnSubsetChildren (EmacsWindow *w) + { + UpwardsUnSubset (w); + for (struct child_frame *f = subset_windows; f; + f = f->next) + f->window->UpwardsUnSubsetChildren (w); + } + + void + Unparent (void) + { + this->SetFeel (B_NORMAL_WINDOW_FEEL); + UpwardsUnSubsetChildren (parent); + this->RemoveFromSubset (this); + this->parent = NULL; + } + + void + UnparentAndUnlink (void) + { + this->parent->UnlinkChild (this); + this->Unparent (); + } + + void + UnlinkChild (EmacsWindow *window) + { + struct child_frame *last = NULL; + struct child_frame *tem = subset_windows; + + for (; tem; last = tem, tem = tem->next) + { + if (tem->window == window) + { + if (last) + last->next = tem->next; + if (tem == subset_windows) + subset_windows = NULL; + delete tem; + return; + } + } + + emacs_abort (); + } + + void + ParentTo (EmacsWindow *window) + { + if (this->parent) + UnparentAndUnlink (); + + this->parent = window; + this->SetFeel (B_FLOATING_SUBSET_WINDOW_FEEL); + this->AddToSubset (this); + if (!IsHidden () && this->parent) + UpwardsSubsetChildren (parent); + this->Sync (); + window->LinkChild (this); + } + + void + LinkChild (EmacsWindow *window) + { + struct child_frame *f = new struct child_frame; + + for (struct child_frame *f = subset_windows; f; + f = f->next) + { + if (window == f->window) + emacs_abort (); + } + + f->window = window; + f->next = subset_windows; + f->xoff = -1; + f->yoff = -1; + + subset_windows = f; + } + + void + DoMove (struct child_frame *f) + { + BRect frame = this->Frame (); + f->window->MoveTo (frame.left + f->xoff, + frame.top + f->yoff); + this->Sync (); + } + + void + DoUpdateWorkspace (struct child_frame *f) + { + f->window->SetWorkspaces (this->Workspaces ()); + } + + void + MoveChild (EmacsWindow *window, int xoff, int yoff, + int weak_p) + { + for (struct child_frame *f = subset_windows; f; + f = f->next) + { + if (window == f->window) + { + f->xoff = xoff; + f->yoff = yoff; + if (!weak_p) + DoMove (f); + return; + } + } + + emacs_abort (); + } + + void + WindowActivated (bool activated) + { + struct haiku_activation_event rq; + rq.window = this; + rq.activated_p = activated; + + haiku_write (ACTIVATION, &rq); + } + + void + MessageReceived (BMessage *msg) + { + if (msg->GetPointer ("menuptr")) + { + struct haiku_menu_bar_select_event rq; + rq.window = this; + rq.ptr = (void *) msg->GetPointer ("menuptr"); + haiku_write (MENU_BAR_SELECT_EVENT, &rq); + } + BDirectWindow::MessageReceived (msg); + } + + void + DispatchMessage (BMessage *msg, BHandler *handler) + { + if (msg->what == B_KEY_DOWN || msg->what == B_KEY_UP) + { + struct haiku_key_event rq; + rq.window = this; + + int32_t code = msg->GetInt32 ("raw_char", 0); + + rq.modifiers = 0; + uint32_t mods = modifiers (); + + if (mods & B_SHIFT_KEY) + rq.modifiers |= HAIKU_MODIFIER_SHIFT; + + if (mods & B_CONTROL_KEY) + rq.modifiers |= HAIKU_MODIFIER_CTRL; + + if (mods & B_COMMAND_KEY) + rq.modifiers |= HAIKU_MODIFIER_ALT; + + rq.mb_char = code; + rq.kc = msg->GetInt32 ("key", -1); + rq.unraw_mb_char = + BUnicodeChar::FromUTF8 (msg->GetString ("bytes")); + + if ((mods & B_SHIFT_KEY) && rq.kc >= 0) + map_shift (rq.kc, &rq.unraw_mb_char); + + haiku_write (msg->what == B_KEY_DOWN ? KEY_DOWN : KEY_UP, &rq); + } + else if (msg->what == B_MOUSE_WHEEL_CHANGED) + { + struct haiku_wheel_move_event rq; + rq.window = this; + rq.modifiers = 0; + + uint32_t mods = modifiers (); + + if (mods & B_SHIFT_KEY) + rq.modifiers |= HAIKU_MODIFIER_SHIFT; + + if (mods & B_CONTROL_KEY) + rq.modifiers |= HAIKU_MODIFIER_CTRL; + + if (mods & B_COMMAND_KEY) + rq.modifiers |= HAIKU_MODIFIER_ALT; + + float dx, dy; + if (msg->FindFloat ("be:wheel_delta_x", &dx) == B_OK && + msg->FindFloat ("be:wheel_delta_y", &dy) == B_OK) + { + rq.delta_x = dx; + rq.delta_y = dy; + + haiku_write (WHEEL_MOVE_EVENT, &rq); + }; + } + else + BDirectWindow::DispatchMessage (msg, handler); + } + + void + MenusBeginning () + { + struct haiku_menu_bar_state_event rq; + rq.window = this; + + haiku_write (MENU_BAR_OPEN, &rq); + } + + void + MenusEnded () + { + struct haiku_menu_bar_state_event rq; + rq.window = this; + + haiku_write (MENU_BAR_CLOSE, &rq); + } + + void + FrameResized (float newWidth, float newHeight) + { + struct haiku_resize_event rq; + rq.window = this; + rq.px_heightf = newHeight; + rq.px_widthf = newWidth; + + haiku_write (FRAME_RESIZED, &rq); + BDirectWindow::FrameResized (newWidth, newHeight); + } + + void + FrameMoved (BPoint newPosition) + { + struct haiku_move_event rq; + rq.window = this; + rq.x = std::lrint (newPosition.x); + rq.y = std::lrint (newPosition.y); + + haiku_write (MOVE_EVENT, &rq); + + for (struct child_frame *f = subset_windows; + f; f = f->next) + DoMove (f); + BDirectWindow::FrameMoved (newPosition); + } + + void + WorkspacesChanged (uint32_t old, uint32_t n) + { + for (struct child_frame *f = subset_windows; + f; f = f->next) + DoUpdateWorkspace (f); + } + + void + EmacsMoveTo (int x, int y) + { + if (!this->parent) + this->MoveTo (x, y); + else + this->parent->MoveChild (this, x, y, 0); + } + + bool + QuitRequested () + { + struct haiku_quit_requested_event rq; + rq.window = this; + haiku_write (QUIT_REQUESTED, &rq); + return false; + } + + void + Minimize (bool minimized_p) + { + BDirectWindow::Minimize (minimized_p); + struct haiku_iconification_event rq; + rq.window = this; + rq.iconified_p = !parent && minimized_p; + + haiku_write (ICONIFICATION, &rq); + } + + void + EmacsHide (void) + { + if (this->IsHidden ()) + return; + Hide (); + if (this->parent) + UpwardsUnSubsetChildren (this->parent); + } + + void + EmacsShow (void) + { + if (!this->IsHidden ()) + return; + Show (); + if (this->parent) + UpwardsSubsetChildren (this->parent); + } +}; + +class EmacsMenuBar : BMenuBar +{ +public: + EmacsMenuBar () : BMenuBar (BRect (0, 0, 0, 0), NULL) + { + } + + void + FrameResized (float newWidth, float newHeight) + { + struct haiku_menu_bar_resize_event rq; + rq.window = this->Window (); + rq.height = std::lrint (newHeight); + rq.width = std::lrint (newWidth); + + haiku_write (MENU_BAR_RESIZE, &rq); + BMenuBar::FrameResized (newWidth, newHeight); + } +}; + +class EmacsView : public BView +{ +public: + uint32_t previous_buttons = 0; + int looper_locked_count = 0; + BRegion sb_region; + + BView *offscreen_draw_view = NULL; + BBitmap *offscreen_draw_bitmap_1 = NULL; + BBitmap *offscreen_blit_bitmap_1 = NULL; + + BScreen *screen = NULL; + color_space cspace; + + EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs Content", + B_FOLLOW_NONE, B_WILL_DRAW | B_INPUT_METHOD_AWARE) + { + + } + + ~EmacsView () + { + TearDownDoubleBuffering (); + delete screen; + } + + void + AttachedToWindow (void) + { + screen = new BScreen (Window ()); + cspace = screen->ColorSpace (); + } + + void + TearDownDoubleBuffering (void) + { + if (offscreen_draw_view) + { + if (!offscreen_draw_view->LockLooper ()) + emacs_abort (); + offscreen_draw_view->RemoveSelf (); + delete offscreen_draw_view; + offscreen_draw_view = NULL; + delete offscreen_draw_bitmap_1; + offscreen_draw_bitmap_1 = NULL; + delete offscreen_blit_bitmap_1; + offscreen_blit_bitmap_1 = NULL; + } + } + + void + AfterResize (float newWidth, float newHeight) + { + if (offscreen_draw_view) + { + if (!offscreen_draw_view->LockLooper ()) + emacs_abort (); + offscreen_draw_view->RemoveSelf (); + delete offscreen_blit_bitmap_1; + offscreen_blit_bitmap_1 = new BBitmap (Frame (), cspace, 1); + delete offscreen_draw_bitmap_1; + offscreen_draw_bitmap_1 = new BBitmap (Frame (), cspace, 1); + offscreen_draw_view->MoveTo (Frame ().left, Frame ().top); + offscreen_draw_view->ResizeTo (Frame ().Width (), Frame ().Height ()); + offscreen_draw_bitmap_1->AddChild (offscreen_draw_view); + + if (looper_locked_count) + offscreen_draw_view->LockLooper (); + } + } + + void + Draw (BRect expose_bounds) + { + struct haiku_expose_event rq; + if (!offscreen_draw_view) + { + if (sb_region.Contains (std::lrint (expose_bounds.left), + std::lrint (expose_bounds.top)) && + sb_region.Contains (std::lrint (expose_bounds.right), + std::lrint (expose_bounds.top)) && + sb_region.Contains (std::lrint (expose_bounds.left), + std::lrint (expose_bounds.bottom)) && + sb_region.Contains (std::lrint (expose_bounds.right), + std::lrint (expose_bounds.bottom))) + return; + + rq.x = std::floor (expose_bounds.left); + rq.y = std::floor (expose_bounds.top); + rq.width = std::ceil (expose_bounds.right - expose_bounds.left + 1); + rq.height = std::ceil (expose_bounds.bottom - expose_bounds.top + 1); + if (!rq.width) + rq.width = 1; + if (!rq.height) + rq.height = 1; + rq.window = this->Window (); + + haiku_write (FRAME_EXPOSED, &rq); + } + else + { + DrawBitmap (offscreen_blit_bitmap_1, expose_bounds, expose_bounds); + } + } + + void + FlipBuffers (void) + { + if (!LockLooper ()) + emacs_abort (); + if (!offscreen_draw_view) + emacs_abort (); + + offscreen_draw_view->RemoveSelf (); + BBitmap *b = offscreen_blit_bitmap_1; + offscreen_blit_bitmap_1 = offscreen_draw_bitmap_1; + offscreen_draw_bitmap_1 = b; + b->ImportBits (offscreen_blit_bitmap_1); + offscreen_draw_bitmap_1->AddChild (offscreen_draw_view); + + if (looper_locked_count) + { + if (!offscreen_draw_view->LockLooper ()) + emacs_abort (); + } + + Invalidate (); + UnlockLooper (); + return; + } + + void + SetUpDoubleBuffering (void) + { + if (!LockLooper ()) + emacs_abort (); + if (offscreen_draw_view) + emacs_abort (); + + offscreen_draw_view = new BView (Frame (), NULL, B_FOLLOW_NONE, B_WILL_DRAW); + offscreen_blit_bitmap_1 = new BBitmap (Frame (), cspace, 1); + offscreen_draw_bitmap_1 = new BBitmap (Frame (), cspace, 1); + offscreen_draw_bitmap_1->AddChild (offscreen_draw_view); + + if (looper_locked_count) + offscreen_draw_view->LockLooper (); + + UnlockLooper (); + Invalidate (); + } + + void + MouseMoved (BPoint point, uint32 transit, const BMessage *msg) + { + struct haiku_mouse_motion_event rq; + + rq.just_exited_p = transit == B_EXITED_VIEW; + rq.x = point.x; + rq.y = point.y; + rq.be_code = transit; + rq.window = this->Window (); + + haiku_write (MOUSE_MOTION, &rq); + } + + void + MouseDown (BPoint point) + { + struct haiku_button_event rq; + uint32_t buttons; + + this->GetMouse (&point, &buttons, false); + + rq.window = this->Window (); + rq.btn_no = 0; + + if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON) && + (buttons & B_PRIMARY_MOUSE_BUTTON)) + rq.btn_no = 0; + else if (!(previous_buttons & B_SECONDARY_MOUSE_BUTTON) && + (buttons & B_SECONDARY_MOUSE_BUTTON)) + rq.btn_no = 2; + else if (!(previous_buttons & B_TERTIARY_MOUSE_BUTTON) && + (buttons & B_TERTIARY_MOUSE_BUTTON)) + rq.btn_no = 1; + previous_buttons = buttons; + + rq.x = point.x; + rq.y = point.y; + + uint32_t mods = modifiers (); + + rq.modifiers = 0; + if (mods & B_SHIFT_KEY) + rq.modifiers |= HAIKU_MODIFIER_SHIFT; + + if (mods & B_CONTROL_KEY) + rq.modifiers |= HAIKU_MODIFIER_CTRL; + + if (mods & B_COMMAND_KEY) + rq.modifiers |= HAIKU_MODIFIER_ALT; + + haiku_write (BUTTON_DOWN, &rq); + } + + void + MouseUp (BPoint point) + { + struct haiku_button_event rq; + uint32_t buttons; + + this->GetMouse (&point, &buttons, false); + + rq.window = this->Window (); + rq.btn_no = 0; + + if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON) && + !(buttons & B_PRIMARY_MOUSE_BUTTON)) + rq.btn_no = 0; + else if ((previous_buttons & B_SECONDARY_MOUSE_BUTTON) && + !(buttons & B_SECONDARY_MOUSE_BUTTON)) + rq.btn_no = 2; + else if ((previous_buttons & B_TERTIARY_MOUSE_BUTTON) && + !(buttons & B_TERTIARY_MOUSE_BUTTON)) + rq.btn_no = 1; + previous_buttons = buttons; + + rq.x = point.x; + rq.y = point.y; + + uint32_t mods = modifiers (); + + rq.modifiers = 0; + if (mods & B_SHIFT_KEY) + rq.modifiers |= HAIKU_MODIFIER_SHIFT; + + if (mods & B_CONTROL_KEY) + rq.modifiers |= HAIKU_MODIFIER_CTRL; + + if (mods & B_COMMAND_KEY) + rq.modifiers |= HAIKU_MODIFIER_ALT; + + haiku_write (BUTTON_UP, &rq); + } +}; + +class EmacsScrollBar : BScrollBar +{ +public: + void *scroll_bar; + + EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p) : + BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ? + B_HORIZONTAL : B_VERTICAL) + { + BView *vw = (BView *) this; + vw->SetFlags (vw->Flags () & ~B_FRAME_EVENTS); + vw->SetResizingMode (B_FOLLOW_NONE); + } + + void + MessageReceived (BMessage *msg) + { + if (msg->what == SCROLL_BAR_UPDATE) + { + this->SetRange (0, msg->GetInt32 ("emacs:range", 0)); + this->SetValue (msg->GetInt32 ("emacs:units", 0)); + } + + BScrollBar::MessageReceived (msg); + } + + void + ValueChanged (float new_value) + { + struct haiku_scroll_bar_value_event rq; + rq.scroll_bar = scroll_bar; + rq.position = new_value; + + haiku_write (SCROLL_BAR_VALUE_EVENT, &rq); + } + + void + MouseDown (BPoint pt) + { + struct haiku_scroll_bar_drag_event rq; + rq.dragging_p = 1; + rq.scroll_bar = scroll_bar; + + haiku_write (SCROLL_BAR_DRAG_EVENT, &rq); + BScrollBar::MouseDown (pt); + } + + void + MouseUp (BPoint pt) + { + struct haiku_scroll_bar_drag_event rq; + rq.dragging_p = 0; + rq.scroll_bar = scroll_bar; + + haiku_write (SCROLL_BAR_DRAG_EVENT, &rq); + BScrollBar::MouseUp (pt); + } +}; + +static void * +start_running_application (void *data) +{ + haiku_io_init_in_app_thread (); + + ((Emacs *) data)->Lock (); + ((Emacs *) data)->Run (); + ((Emacs *) data)->Unlock (); + return NULL; +} + +static uint8_t +reverse_fringe_byte (uint8_t b) +{ + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} + +void * +BBitmap_data (void *bitmap) +{ + return ((BBitmap *) bitmap)->Bits (); +} + +int +BBitmap_convert (void *_bitmap, void **new_bitmap) +{ + BBitmap *bitmap = (BBitmap *) _bitmap; + if (bitmap->ColorSpace () != B_RGBA32) + return 0; + BRect bounds = bitmap->Bounds (); + BBitmap *bmp = new (std::nothrow) BBitmap (bounds, B_RGBA32); + if (!bmp) + return 0; + if (bmp->ImportBits (bitmap) != B_OK) + { + delete bmp; + return 0; + } + **(BBitmap **) new_bitmap = bmp; + return 1; +} + +void +BBitmap_free (void *bitmap) +{ + delete (BBitmap *) bitmap; +} + +void * +BBitmap_new (int width, int height, int mono_p) +{ + BBitmap *bn = new (std::nothrow) BBitmap (BRect (0, 0, width - 1, height - 1), + mono_p ? B_GRAY1 : B_RGB32); + + return bn; +} + +void +BBitmap_dimensions (void *bitmap, int *left, int *top, + int *right, int *bottom, + int32_t *bytes_per_row, int *mono_p) +{ + BRect rect = ((BBitmap *) bitmap)->Bounds (); + *left = rect.left; + *top = rect.top; + *right = rect.right; + *bottom = rect.bottom; + + *bytes_per_row = ((BBitmap *) bitmap)->BytesPerRow (); + *mono_p = (((BBitmap *) bitmap)->ColorSpace () == B_GRAY1); +} + +void * +BApplication_setup (void) +{ + if (be_app) + return be_app; + Emacs *app; + + app = new Emacs; + if (pthread_create (&app_thread_id, NULL, start_running_application, app)) + { + perror ("pthread_create"); + emacs_abort (); + } + + return app; +} + +void * +BWindow_new (void *_view) +{ + BWindow *window = new (std::nothrow) EmacsWindow; + BView **v = (BView **) _view; + if (!window) + { + *v = NULL; + return window; + } + + BView *vw = new (std::nothrow) EmacsView; + if (!vw) + { + *v = NULL; + window->Lock (); + window->Quit (); + return NULL; + } + window->AddChild (vw); + *v = vw; + return window; +} + +void +BWindow_quit (void *window) +{ + ((BWindow *) window)->Lock (); + ((BWindow *) window)->Quit (); +} + +void +BWindow_set_offset (void *window, int x, int y) +{ + BWindow *wn = (BWindow *) window; + EmacsWindow *w = dynamic_cast (wn); + if (w) + { + if (!w->LockLooper ()) + emacs_abort (); + w->EmacsMoveTo (x, y); + w->UnlockLooper (); + } + else + wn->MoveTo (x, y); +} + +void +BWindow_iconify (void *window) +{ + if (((BWindow *) window)->IsHidden ()) + BWindow_set_visible (window, true); + ((BWindow *) window)->Minimize (true); +} + +void +BWindow_set_visible (void *window, int visible_p) +{ + EmacsWindow *win = (EmacsWindow *) window; + if (visible_p) + { + if (win->IsMinimized ()) + win->Minimize (false); + win->EmacsShow (); + } + else if (!win->IsHidden ()) + { + if (win->IsMinimized ()) + win->Minimize (false); + win->EmacsHide (); + } + win->Sync (); +} + +void +BWindow_retitle (void *window, const char *title) +{ + ((BWindow *) window)->SetTitle (title); +} + +void +BWindow_resize (void *window, int width, int height) +{ + ((BWindow *) window)->ResizeTo (width, height); +} + +void +BWindow_activate (void *window) +{ + ((BWindow *) window)->Activate (); +} + +void +BScreen_px_dim (int *width, int *height) +{ + BScreen screen; + BRect frame = screen.Frame (); + + *width = frame.right - frame.left; + *height = frame.bottom - frame.top; +} + +void +BView_resize_to (void *view, int width, int height) +{ + EmacsView *vw = (EmacsView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->ResizeTo (width, height); + vw->AfterResize (width, height); + vw->UnlockLooper (); +} + +void * +BCursor_create_default (void) +{ + return new BCursor (B_CURSOR_ID_SYSTEM_DEFAULT); +} + +void * +BCursor_from_id (enum haiku_cursor cursor) +{ + return new BCursor ((enum BCursorID) cursor); +} + +void * +BCursor_create_i_beam (void) +{ + return new BCursor (B_CURSOR_ID_I_BEAM); +} + +void * +BCursor_create_progress_cursor (void) +{ + return new BCursor (B_CURSOR_ID_PROGRESS); +} + +void * +BCursor_create_grab (void) +{ + return new BCursor (B_CURSOR_ID_GRAB); +} + +void +BCursor_delete (void *cursor) +{ + delete (BCursor *) cursor; +} + +void +BView_set_view_cursor (void *view, void *cursor) +{ + if (!((BView *) view)->LockLooper ()) + emacs_abort (); + ((BView *) view)->SetViewCursor ((BCursor *) cursor); + ((BView *) view)->UnlockLooper (); +} + +void +BWindow_Flush (void *window) +{ + ((BWindow *) window)->Flush (); +} + +void +BMapKey (uint32_t kc, int *non_ascii_p, unsigned *code) +{ + *code = 0; + + switch (kc) + { + default: + *non_ascii_p = 0; + if (kc < 0xe && kc > 0x1) + { + *code = XK_F1 + kc - 2; + *non_ascii_p = 1; + } + return; + case 0x1e: + *code = XK_BackSpace; + break; + case 0x32: + case 0x5b: + case 0x47: + *code = XK_Return; + break; + case 0x61: + *code = XK_Left; + break; + case 0x63: + *code = XK_Right; + break; + case 0x57: + *code = XK_Up; + break; + case 0x62: + *code = XK_Down; + break; + case 0x64: + *code = XK_Insert; + break; + case 0x65: + *code = XK_Delete; + break; + case 0x37: + *code = XK_Home; + break; + case 0x58: + *code = XK_End; + break; + case 0x39: + *code = XK_Page_Up; + break; + case 0x5a: + *code = XK_Page_Down; + break; + case 0x1: + *code = XK_Escape; + break; + case 0x68: + *code = XK_Menu; + break; + } + *non_ascii_p = 1; +} + +void * +BScrollBar_make_for_view (void *view, int horizontal_p, + int x, int y, int x1, int y1, + void *scroll_bar_ptr) +{ + EmacsScrollBar *sb = new EmacsScrollBar (x, y, x1, y1, horizontal_p); + sb->scroll_bar = scroll_bar_ptr; + + BView *vw = (BView *) view; + BView *sv = (BView *) sb; + if (!vw->LockLooper ()) + emacs_abort (); + vw->AddChild ((BView *) sb); + sv->WindowActivated (vw->Window ()->IsActive ()); + vw->UnlockLooper (); + return sb; +} + +void +BScrollBar_delete (void *sb) +{ + BView *view = (BView *) sb; + BView *pr = view->Parent (); + + if (!pr->LockLooper ()) + emacs_abort (); + pr->RemoveChild (view); + pr->UnlockLooper (); + + delete (EmacsScrollBar *) sb; +} + +void +BView_move_frame (void *view, int x, int y, int x1, int y1) +{ + BView *vw = (BView *) view; + + if (!vw->LockLooper ()) + emacs_abort (); + vw->MoveTo (x, y); + vw->ResizeTo (x1 - x, y1 - y); + vw->UnlockLooper (); +} + +void +BView_scroll_bar_update (void *sb, int portion, int whole, int position) +{ + BScrollBar *bar = (BScrollBar *) sb; + BMessage msg = BMessage (SCROLL_BAR_UPDATE); + BMessenger mr = BMessenger (bar); + msg.AddInt32 ("emacs:range", whole); + msg.AddInt32 ("emacs:units", position); + + mr.SendMessage (&msg); +} + +int +BScrollBar_default_size (int horizontal_p) +{ + return horizontal_p ? B_H_SCROLL_BAR_HEIGHT : B_V_SCROLL_BAR_WIDTH; +} + +void +BView_hide (void *view) +{ + BView *vw = (BView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->Hide (); + vw->UnlockLooper (); +} + +void +BView_show (void *view) +{ + BView *vw = (BView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->Show (); + vw->UnlockLooper (); +} + +void +BView_invalidate (void *view) +{ + BView *vw = (BView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->Invalidate (); + vw->UnlockLooper (); +} + +void +BView_draw_lock (void *view) +{ + EmacsView *vw = (EmacsView *) view; + if (vw->looper_locked_count) + { + vw->looper_locked_count++; + return; + } + BView *v = (BView *) find_appropriate_view_for_draw (vw); + if (!v->LockLooper ()) + emacs_abort (); + + if (v != vw && !vw->LockLooper ()) + emacs_abort (); + vw->looper_locked_count++; +} + +void +BView_draw_unlock (void *view) +{ + EmacsView *vw = (EmacsView *) view; + if (--vw->looper_locked_count) + return; + + BView *v = (BView *) find_appropriate_view_for_draw (view); + v->UnlockLooper (); + if (v != vw) + vw->UnlockLooper (); +} + +void +BWindow_center_on_screen (void *window) +{ + BWindow *w = (BWindow *) window; + w->CenterOnScreen (); +} + +void +BView_mouse_down (void *view, int x, int y) +{ + BView *vw = (BView *) view; + if (vw->LockLooper ()) + { + vw->MouseDown (BPoint (x, y)); + vw->UnlockLooper (); + } +} + +void +BView_mouse_up (void *view, int x, int y) +{ + BView *vw = (BView *) view; + if (vw->LockLooper ()) + { + vw->MouseUp (BPoint (x, y)); + vw->UnlockLooper (); + } +} + +void +BView_mouse_moved (void *view, int x, int y, uint32_t transit) +{ + BView *vw = (BView *) view; + if (vw->LockLooper ()) + { + vw->MouseMoved (BPoint (x, y), transit, NULL); + vw->UnlockLooper (); + } +} + +void +BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h) +{ + BBitmap *bmp = (BBitmap *) bitmap; + unsigned char *data = (unsigned char *) bmp->Bits (); + unsigned short *bts = (unsigned short *) bits; + + for (int i = 0; i < (h * (wd / 8)); i++) + { + *((unsigned short *) data) = reverse_fringe_byte (~bts[i]); + data += bmp->BytesPerRow (); + } +} + +void +BView_publish_scroll_bar (void *view, int x, int y, int width, int height) +{ + EmacsView *vw = (EmacsView *) view; + if (vw->LockLooper ()) + { + vw->sb_region.Include (BRect (x, y, x - 1 + width, + y - 1 + height)); + vw->UnlockLooper (); + } +} + +void +BView_forget_scroll_bar (void *view, int x, int y, int width, int height) +{ + EmacsView *vw = (EmacsView *) view; + if (vw->LockLooper ()) + { + vw->sb_region.Exclude (BRect (x, y, x - 1 + width, + y - 1 + height)); + vw->UnlockLooper (); + } +} + +int +BFont_family_count (void) +{ + return count_font_families (); +} + +void +BView_get_mouse (void *view, int *x, int *y) +{ + BPoint l; + BView *vw = (BView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->GetMouse (&l, NULL, 1); + vw->UnlockLooper (); + + *x = std::lrint (l.x); + *y = std::lrint (l.y); +} + +void +BView_convert_to_screen (void *view, int *x, int *y) +{ + BPoint l = BPoint (*x, *y); + BView *vw = (BView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->ConvertToScreen (&l); + vw->UnlockLooper (); + + *x = std::lrint (l.x); + *y = std::lrint (l.y); +} + +void +BView_convert_from_screen (void *view, int *x, int *y) +{ + BPoint l = BPoint (*x, *y); + BView *vw = (BView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->ConvertFromScreen (&l); + vw->UnlockLooper (); + + *x = std::lrint (l.x); + *y = std::lrint (l.y); +} + +void +BWindow_change_decoration (void *window, int decorate_p) +{ + BWindow *w = (BWindow *) window; + if (!w->LockLooper ()) + emacs_abort (); + if (decorate_p) + w->SetLook (B_TITLED_WINDOW_LOOK); + else + w->SetLook (B_NO_BORDER_WINDOW_LOOK); + w->UnlockLooper (); +} + +void +BWindow_set_tooltip_decoration (void *window) +{ + BWindow *w = (BWindow *) window; + if (!w->LockLooper ()) + emacs_abort (); + w->SetLook (B_BORDERED_WINDOW_LOOK); + w->SetFeel (B_FLOATING_APP_WINDOW_FEEL); + w->UnlockLooper (); +} + +void +BWindow_set_avoid_focus (void *window, int avoid_focus_p) +{ + BWindow *w = (BWindow *) window; + if (!w->LockLooper ()) + emacs_abort (); + + if (!avoid_focus_p) + w->SetFlags (w->Flags () & ~B_AVOID_FOCUS); + else + w->SetFlags (B_AVOID_FOCUS); + w->Sync (); + w->UnlockLooper (); +} + +void +BView_emacs_delete (void *view) +{ + EmacsView *vw = (EmacsView *) view; + if (!vw->LockLooper ()) + emacs_abort (); + vw->RemoveSelf (); + delete vw; +} + +uint32_t +haiku_current_workspace (void) +{ + return current_workspace (); +} + +uint32_t +BWindow_workspaces (void *window) +{ + return ((BWindow *) window)->Workspaces (); +} + +void * +BPopUpMenu_new (const char *name) +{ + BPopUpMenu *menu = new BPopUpMenu (name, false); + return menu; +} + +void +BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p, + bool marked_p) +{ + BMenu *m = (BMenu *) menu; + BMessage *msg; + if (ptr) + msg = new BMessage (); + BMenuItem *it = new BMenuItem (label, ptr ? msg : NULL); + it->SetTarget (m->Window ()); + it->SetEnabled (enabled_p); + it->SetMarked (marked_p); + if (ptr) + msg->AddPointer ("menuptr", ptr); + m->AddItem (it); +} + +void +BMenu_add_separator (void *menu) +{ + BMenu *m = (BMenu *) menu; + + m->AddSeparatorItem (); +} + +void * +BMenu_new_submenu (void *menu, const char *label, bool enabled_p) +{ + BMenu *m = (BMenu *) menu; + BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN); + mn->SetRadioMode (0); + BMenuItem *i = new BMenuItem (mn); + i->SetEnabled (enabled_p); + m->AddItem (i); + return mn; +} + +void * +BMenu_new_menu_bar_submenu (void *menu, const char *label) +{ + BMenu *m = (BMenu *) menu; + BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN); + mn->SetRadioMode (0); + BMenuItem *i = new BMenuItem (mn); + i->SetEnabled (1); + m->AddItem (i); + return mn; +} + +void * +BMenu_run (void *menu, int x, int y) +{ + BPopUpMenu *mn = (BPopUpMenu *) menu; + BMenuItem *it = mn->Go (BPoint (x, y)); + if (it) + { + BMessage *mg = it->Message (); + if (mg) + return (void *) mg->GetPointer ("menuptr"); + else + return NULL; + } + return NULL; +} + +void +BPopUpMenu_delete (void *menu) +{ + delete (BPopUpMenu *) menu; +} + +void * +BMenuBar_new (void *view) +{ + BView *vw = (BView *) view; + EmacsMenuBar *bar = new EmacsMenuBar (); + + if (!vw->LockLooper ()) + emacs_abort (); + vw->AddChild ((BView *) bar); + vw->UnlockLooper (); + + return bar; +} + +void +BMenuBar_delete (void *menubar) +{ + BView *vw = (BView *) menubar; + BView *p = vw->Parent (); + if (!p->LockLooper ()) + emacs_abort (); + vw->RemoveSelf (); + p->UnlockLooper (); + delete vw; +} + +void +BMenu_delete_all (void *menu) +{ + BMenu *mn = (BMenu *) menu; + mn->RemoveItems (0, mn->CountItems (), true); +} + +void +BMenu_delete_from (void *menu, int start, int count) +{ + BMenu *mn = (BMenu *) menu; + mn->RemoveItems (start, count, true); +} + +int +BMenu_count_items (void *menu) +{ + return ((BMenu *) menu)->CountItems (); +} + +void * +BMenu_item_at (void *menu, int idx) +{ + return ((BMenu *) menu)->ItemAt (idx); +} + +void +BMenu_item_set_label (void *item, const char *label) +{ + ((BMenuItem *) item)->SetLabel (label); +} + +void * +BMenu_item_get_menu (void *item) +{ + return ((BMenuItem *) item)->Submenu (); +} + +void +haiku_ring_bell (void) +{ + beep (); +} + +void * +BAlert_new (const char *text, enum haiku_alert_type type) +{ + return new BAlert (NULL, text, NULL, NULL, NULL, B_WIDTH_AS_USUAL, + (enum alert_type) type); +} + +void * +BAlert_add_button (void *alert, const char *text) +{ + BAlert *al = (BAlert *) alert; + al->AddButton (text); + return al->ButtonAt (al->CountButtons () - 1); +} + +int32_t +BAlert_go (void *alert) +{ + return ((BAlert *) alert)->Go (); +} + +void +BButton_set_enabled (void *button, int enabled_p) +{ + ((BButton *) button)->SetEnabled (enabled_p); +} + +void +BView_set_tooltip (void *view, const char *tooltip) +{ + ((BView *) view)->SetToolTip (tooltip); +} + +void +BAlert_delete (void *alert) +{ + delete (BAlert *) alert; +} + +void +BScreen_res (double *rrsx, double *rrsy) +{ + BScreen s (B_MAIN_SCREEN_ID); + if (!s.IsValid ()) + emacs_abort (); + monitor_info i; + + if (s.GetMonitorInfo (&i) == B_OK) + { + *rrsx = (double) i.width / (double) 2.54; + *rrsy = (double) i.height / (double) 2.54; + } + else + { + *rrsx = 72.27; + *rrsy = 72.27; + } +} + +void +EmacsWindow_parent_to (void *window, void *other_window) +{ + EmacsWindow *w = (EmacsWindow *) window; + if (!w->LockLooper ()) + emacs_abort (); + w->ParentTo ((EmacsWindow *) other_window); + w->UnlockLooper (); +} + +void +EmacsWindow_unparent (void *window) +{ + EmacsWindow *w = (EmacsWindow *) window; + if (!w->LockLooper ()) + emacs_abort (); + w->UnparentAndUnlink (); + w->UnlockLooper (); +} + +void +be_get_version_string (char *version, int len) +{ + std::strncpy (version, "Unknown Haiku release", len - 1); + BPath path; + if (find_directory (B_BEOS_LIB_DIRECTORY, &path) == B_OK) + { + path.Append ("libbe.so"); + + BAppFileInfo appFileInfo; + version_info versionInfo; + BFile file; + if (file.SetTo (path.Path (), B_READ_ONLY) == B_OK + && appFileInfo.SetTo (&file) == B_OK + && appFileInfo.GetVersionInfo (&versionInfo, + B_APP_VERSION_KIND) == B_OK + && versionInfo.short_info[0] != '\0') + std::strncpy (version, versionInfo.short_info, len - 1); + } +} + +int +be_get_display_planes (void) +{ + color_space space = dpy_color_space; + if (space == B_NO_COLOR_SPACE) + { + BScreen screen; /* This is actually a very slow operation. */ + space = dpy_color_space = screen.ColorSpace (); + } + + if (space == B_RGB32 || space == B_RGB24) + return 24; + if (space == B_RGB16) + return 16; + if (space == B_RGB15) + return 15; + if (space == B_CMAP8) + return 8; + + emacs_abort (); /* https://www.haiku-os.org/docs/api/classBScreen.html + says a valid screen can't be anything else. */ + return -1; +} + +int +be_get_display_color_cells (void) +{ + color_space space = dpy_color_space; + if (space == B_NO_COLOR_SPACE) + { + BScreen screen; + space = dpy_color_space = screen.ColorSpace (); + } + + if (space == B_RGB32 || space == B_RGB24) + return 1677216; + if (space == B_RGB16) + return 65536; + if (space == B_RGB15) + return 32768; + if (space == B_CMAP8) + return 256; + + emacs_abort (); + return -1; +} + +void +be_warp_pointer (int x, int y) +{ + /* We're not supposed to use the following function without a + BWindowScreen object, but in Haiku nothing actually prevents us + from doing so. */ + + set_mouse_position (x, y); +} + +void +EmacsWindow_move_weak_child (void *window, void *child, int xoff, int yoff) +{ + EmacsWindow *w = (EmacsWindow *) window; + EmacsWindow *c = (EmacsWindow *) child; + + if (!w->LockLooper ()) + emacs_abort (); + w->MoveChild (c, xoff, yoff, 1); + w->UnlockLooper (); +} + +void * +find_appropriate_view_for_draw (void *vw) +{ + BView *v = (BView *) vw; + EmacsView *ev = dynamic_cast(v); + if (!ev) + return v; + + return ev->offscreen_draw_view ? ev->offscreen_draw_view : vw; +} + +void +EmacsView_set_up_double_buffering (void *vw) +{ + EmacsView *view = (EmacsView *) vw; + if (!view->LockLooper ()) + emacs_abort (); + if (view->offscreen_draw_view) + { + view->UnlockLooper (); + return; + } + view->SetUpDoubleBuffering (); + view->UnlockLooper (); +} + +void +EmacsView_flip_and_blit (void *vw) +{ + EmacsView *view = (EmacsView *) vw; + if (!view->offscreen_draw_view) + return; + if (!view->LockLooper ()) + emacs_abort (); + view->FlipBuffers (); + view->UnlockLooper (); +} + +void +EmacsView_disable_double_buffering (void *vw) +{ + EmacsView *view = (EmacsView *) vw; + if (!view->LockLooper ()) + emacs_abort (); + view->TearDownDoubleBuffering (); + view->UnlockLooper (); +} + +int +EmacsView_double_buffered_p (void *vw) +{ + EmacsView *view = (EmacsView *) vw; + if (!view->LockLooper ()) + emacs_abort (); + int db_p = !!view->offscreen_draw_view; + view->UnlockLooper (); + return db_p; +} diff --git a/src/haiku_support.h b/src/haiku_support.h new file mode 100644 index 0000000000..bade33496f --- /dev/null +++ b/src/haiku_support.h @@ -0,0 +1,916 @@ +/* Haiku window system support. Hey Emacs, this is -*- C++ -*- + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#ifndef _HAIKU_SUPPORT_H +#define _HAIKU_SUPPORT_H + +#include + +#ifdef HAVE_FREETYPE +#include +#include +#include FT_FREETYPE_H +#include FT_SIZES_H +#endif + +enum haiku_cursor + { + CURSOR_ID_NO_CURSOR = 12, + CURSOR_ID_RESIZE_NORTH = 15, + CURSOR_ID_RESIZE_EAST = 16, + CURSOR_ID_RESIZE_SOUTH = 17, + CURSOR_ID_RESIZE_WEST = 18, + CURSOR_ID_RESIZE_NORTH_EAST = 19, + CURSOR_ID_RESIZE_NORTH_WEST = 20, + CURSOR_ID_RESIZE_SOUTH_EAST = 21, + CURSOR_ID_RESIZE_SOUTH_WEST = 22, + CURSOR_ID_RESIZE_NORTH_SOUTH = 23, + CURSOR_ID_RESIZE_EAST_WEST = 24, + CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST = 25, + CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST = 26 + }; + +enum haiku_alert_type + { + HAIKU_EMPTY_ALERT = 0, + HAIKU_INFO_ALERT, + HAIKU_IDEA_ALERT, + HAIKU_WARNING_ALERT, + HAIKU_STOP_ALERT + }; + +enum haiku_event_type + { + QUIT_REQUESTED, + FRAME_RESIZED, + FRAME_EXPOSED, + KEY_DOWN, + KEY_UP, + ACTIVATION, + MOUSE_MOTION, + BUTTON_DOWN, + BUTTON_UP, + ICONIFICATION, + MOVE_EVENT, + SCROLL_BAR_VALUE_EVENT, + SCROLL_BAR_DRAG_EVENT, + WHEEL_MOVE_EVENT, + MENU_BAR_RESIZE, + MENU_BAR_OPEN, + MENU_BAR_SELECT_EVENT, + MENU_BAR_CLOSE + }; + +struct haiku_quit_requested_event +{ + void *window; +}; + +struct haiku_resize_event +{ + void *window; + float px_heightf; + float px_widthf; +}; + +struct haiku_expose_event +{ + void *window; + int x; + int y; + int width; + int height; +}; + +#define HAIKU_MODIFIER_ALT (1) +#define HAIKU_MODIFIER_CTRL (1 << 1) +#define HAIKU_MODIFIER_SHIFT (1 << 2) + +struct haiku_key_event +{ + void *window; + int modifiers; + uint32_t mb_char; + uint32_t unraw_mb_char; + short kc; +}; + +struct haiku_activation_event +{ + void *window; + int activated_p; +}; + +struct haiku_mouse_motion_event +{ + void *window; + bool just_exited_p; + int x; + int y; + uint32_t be_code; +}; + +struct haiku_button_event +{ + void *window; + int btn_no; + int modifiers; + int x; + int y; +}; + +struct haiku_iconification_event +{ + void *window; + int iconified_p; +}; + +struct haiku_move_event +{ + void *window; + int x; + int y; +}; + +struct haiku_wheel_move_event +{ + void *window; + int modifiers; + float delta_x; + float delta_y; +}; + +struct haiku_menu_bar_select_event +{ + void *window; + void *ptr; +}; + +#define FSPEC_FAMILY 1 +#define FSPEC_STYLE (1 << 1) +#define FSPEC_SLANT (1 << 2) +#define FSPEC_WEIGHT (1 << 3) +#define FSPEC_SPACING (1 << 4) +#define FSPEC_WANTED (1 << 5) +#define FSPEC_NEED_ONE_OF (1 << 6) +#define FSPEC_WIDTH (1 << 7) +#define FSPEC_LANGUAGE (1 << 8) + +typedef char haiku_font_family_or_style[64]; + +enum haiku_font_slant + { + NO_SLANT = -1, + SLANT_OBLIQUE, + SLANT_REGULAR, + SLANT_ITALIC + }; + +enum haiku_font_width + { + NO_WIDTH = -1, + ULTRA_CONDENSED, + EXTRA_CONDENSED, + CONDENSED, + SEMI_CONDENSED, + NORMAL_WIDTH, + SEMI_EXPANDED, + EXPANDED, + EXTRA_EXPANDED, + ULTRA_EXPANDED + }; + +enum haiku_font_language + { + LANGUAGE_CN, + LANGUAGE_KO, + LANGUAGE_JP, + MAX_LANGUAGE /* This isn't a language. */ + }; + +struct haiku_font_pattern +{ + int specified; + struct haiku_font_pattern *next; + /* The next two fields are only temporarily used during the font + discovery process! Do not rely on it being correct outside + BFont_find. */ + struct haiku_font_pattern *last; + struct haiku_font_pattern *next_family; + haiku_font_family_or_style family; + haiku_font_family_or_style style; + int weight; + int mono_spacing_p; + int want_chars_len; + int need_one_of_len; + enum haiku_font_slant slant; + enum haiku_font_width width; + enum haiku_font_language language; + uint32_t *wanted_chars; + uint32_t *need_one_of; + + int oblique_seen_p; +}; + +struct haiku_scroll_bar_value_event +{ + void *scroll_bar; + int position; +}; + +struct haiku_scroll_bar_drag_event +{ + void *scroll_bar; + int dragging_p; +}; + +struct haiku_menu_bar_resize_event +{ + void *window; + int width; + int height; +}; + +struct haiku_menu_bar_state_event +{ + void *window; +}; + +#define HAIKU_THIN 0 +#define HAIKU_ULTRALIGHT 20 +#define HAIKU_EXTRALIGHT 40 +#define HAIKU_LIGHT 50 +#define HAIKU_SEMI_LIGHT 75 +#define HAIKU_REGULAR 100 +#define HAIKU_SEMI_BOLD 180 +#define HAIKU_BOLD 200 +#define HAIKU_EXTRA_BOLD 205 +#define HAIKU_ULTRA_BOLD 210 + +#ifdef __cplusplus +extern "C" +{ +#endif +#include +#include + +#ifdef __cplusplus + typedef void *haiku; + + extern void + haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel); + + extern unsigned long + haiku_get_pixel (haiku bitmap, int x, int y); +#endif + + /* The port used to send messages from Emacs to the application + thread. */ + extern port_id port_emacs_to_application; + /* The port used to send messages from the application thread to + Emacs. */ + extern port_id port_application_to_emacs; + + extern void haiku_io_init (void); + extern void haiku_io_init_in_app_thread (void); + + /* Read the size of the next message into len, returning -1 if the + query fails or there is no next message */ + extern void + haiku_read_size (ssize_t *len); + + /* Read the next message into buf, putting its type into type, + assuming the message is len long. Return 0 if successful and + -1 if the read fails. */ + extern int + haiku_read (enum haiku_event_type *type, void *buf, ssize_t len); + + /* Write a message with type type into buf. */ + extern int + haiku_write (enum haiku_event_type type, void *buf); + + /* Convert RGB32 color color from RGB color space to its + HSL components pointed to by h, s and l. */ + extern void + rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l); + + /* Ditto, but the other way round */ + extern void + hsl_color_rgb (double h, double s, double l, uint32_t *rgb); + + /* Create new bitmap in RGB32 format */ + extern void * + BBitmap_new (int width, int height, int mono_p); + + /* Take bitmap, a reference to a BBitmap, and return a pointer to + its data, in RGB32 format */ + extern void * + BBitmap_data (void *bitmap); + + /* Convert bitmap if required, placing the new bitmap in new_bitmap, + and return non-null if bitmap was successfully converted. + Bitmaps should be freed with `BBitmap_free' */ + extern int + BBitmap_convert (void *bitmap, void **new_bitmap); + + /* Delete bitmap */ + extern void + BBitmap_free (void *bitmap); + + /* Retrieve the dimensions of bitmap */ + extern void + BBitmap_dimensions (void *bitmap, int *left, int *top, + int *right, int *bottom, int32_t *bytes_per_row, + int *mono_p); + + /* Set up an application and return it. If starting the application + thread fails, abort Emacs */ + extern void * + BApplication_setup (void); + + /* Set up and return a window with its view put in VIEW */ + extern void * + BWindow_new (void *view); + + /* Delete a window */ + extern void + BWindow_quit (void *window); + + /* Set window offset to X, Y */ + extern void + BWindow_set_offset (void *window, int x, int y); + + /* Iconify window */ + extern void + BWindow_iconify (void *window); + + /* Show or hide window */ + extern void + BWindow_set_visible (void *window, int visible_p); + + /* Open the default monospace font */ + extern void * + BFont_open_default (double size, int plain_or_bold_or_fixed); + + /* Close a font */ + extern void + BFont_close (void *font); + + /* Compute font data */ + extern void + BFont_dat (void *font, int *px_size, int *min_width, int *max_width, + int *avg_width, int *height, int *space_width, int *ascent, + int *descent, int *underline_position, int *underline_thickness); + + /* Return non-null if font contains chr, a Unicode code-point */ + extern int + BFont_have_char_p (void *font, int32_t chr); + + /* Compute bounds for mb_str, a character in multibyte encoding, + used with font. The width (in pixels) is returned in advance, + the left bearing in lb, and the right bearing in rb */ + extern void + BFont_char_bounds (void *font, const char *mb_str, int *advance, + int *lb, int *rb); + + /* The same, but for a variable amount of chars. */ + extern void + BFont_nchar_bounds (void *font, const char *mb_str, int *advance, + int *lb, int *rb, int32_t n); + + /* Change the title of window to the multibyte string title */ + extern void + BWindow_retitle (void *window, const char *title); + + /* Resize window to width by height */ + extern void + BWindow_resize (void *window, int width, int height); + + /* Activate window */ + extern void + BWindow_activate (void *window); + + /* Drawing functions */ + extern void + BView_StartClip (void *view); + + extern void + BView_EndClip (void *view); + + extern void + BView_SetHighColor (void *view, uint32_t color); + + extern void + BView_SetLowColor (void *view, uint32_t color); + + extern void + BView_SetPenSize (void *view, int u); + + extern void + BView_SetFont (void *view, void *font); + + extern void + BView_MovePenTo (void *view, int x, int y); + + extern void + BView_DrawString (void *view, const char *chr, ptrdiff_t len); + + extern void + BView_DrawChar (void *view, char chr); + + extern void + BView_Draw (void *view, int x, int y, int width, int height); + + extern void + BView_FillRectangle (void *view, int x, int y, int width, int height); + + extern void + BView_FillRectangleAbs (void *view, int x, int y, int x1, int y1); + + extern void + BView_StrokeRectangle (void *view, int x, int y, int width, int height); + + extern void + BView_SetViewColor (void *view, uint32_t color); + + extern void + BView_ClipToRect (void *view, int x, int y, int width, int height); + + extern void + BView_ClipToInverseRect (void *view, int x, int y, int width, int height); + + extern void + BView_StrokeLine (void *view, int sx, int sy, int tx, int ty); + + extern void + BView_CopyBits (void *view, int x, int y, int width, int height, + int tox, int toy, int towidth, int toheight); + + extern void + BView_DrawBitmap (void *view, void *bitmap, int x, int y, + int width, int height, int vx, int vy, int vwidth, + int vheight); + + extern void + BView_DrawBitmapWithEraseOpAbs (void *view, void *bitmap, int x, int y, + int width, int height, int vx, int vy, int vwidth, + int vheight); + + extern void + BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x, + int y, int width, int height); + + /* Potential Haiku bug: the Be Book says B_OP_ERASE ought to treat + monochrome BBitmaps as patterns, but that isn't the case here, so + we have to do everything manually. */ + extern void + BView_DrawFringeBitmap (void *src, void *view, + int x, int y, int width, int height, + uint32_t color); + + extern void + BView_DrawMask (void *src, void *view, + int x, int y, int width, int height, + int vx, int vy, int vwidth, int vheight, + uint32_t color); + + extern void * + BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color, + double rot, int desw, int desh); + + extern void + BView_EnableWindowUpdates (void *view); + + extern void + BView_DisableWindowUpdates (void *view); + + extern void + BView_BeginLayer (void *view, float opacity); + + extern void + BView_EndLayer (void *view); + + /* Return the pixel dimensions of the main screen in width and height */ + extern void + BScreen_px_dim (int *width, int *height); + + /* Resize view to width, height */ + extern void + BView_resize_to (void *view, int width, int height); + + /* Functions for creating and freeing cursors */ + extern void * + BCursor_create_default (void); + + extern void * + BCursor_from_id (enum haiku_cursor cursor); + + extern void * + BCursor_create_i_beam (void); + + extern void * + BCursor_create_progress_cursor (void); + + extern void * + BCursor_create_grab (void); + + /* Delete cursor */ + extern void + BCursor_delete (void *cursor); + + /* Set view's cursor to cursor */ + extern void + BView_set_view_cursor (void *view, void *cursor); + + /* Flush window's connection to the App Server */ + extern void + BWindow_Flush (void *window); + + /* Map the keycode kc, storing the result in code and 1 in + non_ascii_p if it should be used */ + extern void + BMapKey (uint32_t kc, int *non_ascii_p, unsigned *code); + + /* Make a scrollbar, attach it to view's window, and return it */ + extern void * + BScrollBar_make_for_view (void *view, int horizontal_p, + int x, int y, int x1, int y1, + void *scroll_bar_ptr); + + /* Delete sb, a scrollbar */ + extern void + BScrollBar_delete (void *sb); + + /* Move view's frame to x, y, x1, y1 */ + extern void + BView_move_frame (void *view, int x, int y, int x1, int y1); + + /* Update sb with portion, whole and position */ + extern void + BView_scroll_bar_update (void *sb, int portion, int whole, int position); + + /* Return the default scrollbar size */ + extern int + BScrollBar_default_size (int horizontal_p); + + /* Make view invisible */ + extern void + BView_hide (void *view); + + /* Make view visible */ + extern void + BView_show (void *view); + + /* Invalidate view */ + extern void + BView_invalidate (void *view); + + /* Lock view. This is usually faster than calling LockLooper + directly. */ + extern void + BView_draw_lock (void *view); + + /* Ditto, but unlock instead. */ + extern void + BView_draw_unlock (void *view); + + /* Center window on its screen */ + extern void + BWindow_center_on_screen (void *window); + + /* Tell view that the mouse has moved to x by y */ + extern void + BView_mouse_moved (void *view, int x, int y, uint32_t transit); + + /* Tell view it has been clicked at x by y */ + extern void + BView_mouse_down (void *view, int x, int y); + + /* Tell view it has been released at x by y */ + extern void + BView_mouse_up (void *view, int x, int y); + + /* Import bits into bitmap using the B_GRAY1 colorspace */ + extern void + BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h); + + /* Return the amount of font families */ + extern int + BFont_family_count (void); + + /* Query the font family at IDX, returning non-0 on failure */ + extern int + BFont_family (int idx, char *f, int *fixed_p); + + /* Return non-0 if the family contains style */ + extern int + BFont_family_has_style_p (haiku_font_family_or_style family, + haiku_font_family_or_style style); + + /* Create a font */ + extern void * + BFont_new (void); + + /* Set font's family and style to FAMILY and STYLE respectively, + returning non-0 on failure. */ + extern int + BFont_set_family_and_style (void *font, haiku_font_family_or_style family, + haiku_font_family_or_style style); + + /* Set FONT's family along with its ITALIC and BOLD faces */ + extern int + BFont_set_family_face (void *font, haiku_font_family_or_style family, + int italic_p, int bold_p); + + /* Delete every element of the font pattern PT */ + extern void + haiku_font_pattern_free (struct haiku_font_pattern *pt); + + /* Find all fonts matching the font pattern PT */ + extern struct haiku_font_pattern * + BFont_find (struct haiku_font_pattern *pt); + + /* Find and open a font matching the pattern PAT, which must have + its family set */ + extern int + BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size); + + /* Query the family of the default fixed font */ + extern void + BFont_populate_fixed_family (struct haiku_font_pattern *ptn); + + /* Ditto, but with the plain family */ + extern void + BFont_populate_plain_family (struct haiku_font_pattern *ptn); + + /* Make a scrollbar at x, y known to the view */ + extern void + BView_publish_scroll_bar (void *view, int x, int y, int width, int height); + + /* Forget the scrollbar at x, y by width, height */ + extern void + BView_forget_scroll_bar (void *view, int x, int y, int width, int height); + + /* Place the current coordinates of the mouse, relative to view, at x and y */ + extern void + BView_get_mouse (void *view, int *x, int *y); + + /* Perform an in-place conversion of x and y from view's coordinate + system to its screen's coordinate system */ + extern void + BView_convert_to_screen (void *view, int *x, int *y); + + /* Do the same, but from the screen coordinate system to the view's. */ + extern void + BView_convert_from_screen (void *view, int *x, int *y); + + /* Decorate or undecorate window depending on decorate_p */ + extern void + BWindow_change_decoration (void *window, int decorate_p); + + /* Decorate window appropriately for use as a tooltip */ + extern void + BWindow_set_tooltip_decoration (void *window); + + /* Set B_AVOID_FOCUS on window if avoid_focus_p is non-nil, or clear + it otherwise */ + extern void + BWindow_set_avoid_focus (void *window, int avoid_focus_p); + + /* Delete the frame view view */ + extern void + BView_emacs_delete (void *view); + + /* Begin a view transaction, during which drawing operations will + not be displayed */ + extern void + BView_BeginTransaction (void *view); + + /* End a view transaction and flush the view */ + extern void + BView_EndTransaction (void *view); + + /* Return the current workspace */ + extern uint32_t + haiku_current_workspace (void); + + /* Return a bitmask consisting of workspaces window is on */ + extern uint32_t + BWindow_workspaces (void *window); + + /* Create a popup menu */ + extern void * + BPopUpMenu_new (const char *name); + + /* Add an item to the menu */ + extern void + BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p, + bool marked_p); + + /* Add a separator to the menu */ + extern void + BMenu_add_separator (void *menu); + + /* Create a submenu and attach it to menu */ + extern void * + BMenu_new_submenu (void *menu, const char *label, bool enabled_p); + + /* Create a submenu that notifies Emacs upon opening */ + extern void * + BMenu_new_menu_bar_submenu (void *menu, const char *label); + + /* Count items in menu */ + extern int + BMenu_count_items (void *menu); + + /* Find the menu item at idx */ + extern void * + BMenu_item_at (void *menu, int idx); + + /* Run menu, waiting for it to close, and returning a pointer to the + data of the selected item (if one exists), or nil. X, Y should + be in the screen coordinate system */ + extern void * + BMenu_run (void *menu, int x, int y); + + /* Delete the entire menu hierarchy of menu, and then delete menu + itself */ + extern void + BPopUpMenu_delete (void *menu); + + /* Create a menubar, attach it to view, and return it */ + extern void * + BMenuBar_new (void *view); + + /* Delete all items from menu */ + extern void + BMenu_delete_all (void *menu); + + /* Delete menubar along with all subitems */ + extern void + BMenuBar_delete (void *menubar); + + /* Set item's label to label */ + extern void + BMenu_item_set_label (void *item, const char *label); + + /* Get item's menu */ + extern void * + BMenu_item_get_menu (void *item); + + /* Delete count items from menu starting from start */ + extern void + BMenu_delete_from (void *menu, int start, int count); + + /* Emit a beep noise */ + extern void + haiku_ring_bell (void); + + /* Create a BAlert with text */ + extern void * + BAlert_new (const char *text, enum haiku_alert_type type); + + /* Add a button to alert and return the button */ + extern void * + BAlert_add_button (void *alert, const char *text); + + /* Run the alert, returning the number of the button that was + selected, or -1 if no button was selected before the alert was + closed */ + extern int32_t + BAlert_go (void *alert); + + /* Enable or disable button depending on enabled_p */ + extern void + BButton_set_enabled (void *button, int enabled_p); + + /* Set view's tooltip to tooltip */ + extern void + BView_set_tooltip (void *view, const char *tooltip); + + /* Delete alert */ + extern void + BAlert_delete (void *alert); + +#ifdef HAVE_FREETYPE + /* Render GLYPHS in FACE */ + extern void + BView_FT_render_glyphs (FT_Face face, unsigned int *codes, + int len, uint32_t color, int x, int y, + void *view, int width, int height, + int sx, int sy); +#endif + + /* Place the resolution of the monitor in DPI in RSSX and RSSY. */ + extern void + BScreen_res (double *rrsx, double *rrsy); + + /* Add WINDOW to OTHER_WINDOW's subset and parent it to OTHER_WINDOW. */ + extern void + EmacsWindow_parent_to (void *window, void *other_window); + + /* Unparent WINDOW. */ + extern void + EmacsWindow_unparent (void *window); + + extern int + BFont_string_width (void *font, const char *utf8); + + /* Place text describing the current version of Haiku in VERSION, + which should be a buffer LEN bytes wide. */ + extern void + be_get_version_string (char *version, int len); + + /* Return the amount of color planes in the current display. */ + extern int + be_get_display_planes (void); + + /* Return the amount of colors the display can handle. */ + extern int + be_get_display_color_cells (void); + + /* Warp the pointer to X by Y. */ + extern void + be_warp_pointer (int x, int y); + + /* Update the position of CHILD in WINDOW without actually moving it. */ + extern void + EmacsWindow_move_weak_child (void *window, void *child, int xoff, int yoff); + + /* Set up double buffering for VW. */ + extern void + EmacsView_set_up_double_buffering (void *vw); + + /* Disable double buffering for VW. */ + extern void + EmacsView_disable_double_buffering (void *vw); + + /* Flip and invalidate the view VW. */ + extern void + EmacsView_flip_and_blit (void *vw); + + /* Return non-0 if VW is double-buffered. */ + extern int + EmacsView_double_buffered_p (void *vw); + +#ifdef __cplusplus + /* Find an appropriate view to draw onto. */ + extern void * + find_appropriate_view_for_draw (void *vw); +} +#endif /* _cplusplus */ + +/* Borrowed from X.Org keysymdef.h */ +#define XK_BackSpace 0xff08 /* Back space, back char */ +#define XK_Tab 0xff09 +#define XK_Linefeed 0xff0a /* Linefeed, LF */ +#define XK_Clear 0xff0b +#define XK_Return 0xff0d /* Return, enter */ +#define XK_Pause 0xff13 /* Pause, hold */ +#define XK_Scroll_Lock 0xff14 +#define XK_Sys_Req 0xff15 +#define XK_Escape 0xff1b +#define XK_Delete 0xffff /* Delete, rubout */ +#define XK_Home 0xff50 +#define XK_Left 0xff51 /* Move left, left arrow */ +#define XK_Up 0xff52 /* Move up, up arrow */ +#define XK_Right 0xff53 /* Move right, right arrow */ +#define XK_Down 0xff54 /* Move down, down arrow */ +#define XK_Prior 0xff55 /* Prior, previous */ +#define XK_Page_Up 0xff55 +#define XK_Next 0xff56 /* Next */ +#define XK_Page_Down 0xff56 +#define XK_End 0xff57 /* EOL */ +#define XK_Begin 0xff58 /* BOL */ +#define XK_Select 0xff60 /* Select, mark */ +#define XK_Print 0xff61 +#define XK_Execute 0xff62 /* Execute, run, do */ +#define XK_Insert 0xff63 /* Insert, insert here */ +#define XK_Undo 0xff65 +#define XK_Redo 0xff66 /* Redo, again */ +#define XK_Menu 0xff67 +#define XK_Find 0xff68 /* Find, search */ +#define XK_Cancel 0xff69 /* Cancel, stop, abort, exit */ +#define XK_Help 0xff6a /* Help */ +#define XK_Break 0xff6b +#define XK_Mode_switch 0xff7e /* Character set switch */ +#define XK_script_switch 0xff7e /* Alias for mode_switch */ +#define XK_Num_Lock 0xff7f +#define XK_F1 0xffbe + +#endif /* _HAIKU_SUPPORT_H_ */ diff --git a/src/haikufns.c b/src/haikufns.c new file mode 100644 index 0000000000..66dd3afbfa --- /dev/null +++ b/src/haikufns.c @@ -0,0 +1,2190 @@ +/* Haiku window system support + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include + +#include "lisp.h" +#include "frame.h" +#include "blockinput.h" +#include "termchar.h" +#include "font.h" +#include "keyboard.h" +#include "buffer.h" +#include "dispextern.h" + +#include "haikugui.h" +#include "haikuterm.h" +#include "haiku_support.h" +#include "termhooks.h" + +#define RGB_TO_ULONG(r, g, b) \ + (((r) << 16) | ((g) << 8) | (b)); +#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) +#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) +#define BLUE_FROM_ULONG(color) ((color) & 0xff) + +/* The frame of the currently visible tooltip. */ +static Lisp_Object tip_frame; + +/* The window-system window corresponding to the frame of the + currently visible tooltip. */ +static Window tip_window; + +/* A timer that hides or deletes the currently visible tooltip when it + fires. */ +static Lisp_Object tip_timer; + +/* STRING argument of last `x-show-tip' call. */ +static Lisp_Object tip_last_string; + +/* Normalized FRAME argument of last `x-show-tip' call. */ +static Lisp_Object tip_last_frame; + +/* PARMS argument of last `x-show-tip' call. */ +static Lisp_Object tip_last_parms; + +static void +haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval); +static void +haiku_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name); + +static ptrdiff_t image_cache_refcount; + +static Lisp_Object +get_geometry_from_preferences (struct haiku_display_info *dpyinfo, + Lisp_Object parms) +{ + struct { + const char *val; + const char *cls; + Lisp_Object tem; + } r[] = { + { "width", "Width", Qwidth }, + { "height", "Height", Qheight }, + { "left", "Left", Qleft }, + { "top", "Top", Qtop }, + }; + + int i; + for (i = 0; i < ARRAYELTS (r); ++i) + { + if (NILP (Fassq (r[i].tem, parms))) + { + Lisp_Object value + = gui_display_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls, + RES_TYPE_NUMBER); + if (! EQ (value, Qunbound)) + parms = Fcons (Fcons (r[i].tem, value), parms); + } + } + + return parms; +} + +void +haiku_change_tool_bar_height (struct frame *f, int height) +{ + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TOOL_BAR_HEIGHT (f); + int lines = (height + unit - 1) / unit; + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + + /* Make sure we redisplay all windows in this frame. */ + fset_redisplay (f); + + FRAME_TOOL_BAR_HEIGHT (f) = height; + FRAME_TOOL_BAR_LINES (f) = lines; + store_frame_param (f, Qtool_bar_lines, make_fixnum (lines)); + + if (FRAME_HAIKU_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0) + { + clear_frame (f); + clear_current_matrices (f); + } + + if ((height < old_height) && WINDOWP (f->tool_bar_window)) + clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); + + if (!f->tool_bar_resized) + { + /* As long as tool_bar_resized is false, effectively try to change + F's native height. */ + if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), + 1, false, Qtool_bar_lines); + else + adjust_frame_size (f, -1, -1, 4, false, Qtool_bar_lines); + + f->tool_bar_resized = f->tool_bar_redisplayed; + } + else + /* Any other change may leave the native size of F alone. */ + adjust_frame_size (f, -1, -1, 3, false, Qtool_bar_lines); + + /* adjust_frame_size might not have done anything, garbage frame + here. */ + adjust_frame_glyphs (f); + SET_FRAME_GARBAGED (f); + + if (FRAME_HAIKU_WINDOW (f)) + haiku_clear_under_internal_border (f); +} + +void +haiku_change_tab_bar_height (struct frame *f, int height) +{ + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TAB_BAR_HEIGHT (f); + int lines = (height + unit - 1) / unit; + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + + /* Make sure we redisplay all windows in this frame. */ + fset_redisplay (f); + + /* Recalculate tab bar and frame text sizes. */ + FRAME_TAB_BAR_HEIGHT (f) = height; + FRAME_TAB_BAR_LINES (f) = lines; + store_frame_param (f, Qtab_bar_lines, make_fixnum (lines)); + + if (FRAME_HAIKU_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0) + { + clear_frame (f); + clear_current_matrices (f); + } + + if ((height < old_height) && WINDOWP (f->tab_bar_window)) + clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix); + + if (!f->tab_bar_resized) + { + /* As long as tab_bar_resized is false, effectively try to change + F's native height. */ + if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), + 1, false, Qtab_bar_lines); + else + adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines); + + f->tab_bar_resized = f->tab_bar_redisplayed; + } + else + /* Any other change may leave the native size of F alone. */ + adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines); + + /* adjust_frame_size might not have done anything, garbage frame + here. */ + adjust_frame_glyphs (f); + SET_FRAME_GARBAGED (f); + if (FRAME_HAIKU_WINDOW (f)) + haiku_clear_under_internal_border (f); +} + +static void +haiku_set_no_focus_on_map (struct frame *f, Lisp_Object value, + Lisp_Object oldval) +{ + if (!EQ (value, oldval)) + FRAME_NO_FOCUS_ON_MAP (f) = !NILP (value); +} + +static void +haiku_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) +{ + int nlines; + + /* Treat tool bars like menu bars. */ + if (FRAME_MINIBUF_ONLY_P (f)) + return; + + /* Use VALUE only if an int >= 0. */ + if (RANGED_FIXNUMP (0, value, INT_MAX)) + nlines = XFIXNAT (value); + else + nlines = 0; + + haiku_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); +} + +static void +haiku_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) +{ + int olines = FRAME_TAB_BAR_LINES (f); + int nlines; + + /* Treat tab bars like menu bars. */ + if (FRAME_MINIBUF_ONLY_P (f)) + return; + + /* Use VALUE only if an int >= 0. */ + if (RANGED_FIXNUMP (0, value, INT_MAX)) + nlines = XFIXNAT (value); + else + nlines = 0; + + if (nlines != olines && (olines == 0 || nlines == 0)) + haiku_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); +} + + +int +haiku_get_color (const char *name, Emacs_Color *color) +{ + unsigned short r16, g16, b16; + Lisp_Object tem; + + if (parse_color_spec (name, &r16, &g16, &b16)) + { + color->pixel = RGB_TO_ULONG (r16 / 256, g16 / 256, b16 / 256); + color->red = r16; + color->green = g16; + color->blue = b16; + return 0; + } + else + { + block_input (); + eassert (x_display_list && !NILP (x_display_list->color_map)); + tem = x_display_list->color_map; + for (; CONSP (tem); tem = XCDR (tem)) + { + Lisp_Object col = XCAR (tem); + if (CONSP (col) && !xstrcasecmp (SSDATA (XCAR (col)), name)) + { + int32_t clr = XFIXNUM (XCDR (col)); + color->pixel = clr; + color->red = RED_FROM_ULONG (clr) * 257; + color->green = GREEN_FROM_ULONG (clr) * 257; + color->blue = BLUE_FROM_ULONG (clr) * 257; + unblock_input (); + return 0; + } + } + + unblock_input (); + } + + return 1; +} + +static struct haiku_display_info * +haiku_display_info_for_name (Lisp_Object name) +{ + CHECK_STRING (name); + + if (!NILP (Fstring_equal (name, build_string ("be")))) + { + if (!x_display_list) + return x_display_list; + + error ("Be windowing not initialized"); + } + + error ("Be displays can only be named \"be\""); +} + +static struct haiku_display_info * +check_haiku_display_info (Lisp_Object object) +{ + struct haiku_display_info *dpyinfo = NULL; + + if (NILP (object)) + { + struct frame *sf = XFRAME (selected_frame); + + if (FRAME_HAIKU_P (sf) && FRAME_LIVE_P (sf)) + dpyinfo = FRAME_DISPLAY_INFO (sf); + else if (x_display_list) + dpyinfo = x_display_list; + else + error ("Be windowing not present"); + } + else if (TERMINALP (object)) + { + struct terminal *t = decode_live_terminal (object); + + if (t->type != output_haiku) + error ("Terminal %d is not a Be display", t->id); + + dpyinfo = t->display_info.haiku; + } + else if (STRINGP (object)) + dpyinfo = haiku_display_info_for_name (object); + else + { + struct frame *f = decode_window_system_frame (object); + dpyinfo = FRAME_DISPLAY_INFO (f); + } + + return dpyinfo; +} + +static void +haiku_set_title_bar_text (struct frame *f, Lisp_Object text) +{ + if (FRAME_HAIKU_WINDOW (f)) + { + block_input (); + BWindow_retitle (FRAME_HAIKU_WINDOW (f), SSDATA (ENCODE_UTF_8 (text))); + unblock_input (); + } +} + +static void +haiku_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name) +{ + /* Don't change the title if it's already NAME. */ + if (EQ (name, f->title)) + return; + + update_mode_lines = 26; + + fset_title (f, name); + + if (NILP (name)) + name = f->name; + + haiku_set_title_bar_text (f, name); +} + +static void +haiku_set_child_frame_border_width (struct frame *f, + Lisp_Object arg, Lisp_Object oldval) +{ + int border; + + if (NILP (arg)) + border = -1; + else if (RANGED_FIXNUMP (0, arg, INT_MAX)) + border = XFIXNAT (arg); + else + signal_error ("Invalid child frame border width", arg); + + if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f)) + { + f->child_frame_border_width = border; + + if (FRAME_HAIKU_WINDOW (f)) + adjust_frame_size (f, -1, -1, 3, 0, Qchild_frame_border_width); + + SET_FRAME_GARBAGED (f); + } +} + +static void +haiku_set_parent_frame (struct frame *f, + Lisp_Object new_value, Lisp_Object old_value) +{ + struct frame *p = NULL; + block_input (); + if (!NILP (new_value) + && (!FRAMEP (new_value) + || !FRAME_LIVE_P (p = XFRAME (new_value)) + || !FRAME_HAIKU_P (p))) + { + store_frame_param (f, Qparent_frame, old_value); + unblock_input (); + error ("Invalid specification of `parent-frame'"); + } + + if (EQ (new_value, old_value)) + { + unblock_input (); + return; + } + + if (!NILP (old_value)) + EmacsWindow_unparent (FRAME_HAIKU_WINDOW (f)); + if (!NILP (new_value)) + { + EmacsWindow_parent_to (FRAME_HAIKU_WINDOW (f), + FRAME_HAIKU_WINDOW (p)); + BWindow_set_offset (FRAME_HAIKU_WINDOW (f), + f->left_pos, f->top_pos); + } + fset_parent_frame (f, new_value); + unblock_input (); +} + +static void +haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + haiku_set_name (f, arg, 1); +} + +static void +haiku_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + block_input (); + if (!EQ (new_value, old_value)) + FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value); + + if (FRAME_HAIKU_WINDOW (f)) + { + BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f), + FRAME_NO_ACCEPT_FOCUS (f)); + } + unblock_input (); +} + +static void +unwind_create_frame (Lisp_Object frame) +{ + struct frame *f = XFRAME (frame); + + /* If frame is already dead, nothing to do. This can happen if the + display is disconnected after the frame has become official, but + before x_create_frame removes the unwind protect. */ + if (!FRAME_LIVE_P (f)) + return; + + /* If frame is ``official'', nothing to do. */ + if (NILP (Fmemq (frame, Vframe_list))) + { +#if defined GLYPH_DEBUG && defined ENABLE_CHECKING + struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); +#endif + + /* If the frame's image cache refcount is still the same as our + private shadow variable, it means we are unwinding a frame + for which we didn't yet call init_frame_faces, where the + refcount is incremented. Therefore, we increment it here, so + that free_frame_faces, called in free_frame_resources later, + will not mistakenly decrement the counter that was not + incremented yet to account for this new frame. */ + if (FRAME_IMAGE_CACHE (f) != NULL + && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount) + FRAME_IMAGE_CACHE (f)->refcount++; + + haiku_free_frame_resources (f); + free_glyphs (f); + +#if defined GLYPH_DEBUG && defined ENABLE_CHECKING + /* Check that reference counts are indeed correct. */ + if (dpyinfo->terminal->image_cache) + eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount); +#endif + } +} + +static void +unwind_create_tip_frame (Lisp_Object frame) +{ + unwind_create_frame (frame); + tip_window = NULL; + tip_frame = Qnil; +} + +static void +haiku_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + struct haiku_output *output = FRAME_OUTPUT_DATA (f); + unsigned long old_fg; + + Emacs_Color color; + + if (haiku_get_color (SSDATA (arg), &color)) + { + store_frame_param (f, Qforeground_color, oldval); + unblock_input (); + error ("Bad color"); + } + + old_fg = FRAME_FOREGROUND_PIXEL (f); + FRAME_FOREGROUND_PIXEL (f) = color.pixel; + + if (FRAME_HAIKU_WINDOW (f)) + { + + block_input (); + if (output->cursor_color.pixel == old_fg) + { + output->cursor_color.pixel = old_fg; + output->cursor_color.red = RED_FROM_ULONG (old_fg); + output->cursor_color.green = GREEN_FROM_ULONG (old_fg); + output->cursor_color.blue = BLUE_FROM_ULONG (old_fg); + } + + unblock_input (); + + update_face_from_frame_parameter (f, Qforeground_color, arg); + + if (FRAME_VISIBLE_P (f)) + redraw_frame (f); + } +} + +static Lisp_Object +haiku_create_frame (Lisp_Object parms, int ttip_p) +{ + struct frame *f; + Lisp_Object frame, tem; + Lisp_Object name; + bool minibuffer_only = false; + long window_prompting = 0; + ptrdiff_t count = SPECPDL_INDEX (); + Lisp_Object display; + struct haiku_display_info *dpyinfo = NULL; + Lisp_Object font; + struct kboard *kb; + + parms = Fcopy_alist (parms); + + Vx_resource_name = Vinvocation_name; + + display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, + RES_TYPE_STRING); + if (EQ (display, Qunbound)) + display = Qnil; + dpyinfo = check_haiku_display_info (display); + kb = dpyinfo->terminal->kboard; + + if (!dpyinfo->terminal->name) + error ("Terminal is not live, can't create new frames on it"); + + name = gui_display_get_arg (dpyinfo, parms, Qname, 0, 0, + RES_TYPE_STRING); + if (!STRINGP (name) + && ! EQ (name, Qunbound) + && ! NILP (name)) + error ("Invalid frame name--not a string or nil"); + + if (STRINGP (name)) + Vx_resource_name = name; + + block_input (); + + /* make_frame_without_minibuffer can run Lisp code and garbage collect. */ + /* No need to protect DISPLAY because that's not used after passing + it to make_frame_without_minibuffer. */ + frame = Qnil; + tem = gui_display_get_arg (dpyinfo, parms, Qminibuffer, + "minibuffer", "Minibuffer", + RES_TYPE_SYMBOL); + if (EQ (tem, Qnone) || NILP (tem)) + f = make_frame_without_minibuffer (Qnil, kb, display); + else if (EQ (tem, Qonly)) + { + f = make_minibuffer_frame (); + minibuffer_only = 1; + } + else if (WINDOWP (tem)) + f = make_frame_without_minibuffer (tem, kb, display); + else + f = make_frame (1); + XSETFRAME (frame, f); + + f->terminal = dpyinfo->terminal; + + f->output_method = output_haiku; + f->output_data.haiku = xzalloc (sizeof *f->output_data.haiku); + + fset_icon_name (f, gui_display_get_arg (dpyinfo, parms, Qicon_name, + "iconName", "Title", + RES_TYPE_STRING)); + if (! STRINGP (f->icon_name)) + fset_icon_name (f, Qnil); + + FRAME_DISPLAY_INFO (f) = dpyinfo; + + /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */ + if (!ttip_p) + record_unwind_protect (unwind_create_frame, frame); + else + record_unwind_protect (unwind_create_tip_frame, frame); + + FRAME_OUTPUT_DATA (f)->parent_desc = NULL; + FRAME_OUTPUT_DATA (f)->explicit_parent = 0; + + /* Set the name; the functions to which we pass f expect the name to + be set. */ + if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name)) + { + fset_name (f, Vinvocation_name); + f->explicit_name = 0; + } + else + { + fset_name (f, name); + f->explicit_name = 1; + specbind (Qx_resource_name, name); + } + +#ifdef HAVE_FREETYPE + register_font_driver (&ftbefont_driver, f); +#ifdef HAVE_HARFBUZZ + register_font_driver (&ftbehbfont_driver, f); +#endif +#endif + register_font_driver (&haikufont_driver, f); + + image_cache_refcount = + FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0; + + gui_default_parameter (f, parms, Qfont_backend, Qnil, + "fontBackend", "FontBackend", RES_TYPE_STRING); + Lisp_Object font_param = gui_display_get_arg (dpyinfo, + parms, Qfont, NULL, NULL, + RES_TYPE_STRING); + if (EQ (font_param, Qunbound)) + font_param = Qnil; + font = !NILP (font_param) ? font_param + : gui_display_get_arg (dpyinfo, parms, Qfont, "font", "Font", + RES_TYPE_STRING); + + font = font_open_by_name (f, STRINGP (font) ? font : build_string + (ttip_p ? "Sans Serif" : "monospace")); + + + if (!NILP (font_param)) + gui_set_frame_parameters (f, Fcons (Fcons (Qfont_parameter, font_param), + Qnil)); + + gui_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING); + + unblock_input (); + + gui_default_parameter (f, parms, Qborder_width, make_fixnum (0), + "borderwidth", "BorderWidth", RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (ttip_p ? 1 : 2), + "internalBorderWidth", "InternalBorderWidth", + RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil, + "childFrameBorderWidth", "childFrameBorderWidth", + RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0), + NULL, NULL, RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0), + NULL, NULL, RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qvertical_scroll_bars, !ttip_p ? Qt : Qnil, + "verticalScrollBars", "VerticalScrollBars", + RES_TYPE_SYMBOL); + gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, + "horizontalScrollBars", "HorizontalScrollBars", + RES_TYPE_SYMBOL); + gui_default_parameter (f, parms, Qforeground_color, build_string ("black"), + "foreground", "Foreground", RES_TYPE_STRING); + gui_default_parameter (f, parms, Qbackground_color, build_string ("white"), + "background", "Background", RES_TYPE_STRING); + gui_default_parameter (f, parms, Qline_spacing, Qnil, + "lineSpacing", "LineSpacing", RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qleft_fringe, Qnil, + "leftFringe", "LeftFringe", RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qright_fringe, Qnil, + "rightFringe", "RightFringe", RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qno_special_glyphs, ttip_p ? Qnil : Qt, + NULL, NULL, RES_TYPE_BOOLEAN); + + init_frame_faces (f); + + /* Read comment about this code in corresponding place in xfns.c. */ + tem = gui_display_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, + RES_TYPE_NUMBER); + if (FIXNUMP (tem)) + store_frame_param (f, Qmin_width, tem); + tem = gui_display_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, + RES_TYPE_NUMBER); + if (FIXNUMP (tem)) + store_frame_param (f, Qmin_height, tem); + adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), + FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1, + Qx_create_frame_1); + + gui_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL); + gui_default_parameter (f, parms, Qno_focus_on_map, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); + if (!ttip_p) + gui_default_parameter (f, parms, Qno_accept_focus, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); + + /* The resources controlling the menu-bar and tool-bar are + processed specially at startup, and reflected in the mode + variables; ignore them here. */ + gui_default_parameter (f, parms, Qmenu_bar_lines, + NILP (Vmenu_bar_mode) || ttip_p + ? make_fixnum (0) : make_fixnum (1), + NULL, NULL, RES_TYPE_NUMBER); + + gui_default_parameter (f, parms, Qtool_bar_lines, + NILP (Vtool_bar_mode) || ttip_p + ? make_fixnum (0) : make_fixnum (1), + NULL, NULL, RES_TYPE_NUMBER); + + gui_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate", + "BufferPredicate", RES_TYPE_SYMBOL); + gui_default_parameter (f, parms, Qtitle, Qnil, "title", "Title", + RES_TYPE_STRING); + + parms = get_geometry_from_preferences (dpyinfo, parms); + window_prompting = gui_figure_window_size (f, parms, false, true); + + if (ttip_p) + { + /* No fringes on tip frame. */ + f->fringe_cols = 0; + f->left_fringe_width = 0; + f->right_fringe_width = 0; + /* No dividers on tip frame. */ + f->right_divider_width = 0; + f->bottom_divider_width = 0; + + f->tooltip = 1; + } + + tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, + RES_TYPE_BOOLEAN); + f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !NILP (tem)); + + /* Add `tooltip' frame parameter's default value. */ + if (NILP (Fframe_parameter (frame, Qtooltip)) && ttip_p) + Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil)); + +#define ASSIGN_CURSOR(cursor, be_cursor) \ + (FRAME_OUTPUT_DATA (f)->cursor = be_cursor) + + ASSIGN_CURSOR (text_cursor, BCursor_create_i_beam ()); + ASSIGN_CURSOR (nontext_cursor, BCursor_create_default ()); + ASSIGN_CURSOR (modeline_cursor, BCursor_create_default ()); + ASSIGN_CURSOR (hand_cursor, BCursor_create_grab ()); + ASSIGN_CURSOR (hourglass_cursor, BCursor_create_progress_cursor ()); + ASSIGN_CURSOR (horizontal_drag_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_EAST_WEST)); + ASSIGN_CURSOR (vertical_drag_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_NORTH_SOUTH)); + ASSIGN_CURSOR (left_edge_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_WEST)); + ASSIGN_CURSOR (top_left_corner_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_NORTH_WEST)); + ASSIGN_CURSOR (top_edge_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_NORTH)); + ASSIGN_CURSOR (top_right_corner_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_NORTH_EAST)); + ASSIGN_CURSOR (right_edge_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_EAST)); + ASSIGN_CURSOR (bottom_right_corner_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_EAST)); + ASSIGN_CURSOR (bottom_edge_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_SOUTH)); + ASSIGN_CURSOR (bottom_left_corner_cursor, + BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_WEST)); + ASSIGN_CURSOR (no_cursor, + BCursor_from_id (CURSOR_ID_NO_CURSOR)); + + ASSIGN_CURSOR (current_cursor, FRAME_OUTPUT_DATA (f)->text_cursor); +#undef ASSIGN_CURSOR + + + if (ttip_p) + f->no_split = true; + f->terminal->reference_count++; + + FRAME_OUTPUT_DATA (f)->window = BWindow_new (&FRAME_OUTPUT_DATA (f)->view); + if (!FRAME_OUTPUT_DATA (f)->window) + xsignal1 (Qerror, build_unibyte_string ("Could not create window")); + + if (!minibuffer_only && !ttip_p && FRAME_EXTERNAL_MENU_BAR (f)) + initialize_frame_menubar (f); + + FRAME_OUTPUT_DATA (f)->window_desc = FRAME_OUTPUT_DATA (f)->window; + Vframe_list = Fcons (frame, Vframe_list); + + Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL, + RES_TYPE_SYMBOL); + + if (EQ (parent_frame, Qunbound) + || NILP (parent_frame) + || !FRAMEP (parent_frame) + || !FRAME_LIVE_P (XFRAME (parent_frame))) + parent_frame = Qnil; + + fset_parent_frame (f, parent_frame); + store_frame_param (f, Qparent_frame, parent_frame); + + if (!NILP (parent_frame)) + haiku_set_parent_frame (f, parent_frame, Qnil); + + gui_default_parameter (f, parms, Qundecorated, Qnil, NULL, NULL, RES_TYPE_BOOLEAN); + + gui_default_parameter (f, parms, Qicon_type, Qnil, + "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL); + if (ttip_p) + { + gui_default_parameter (f, parms, Qundecorated, Qt, NULL, NULL, RES_TYPE_BOOLEAN); + gui_default_parameter (f, parms, Qno_accept_focus, Qt, NULL, NULL, + RES_TYPE_BOOLEAN); + } + + gui_default_parameter (f, parms, Qauto_raise, Qnil, + "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); + gui_default_parameter (f, parms, Qauto_lower, Qnil, + "autoLower", "AutoLower", RES_TYPE_BOOLEAN); + gui_default_parameter (f, parms, Qcursor_type, Qbox, + "cursorType", "CursorType", RES_TYPE_SYMBOL); + gui_default_parameter (f, parms, Qscroll_bar_width, Qnil, + "scrollBarWidth", "ScrollBarWidth", + RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qscroll_bar_height, Qnil, + "scrollBarHeight", "ScrollBarHeight", + RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qalpha, Qnil, + "alpha", "Alpha", RES_TYPE_NUMBER); + gui_default_parameter (f, parms, Qfullscreen, Qnil, + "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil, + "inhibitDoubleBuffering", "InhibitDoubleBuffering", + RES_TYPE_BOOLEAN); + + f->can_set_window_size = true; + + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), + 0, true, ttip_p ? Qtip_frame : Qx_create_frame_2); + + if (!FRAME_OUTPUT_DATA (f)->explicit_parent && !ttip_p) + { + Lisp_Object visibility; + + visibility = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0, + RES_TYPE_SYMBOL); + if (EQ (visibility, Qunbound)) + visibility = Qt; + if (EQ (visibility, Qicon)) + haiku_iconify_frame (f); + else if (!NILP (visibility)) + haiku_visualize_frame (f); + else /* Qnil */ + { + f->was_invisible = true; + } + } + + if (FRAME_HAS_MINIBUF_P (f) + && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame)) + || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) + kset_default_minibuffer_frame (kb, frame); + + for (tem = parms; CONSP (tem); tem = XCDR (tem)) + if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem)))) + fset_param_alist (f, Fcons (XCAR (tem), f->param_alist)); + + if (window_prompting & (USPosition | PPosition)) + haiku_set_offset (f, f->left_pos, f->top_pos, 1); + else + BWindow_center_on_screen (FRAME_HAIKU_WINDOW (f)); + + /* Make sure windows on this frame appear in calls to next-window + and similar functions. */ + Vwindow_list = Qnil; + + return unbind_to (count, frame); +} + +static void +compute_tip_xy (struct frame *f, + Lisp_Object parms, Lisp_Object dx, Lisp_Object dy, + int width, int height, int *root_x, int *root_y) +{ + Lisp_Object left, top, right, bottom; + int min_x = 0, min_y = 0, max_x = 0, max_y = 0; + + /* User-specified position? */ + left = Fcdr (Fassq (Qleft, parms)); + top = Fcdr (Fassq (Qtop, parms)); + right = Fcdr (Fassq (Qright, parms)); + bottom = Fcdr (Fassq (Qbottom, parms)); + + /* Move the tooltip window where the mouse pointer is. Resize and + show it. */ + if ((!FIXNUMP (left) && !FIXNUMP (right)) + || (!FIXNUMP (top) && !FIXNUMP (bottom))) + { + int x, y; + + /* Default min and max values. */ + min_x = 0; + min_y = 0; + BScreen_px_dim (&max_x, &max_y); + + block_input (); + BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y); + BView_convert_to_screen (FRAME_HAIKU_VIEW (f), &x, &y); + *root_x = x; + *root_y = y; + unblock_input (); + } + + if (FIXNUMP (top)) + *root_y = XFIXNUM (top); + else if (FIXNUMP (bottom)) + *root_y = XFIXNUM (bottom) - height; + else if (*root_y + XFIXNUM (dy) <= min_y) + *root_y = min_y; /* Can happen for negative dy */ + else if (*root_y + XFIXNUM (dy) + height <= max_y) + /* It fits below the pointer */ + *root_y += XFIXNUM (dy); + else if (height + XFIXNUM (dy) + min_y <= *root_y) + /* It fits above the pointer. */ + *root_y -= height + XFIXNUM (dy); + else + /* Put it on the top. */ + *root_y = min_y; + + if (FIXNUMP (left)) + *root_x = XFIXNUM (left); + else if (FIXNUMP (right)) + *root_x = XFIXNUM (right) - width; + else if (*root_x + XFIXNUM (dx) <= min_x) + *root_x = 0; /* Can happen for negative dx */ + else if (*root_x + XFIXNUM (dx) + width <= max_x) + /* It fits to the right of the pointer. */ + *root_x += XFIXNUM (dx); + else if (width + XFIXNUM (dx) + min_x <= *root_x) + /* It fits to the left of the pointer. */ + *root_x -= width + XFIXNUM (dx); + else + /* Put it left justified on the screen -- it ought to fit that way. */ + *root_x = min_x; +} + +static Lisp_Object +haiku_hide_tip (bool delete) +{ + if (!NILP (tip_timer)) + { + call1 (Qcancel_timer, tip_timer); + tip_timer = Qnil; + } + + if (NILP (tip_frame) + || (!delete && FRAMEP (tip_frame) + && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + return Qnil; + else + { + ptrdiff_t count; + Lisp_Object was_open = Qnil; + + count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); + + if (FRAMEP (tip_frame)) + { + if (FRAME_LIVE_P (XFRAME (tip_frame))) + { + if (delete) + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + haiku_unvisualize_frame (XFRAME (tip_frame)); + + was_open = Qt; + } + else + tip_frame = Qnil; + } + else + tip_frame = Qnil; + + return unbind_to (count, was_open); + } +} + +static void +haiku_set_undecorated (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value) +{ + if (EQ (new_value, old_value)) + return; + + block_input (); + FRAME_UNDECORATED (f) = !NILP (new_value); + BWindow_change_decoration (FRAME_HAIKU_WINDOW (f), NILP (new_value)); + unblock_input (); +} + +static void +haiku_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) +{ + int nlines; + if (TYPE_RANGED_FIXNUMP (int, value)) + nlines = XFIXNUM (value); + else + nlines = 0; + + fset_redisplay (f); + + FRAME_MENU_BAR_LINES (f) = 0; + FRAME_MENU_BAR_HEIGHT (f) = 0; + + if (nlines) + { + FRAME_EXTERNAL_MENU_BAR (f) = 1; + if (FRAME_HAIKU_P (f) && !FRAME_HAIKU_MENU_BAR (f)) + XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = 1; + } + else + { + if (FRAME_EXTERNAL_MENU_BAR (f)) + free_frame_menubar (f); + FRAME_EXTERNAL_MENU_BAR (f) = 0; + if (FRAME_HAIKU_P (f)) + FRAME_HAIKU_MENU_BAR (f) = 0; + } + + adjust_frame_glyphs (f); +} + +/* Return geometric attributes of FRAME. According to the value of + ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the inner + edges of FRAME, the root window edges of frame (Qroot_edges). Any + other value means to return the geometry as returned by + Fx_frame_geometry. */ +static Lisp_Object +frame_geometry (Lisp_Object frame, Lisp_Object attribute) +{ + struct frame *f = decode_live_frame (frame); + check_window_system (f); + + if (EQ (attribute, Qouter_edges)) + return list4i (f->left_pos, f->top_pos, + f->left_pos, f->top_pos); + else if (EQ (attribute, Qnative_edges)) + return list4i (f->left_pos, f->top_pos, + f->left_pos + FRAME_PIXEL_WIDTH (f), + f->top_pos + FRAME_PIXEL_HEIGHT (f)); + else if (EQ (attribute, Qinner_edges)) + return list4i (f->left_pos + FRAME_INTERNAL_BORDER_WIDTH (f), + f->top_pos + FRAME_INTERNAL_BORDER_WIDTH (f) + + FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f), + f->left_pos - FRAME_INTERNAL_BORDER_WIDTH (f) + + FRAME_PIXEL_WIDTH (f), + f->top_pos + FRAME_PIXEL_HEIGHT (f) - + FRAME_INTERNAL_BORDER_WIDTH (f)); + + else + return + list (Fcons (Qouter_position, + Fcons (make_fixnum (f->left_pos), + make_fixnum (f->top_pos))), + Fcons (Qouter_size, + Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)), + make_fixnum (FRAME_PIXEL_HEIGHT (f)))), + Fcons (Qexternal_border_size, + Fcons (make_fixnum (0), make_fixnum (0))), + Fcons (Qtitle_bar_size, + Fcons (make_fixnum (0), make_fixnum (0))), + Fcons (Qmenu_bar_external, Qnil), + Fcons (Qmenu_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) - + (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)), + make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))), + Fcons (Qtool_bar_external, Qnil), + Fcons (Qtool_bar_position, Qtop), + Fcons (Qtool_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) - + (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)), + make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))), + Fcons (Qinternal_border_width, make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f)))); +} + +void +haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + CHECK_STRING (arg); + + block_input (); + Emacs_Color color; + + if (haiku_get_color (SSDATA (arg), &color)) + { + store_frame_param (f, Qbackground_color, oldval); + unblock_input (); + error ("Bad color"); + } + + FRAME_OUTPUT_DATA (f)->cursor_fg = color.pixel; + FRAME_BACKGROUND_PIXEL (f) = color.pixel; + + if (FRAME_HAIKU_VIEW (f)) + { + struct face *defface; + + BView_draw_lock (FRAME_HAIKU_VIEW (f)); + BView_SetViewColor (FRAME_HAIKU_VIEW (f), color.pixel); + BView_draw_unlock (FRAME_HAIKU_VIEW (f)); + + defface = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID); + if (defface) + { + defface->background = color.pixel; + update_face_from_frame_parameter (f, Qbackground_color, arg); + clear_frame (f); + } + } + + if (FRAME_VISIBLE_P (f)) + SET_FRAME_GARBAGED (f); + unblock_input (); +} + +void +haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + CHECK_STRING (arg); + + block_input (); + Emacs_Color color; + + if (haiku_get_color (SSDATA (arg), &color)) + { + store_frame_param (f, Qcursor_color, oldval); + unblock_input (); + error ("Bad color"); + } + + FRAME_CURSOR_COLOR (f) = color; + if (FRAME_VISIBLE_P (f)) + { + gui_update_cursor (f, 0); + gui_update_cursor (f, 1); + } + update_face_from_frame_parameter (f, Qcursor_color, arg); + unblock_input (); +} + +void +haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + set_frame_cursor_types (f, arg); +} + +unsigned long +haiku_get_pixel (haiku bitmap, int x, int y) +{ + unsigned char *data; + int32_t bytes_per_row; + int mono_p; + int left; + int right; + int top; + int bottom; + + data = BBitmap_data (bitmap); + BBitmap_dimensions (bitmap, &left, &top, &right, &bottom, + &bytes_per_row, &mono_p); + + if (x < left || x > right || y < top || y > bottom) + emacs_abort (); + + if (!mono_p) + return ((uint32_t *) (data + (bytes_per_row * y)))[x]; + + int byte = y * bytes_per_row + x / 8; + return data[byte] & (1 << (x % 8)); +} + +void +haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel) +{ + unsigned char *data; + int32_t bytes_per_row; + int mono_p; + int left; + int right; + int top; + int bottom; + + data = BBitmap_data (bitmap); + BBitmap_dimensions (bitmap, &left, &top, &right, &bottom, + &bytes_per_row, &mono_p); + + if (x < left || x > right || y < top || y > bottom) + emacs_abort (); + + if (mono_p) + { + ptrdiff_t off = y * bytes_per_row; + ptrdiff_t bit = x % 8; + ptrdiff_t xoff = x / 8; + + unsigned char *byte = data + off + xoff; + if (!pixel) + *byte &= ~(1 << bit); + else + *byte |= 1 << bit; + } + else + ((uint32_t *) (data + (bytes_per_row * y)))[x] = pixel; +} + +void +haiku_free_frame_resources (struct frame *f) +{ + haiku window, drawable, mbar; + Mouse_HLInfo *hlinfo; + struct haiku_display_info *dpyinfo; + Lisp_Object bar; + struct scroll_bar *b; + + block_input (); + check_window_system (f); + + hlinfo = MOUSE_HL_INFO (f); + window = FRAME_HAIKU_WINDOW (f); + drawable = FRAME_HAIKU_VIEW (f); + mbar = FRAME_HAIKU_MENU_BAR (f); + dpyinfo = FRAME_DISPLAY_INFO (f); + + free_frame_faces (f); + + /* Free scroll bars */ + for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next) + { + b = XSCROLL_BAR (bar); + haiku_scroll_bar_remove (b); + } + + if (f == dpyinfo->highlight_frame) + dpyinfo->highlight_frame = 0; + if (f == dpyinfo->focused_frame) + dpyinfo->focused_frame = 0; + if (f == dpyinfo->last_mouse_motion_frame) + dpyinfo->last_mouse_motion_frame = NULL; + if (f == dpyinfo->last_mouse_frame) + dpyinfo->last_mouse_frame = NULL; + if (f == dpyinfo->focus_event_frame) + dpyinfo->focus_event_frame = NULL; + + if (f == hlinfo->mouse_face_mouse_frame) + reset_mouse_highlight (hlinfo); + + if (mbar) + BMenuBar_delete (mbar); + + if (drawable) + BView_emacs_delete (drawable); + + if (window) + BWindow_quit (window); + + /* Free cursors */ + + BCursor_delete (f->output_data.haiku->text_cursor); + BCursor_delete (f->output_data.haiku->nontext_cursor); + BCursor_delete (f->output_data.haiku->modeline_cursor); + BCursor_delete (f->output_data.haiku->hand_cursor); + BCursor_delete (f->output_data.haiku->hourglass_cursor); + BCursor_delete (f->output_data.haiku->horizontal_drag_cursor); + BCursor_delete (f->output_data.haiku->vertical_drag_cursor); + BCursor_delete (f->output_data.haiku->left_edge_cursor); + BCursor_delete (f->output_data.haiku->top_left_corner_cursor); + BCursor_delete (f->output_data.haiku->top_edge_cursor); + BCursor_delete (f->output_data.haiku->top_right_corner_cursor); + BCursor_delete (f->output_data.haiku->right_edge_cursor); + BCursor_delete (f->output_data.haiku->bottom_right_corner_cursor); + BCursor_delete (f->output_data.haiku->bottom_edge_cursor); + BCursor_delete (f->output_data.haiku->bottom_left_corner_cursor); + BCursor_delete (f->output_data.haiku->no_cursor); + + xfree (FRAME_OUTPUT_DATA (f)); + FRAME_OUTPUT_DATA (f) = NULL; + + unblock_input (); +} + +void +haiku_iconify_frame (struct frame *frame) +{ + if (FRAME_ICONIFIED_P (frame)) + return; + + block_input (); + + SET_FRAME_VISIBLE (frame, false); + SET_FRAME_ICONIFIED (frame, true); + + BWindow_iconify (FRAME_HAIKU_WINDOW (frame)); + + unblock_input (); +} + +void +haiku_set_offset (struct frame *frame, int x, int y, + int change_gravity) +{ + if (change_gravity > 0) + { + frame->top_pos = y; + frame->left_pos = x; + frame->size_hint_flags &= ~ (XNegative | YNegative); + if (x < 0) + frame->size_hint_flags |= XNegative; + if (y < 0) + frame->size_hint_flags |= YNegative; + frame->win_gravity = NorthWestGravity; + } + + block_input (); + if (change_gravity) + BWindow_set_offset (FRAME_HAIKU_WINDOW (frame), x, y); + unblock_input (); +} + +void +haiku_visualize_frame (struct frame *f) +{ + block_input (); + + if (!FRAME_VISIBLE_P (f)) + { + if (FRAME_NO_FOCUS_ON_MAP (f)) + BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f), 1); + BWindow_set_visible (FRAME_HAIKU_WINDOW (f), 1); + if (FRAME_NO_FOCUS_ON_MAP (f) && + !FRAME_NO_ACCEPT_FOCUS (f)) + BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f), 0); + + haiku_set_offset (f, f->left_pos, f->top_pos, 0); + + SET_FRAME_VISIBLE (f, 1); + SET_FRAME_ICONIFIED (f, 0); + } + + unblock_input (); +} + +void +haiku_unvisualize_frame (struct frame *f) +{ + block_input (); + + BWindow_set_visible (FRAME_HAIKU_WINDOW (f), 0); + SET_FRAME_VISIBLE (f, 0); + SET_FRAME_ICONIFIED (f, 0); + + unblock_input (); +} + +void +haiku_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + int old_width = FRAME_INTERNAL_BORDER_WIDTH (f); + int new_width = check_int_nonnegative (arg); + + if (new_width == old_width) + return; + f->internal_border_width = new_width; + + if (FRAME_HAIKU_WINDOW (f)) + { + adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width); + haiku_clear_under_internal_border (f); + } + + SET_FRAME_GARBAGED (f); +} + +void +haiku_set_frame_visible_invisible (struct frame *f, bool visible_p) +{ + if (visible_p) + haiku_visualize_frame (f); + else + haiku_unvisualize_frame (f); +} + +void +frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) +{ + block_input (); + + BView_convert_to_screen (FRAME_HAIKU_VIEW (f), &pix_x, &pix_y); + be_warp_pointer (pix_x, pix_y); + + unblock_input (); +} + +void +haiku_query_color (uint32_t col, Emacs_Color *color_def) +{ + color_def->red = RED_FROM_ULONG (col) * 257; + color_def->green = GREEN_FROM_ULONG (col) * 257; + color_def->blue = BLUE_FROM_ULONG (col) * 257; + + color_def->pixel = col; +} + +Display_Info * +check_x_display_info (Lisp_Object object) +{ + return check_haiku_display_info (object); +} + +/* Rename frame F to NAME. If NAME is nil, set F's name to "GNU + Emacs". If EXPLICIT_P is non-zero, that indicates Lisp code is + setting the name, not redisplay; in that case, set F's name to NAME + and set F->explicit_name; if NAME is nil, clear F->explicit_name. + + If EXPLICIT_P is zero, it means redisplay is setting the name; the + name provided will be ignored if explicit_name is set. */ +void +haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p) +{ + if (explicit_p) + { + if (f->explicit_name && NILP (name)) + update_mode_lines = 24; + + f->explicit_name = !NILP (name); + } + else if (f->explicit_name) + return; + + if (NILP (name)) + name = build_unibyte_string ("GNU Emacs"); + + if (!NILP (Fstring_equal (name, f->name))) + return; + + fset_name (f, name); + + if (!NILP (f->title)) + name = f->title; + + haiku_set_title_bar_text (f, name); +} + +static void +haiku_set_inhibit_double_buffering (struct frame *f, + Lisp_Object new_value, + Lisp_Object old_value) +{ + block_input (); + if (FRAME_HAIKU_WINDOW (f)) + { + if (NILP (new_value)) + { + EmacsView_set_up_double_buffering (FRAME_HAIKU_VIEW (f)); + if (!NILP (old_value)) + { + SET_FRAME_GARBAGED (f); + expose_frame (f, 0, 0, 0, 0); + } + } + else + EmacsView_disable_double_buffering (FRAME_HAIKU_VIEW (f)); + } + unblock_input (); +} + + + +DEFUN ("haiku-set-mouse-absolute-pixel-position", + Fhaiku_set_mouse_absolute_pixel_position, + Shaiku_set_mouse_absolute_pixel_position, 2, 2, 0, + doc: /* Move mouse pointer to a pixel position at (X, Y). The +coordinates X and Y are interpreted to start from the top-left +corner of the screen. */) + (Lisp_Object x, Lisp_Object y) +{ + int xval = check_integer_range (x, INT_MIN, INT_MAX); + int yval = check_integer_range (y, INT_MIN, INT_MAX); + + if (!x_display_list) + error ("Window system not initialized"); + + block_input (); + be_warp_pointer (xval, yval); + unblock_input (); + return Qnil; +} + +DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + return Qt; +} + +DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object color, Lisp_Object frame) +{ + Emacs_Color col; + CHECK_STRING (color); + decode_window_system_frame (frame); + + return haiku_get_color (SSDATA (color), &col) ? Qnil : Qt; +} + +DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object color, Lisp_Object frame) +{ + Emacs_Color col; + CHECK_STRING (color); + decode_window_system_frame (frame); + + block_input (); + if (haiku_get_color (SSDATA (color), &col)) + { + unblock_input (); + return Qnil; + } + unblock_input (); + return list3i (lrint (col.red), lrint (col.green), lrint (col.blue)); +} + +DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p, + 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + return Qnil; +} + +DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, + 1, 3, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed) +{ + struct haiku_display_info *dpy_info; + CHECK_STRING (display); + + if (NILP (Fstring_equal (display, build_string ("be")))) + !NILP (must_succeed) ? fatal ("Bad display") : error ("Bad display"); + dpy_info = haiku_term_init (); + + if (!dpy_info) + !NILP (must_succeed) ? fatal ("Display not responding") : + error ("Display not responding"); + + return Qnil; +} + +DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width, + 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) + +{ + check_haiku_display_info (terminal); + + int width, height; + BScreen_px_dim (&width, &height); + return make_fixnum (width); +} + +DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_height, + 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) + +{ + check_haiku_display_info (terminal); + + int width, height; + BScreen_px_dim (&width, &height); + return make_fixnum (width); +} + +DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal); + + int width, height; + BScreen_px_dim (&width, &height); + + return make_fixnum (height / (dpyinfo->resy / 25.4)); +} + + +DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal); + + int width, height; + BScreen_px_dim (&width, &height); + + return make_fixnum (height / (dpyinfo->resy / 25.4)); +} + +DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, + 1, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object parms) +{ + return haiku_create_frame (parms, 0); +} + +DEFUN ("x-display-visual-class", Fx_display_visual_class, + Sx_display_visual_class, 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + check_haiku_display_info (terminal); + + return intern ("direct-color"); +} + +DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, + Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) +{ + struct frame *tip_f; + struct window *w; + int root_x, root_y; + struct buffer *old_buffer; + struct text_pos pos; + int width, height; + int old_windows_or_buffers_changed = windows_or_buffers_changed; + ptrdiff_t count = SPECPDL_INDEX (); + ptrdiff_t count_1; + Lisp_Object window, size, tip_buf; + + AUTO_STRING (tip, " *tip*"); + + specbind (Qinhibit_redisplay, Qt); + + CHECK_STRING (string); + + if (NILP (frame)) + frame = selected_frame; + decode_window_system_frame (frame); + + if (NILP (timeout)) + timeout = make_fixnum (5); + else + CHECK_FIXNAT (timeout); + + if (NILP (dx)) + dx = make_fixnum (5); + else + CHECK_FIXNUM (dx); + + if (NILP (dy)) + dy = make_fixnum (-10); + else + CHECK_FIXNUM (dy); + + if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) + { + if (FRAME_VISIBLE_P (XFRAME (tip_frame)) + && EQ (frame, tip_last_frame) + && !NILP (Fequal_including_properties (string, tip_last_string)) + && !NILP (Fequal (parms, tip_last_parms))) + { + /* Only DX and DY have changed. */ + tip_f = XFRAME (tip_frame); + if (!NILP (tip_timer)) + { + Lisp_Object timer = tip_timer; + + tip_timer = Qnil; + call1 (Qcancel_timer, timer); + } + + block_input (); + compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f), + FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y); + haiku_set_offset (tip_f, root_x, root_y, 1); + haiku_visualize_frame (tip_f); + unblock_input (); + + goto start_timer; + } + else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame)) + { + bool delete = false; + Lisp_Object tail, elt, parm, last; + + /* Check if every parameter in PARMS has the same value in + tip_last_parms. This may destruct tip_last_parms + which, however, will be recreated below. */ + for (tail = parms; CONSP (tail); tail = XCDR (tail)) + { + elt = XCAR (tail); + parm = Fcar (elt); + /* The left, top, right and bottom parameters are handled + by compute_tip_xy so they can be ignored here. */ + if (!EQ (parm, Qleft) && !EQ (parm, Qtop) + && !EQ (parm, Qright) && !EQ (parm, Qbottom)) + { + last = Fassq (parm, tip_last_parms); + if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) + { + /* We lost, delete the old tooltip. */ + delete = true; + break; + } + else + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); + } + else + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); + } + + /* Now check if there's a parameter left in tip_last_parms with a + non-nil value. */ + for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail)) + { + elt = XCAR (tail); + parm = Fcar (elt); + if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) + && !EQ (parm, Qbottom) && !NILP (Fcdr (elt))) + { + /* We lost, delete the old tooltip. */ + delete = true; + break; + } + } + + haiku_hide_tip (delete); + } + else + haiku_hide_tip (true); + } + else + haiku_hide_tip (true); + + tip_last_frame = frame; + tip_last_string = string; + tip_last_parms = parms; + + /* Block input until the tip has been fully drawn, to avoid crashes + when drawing tips in menus. */ + block_input (); + + if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) + { + /* Add default values to frame parameters. */ + if (NILP (Fassq (Qname, parms))) + parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); + if (NILP (Fassq (Qinternal_border_width, parms))) + parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)), parms); + if (NILP (Fassq (Qborder_width, parms))) + parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms); + if (NILP (Fassq (Qborder_color, parms))) + parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), + parms); + if (NILP (Fassq (Qbackground_color, parms))) + parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), + parms); + + /* Create a frame for the tooltip and record it in the global + variable tip_frame. */ + + if (NILP (tip_frame = haiku_create_frame (parms, 1))) + { + /* Creating the tip frame failed. */ + unblock_input (); + return unbind_to (count, Qnil); + } + } + + tip_f = XFRAME (tip_frame); + window = FRAME_ROOT_WINDOW (tip_f); + tip_buf = Fget_buffer_create (tip, Qnil); + /* We will mark the tip window a "pseudo-window" below, and such + windows cannot have display margins. */ + bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0)); + bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0)); + set_window_buffer (window, tip_buf, false, false); + w = XWINDOW (window); + w->pseudo_window_p = true; + /* Try to avoid that `other-window' select us (Bug#47207). */ + Fset_window_parameter (window, Qno_other_window, Qt); + + /* Set up the frame's root window. Note: The following code does not + try to size the window or its frame correctly. Its only purpose is + to make the subsequent text size calculations work. The right + sizes should get installed when the toolkit gets back to us. */ + w->left_col = 0; + w->top_line = 0; + w->pixel_left = 0; + w->pixel_top = 0; + + if (CONSP (Vx_max_tooltip_size) + && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX) + && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX)) + { + w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size)); + w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size)); + } + else + { + w->total_cols = 80; + w->total_lines = 40; + } + + w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f); + w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f); + FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w); + adjust_frame_glyphs (tip_f); + + /* Insert STRING into the root window's buffer and fit the frame to + the buffer. */ + count_1 = SPECPDL_INDEX (); + old_buffer = current_buffer; + set_buffer_internal_1 (XBUFFER (w->contents)); + bset_truncate_lines (current_buffer, Qnil); + specbind (Qinhibit_read_only, Qt); + specbind (Qinhibit_modification_hooks, Qt); + specbind (Qinhibit_point_motion_hooks, Qt); + Ferase_buffer (); + Finsert (1, &string); + clear_glyph_matrix (w->desired_matrix); + clear_glyph_matrix (w->current_matrix); + SET_TEXT_POS (pos, BEGV, BEGV_BYTE); + try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); + /* Calculate size of tooltip window. */ + size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil, + make_fixnum (w->pixel_height), Qnil); + /* Add the frame's internal border to calculated size. */ + width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); + height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); + /* Calculate position of tooltip frame. */ + compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y); + + /* Tooltip code currently disabled because + B_FLOATING_APP_WINDOW_FEEL seem to work better. If this causes + problems, we can always switch back to the tooltip-specific + code. */ + /* EmacsWindow_put_tooltip (FRAME_HAIKU_WINDOW (XFRAME (frame)), */ + /* FRAME_HAIKU_WINDOW (tip_f)); */ + BWindow_resize (FRAME_HAIKU_WINDOW (tip_f), width, height); + haiku_set_offset (tip_f, root_x, root_y, 1); + BWindow_set_tooltip_decoration (FRAME_HAIKU_WINDOW (tip_f)); + BView_set_view_cursor (FRAME_HAIKU_VIEW (tip_f), + FRAME_OUTPUT_DATA (XFRAME (frame))->current_cursor); + SET_FRAME_VISIBLE (tip_f, 1); + BWindow_set_visible (FRAME_HAIKU_WINDOW (tip_f), 1); + + w->must_be_updated_p = true; + update_single_window (w); + set_buffer_internal_1 (old_buffer); + unbind_to (count_1, Qnil); + unblock_input (); + windows_or_buffers_changed = old_windows_or_buffers_changed; + + start_timer: + /* Let the tip disappear after timeout seconds. */ + tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, + intern ("x-hide-tip")); + + return unbind_to (count, Qnil); +} + +DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, + doc: /* SKIP: real doc in xfns.c. */) + (void) +{ + return haiku_hide_tip (!tooltip_reuse_hidden_frame); +} + +DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1, 1, 0, + doc: /* SKIP: real doc in xfns.c. */ + attributes: noreturn) + (Lisp_Object terminal) +{ + check_haiku_display_info (terminal); + + error ("Cannot close Haiku displays"); +} + +DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, + doc: /* SKIP: real doc in xfns.c. */) + (void) +{ + if (!x_display_list) + return Qnil; + + return list1 (x_display_list->name_list_element); +} + +DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + check_haiku_display_info (terminal); + return build_string ("Haiku, Inc."); +} + +DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + check_haiku_display_info (terminal); + return list3i (5, 1, 1); +} + +DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + check_haiku_display_info (terminal); + return make_fixnum (1); +} + +DEFUN ("haiku-get-version-string", Fhaiku_get_version_string, + Shaiku_get_version_string, 0, 0, 0, + doc: /* Return a string describing the current Haiku version. */) + (void) +{ + char buf[1024]; + + be_get_version_string ((char *) &buf, sizeof buf); + return build_string (buf); +} + +DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, + 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + check_haiku_display_info (terminal); + + return make_fixnum (be_get_display_color_cells ()); +} + +DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, + 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + check_haiku_display_info (terminal); + + return make_fixnum (be_get_display_planes ()); +} + +DEFUN ("x-double-buffered-p", Fx_double_buffered_p, Sx_double_buffered_p, + 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object frame) +{ + struct frame *f = decode_live_frame (frame); + check_window_system (f); + + return EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)) ? Qt : Qnil; +} + +DEFUN ("x-display-backing-store", Fx_display_backing_store, Sx_display_backing_store, + 0, 1, 0, + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object terminal) +{ + if (FRAMEP (terminal)) + { + CHECK_LIVE_FRAME (terminal); + struct frame *f = decode_window_system_frame (terminal); + + if (FRAME_HAIKU_VIEW (f) && + EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f))) + return Qalways; + else + return Qnot_useful; + } + else + { + check_haiku_display_info (terminal); + return Qnot_useful; + } +} + +DEFUN ("haiku-frame-geometry", Fhaiku_frame_geometry, Shaiku_frame_geometry, 0, 1, 0, + doc: /* Return geometric attributes of FRAME. +FRAME must be a live frame and defaults to the selected one. The return +value is an association list of the attributes listed below. All height +and width values are in pixels. + +`outer-position' is a cons of the outer left and top edges of FRAME + relative to the origin - the position (0, 0) - of FRAME's display. + +`outer-size' is a cons of the outer width and height of FRAME. The + outer size includes the title bar and the external borders as well as + any menu and/or tool bar of frame. + +`external-border-size' is a cons of the horizontal and vertical width of + FRAME's external borders as supplied by the window manager. + +`title-bar-size' is a cons of the width and height of the title bar of + FRAME as supplied by the window manager. If both of them are zero, + FRAME has no title bar. If only the width is zero, Emacs was not + able to retrieve the width information. + +`menu-bar-external', if non-nil, means the menu bar is external (never + included in the inner edges of FRAME). + +`menu-bar-size' is a cons of the width and height of the menu bar of + FRAME. + +`tool-bar-external', if non-nil, means the tool bar is external (never + included in the inner edges of FRAME). + +`tool-bar-position' tells on which side the tool bar on FRAME is and can + be one of `left', `top', `right' or `bottom'. If this is nil, FRAME + has no tool bar. + +`tool-bar-size' is a cons of the width and height of the tool bar of + FRAME. + +`internal-border-width' is the width of the internal border of + FRAME. */) + (Lisp_Object frame) +{ + return frame_geometry (frame, Qnil); +} + +DEFUN ("haiku-frame-edges", Fhaiku_frame_edges, Shaiku_frame_edges, 0, 2, 0, + doc: /* Return edge coordinates of FRAME. +FRAME must be a live frame and defaults to the selected one. The return +value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are +in pixels relative to the origin - the position (0, 0) - of FRAME's +display. + +If optional argument TYPE is the symbol `outer-edges', return the outer +edges of FRAME. The outer edges comprise the decorations of the window +manager (like the title bar or external borders) as well as any external +menu or tool bar of FRAME. If optional argument TYPE is the symbol +`native-edges' or nil, return the native edges of FRAME. The native +edges exclude the decorations of the window manager and any external +menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return +the inner edges of FRAME. These edges exclude title bar, any borders, +menu bar or tool bar of FRAME. */) + (Lisp_Object frame, Lisp_Object type) +{ + return frame_geometry (frame, ((EQ (type, Qouter_edges) + || EQ (type, Qinner_edges)) + ? type + : Qnative_edges)); +} + +frame_parm_handler haiku_frame_parm_handlers[] = + { + gui_set_autoraise, + gui_set_autolower, + haiku_set_background_color, + NULL, /* x_set_border_color */ + gui_set_border_width, + haiku_set_cursor_color, + haiku_set_cursor_type, + gui_set_font, + haiku_set_foreground_color, + NULL, /* set icon name */ + NULL, /* set icon type */ + haiku_set_child_frame_border_width, + haiku_set_internal_border_width, + gui_set_right_divider_width, + gui_set_bottom_divider_width, + haiku_set_menu_bar_lines, + NULL, /* set mouse color */ + haiku_explicitly_set_name, + gui_set_scroll_bar_width, + gui_set_scroll_bar_height, + haiku_set_title, + gui_set_unsplittable, + gui_set_vertical_scroll_bars, + gui_set_horizontal_scroll_bars, + gui_set_visibility, + haiku_set_tab_bar_lines, + haiku_set_tool_bar_lines, + NULL, /* set scroll bar fg */ + NULL, /* set scroll bar bkg */ + gui_set_screen_gamma, + gui_set_line_spacing, + gui_set_left_fringe, + gui_set_right_fringe, + NULL, /* x wait for wm */ + gui_set_fullscreen, + gui_set_font_backend, + gui_set_alpha, + NULL, /* set sticky */ + NULL, /* set tool bar pos */ + haiku_set_inhibit_double_buffering, + haiku_set_undecorated, + haiku_set_parent_frame, + NULL, /* set skip taskbar */ + haiku_set_no_focus_on_map, + haiku_set_no_accept_focus, + NULL, /* set z group */ + NULL, /* set override redir */ + gui_set_no_special_glyphs + }; + +void +syms_of_haikufns (void) +{ + DEFSYM (Qfont_parameter, "font-parameter"); + DEFSYM (Qcancel_timer, "cancel-timer"); + DEFSYM (Qassq_delete_all, "assq-delete-all"); + + DEFSYM (Qalways, "always"); + DEFSYM (Qnot_useful, "not-useful"); + + defsubr (&Sx_hide_tip); + defsubr (&Sxw_display_color_p); + defsubr (&Sx_display_grayscale_p); + defsubr (&Sx_open_connection); + defsubr (&Sx_create_frame); + defsubr (&Sx_display_pixel_width); + defsubr (&Sx_display_pixel_height); + defsubr (&Sxw_color_values); + defsubr (&Sxw_color_defined_p); + defsubr (&Sx_display_visual_class); + defsubr (&Sx_show_tip); + defsubr (&Sx_display_mm_height); + defsubr (&Sx_display_mm_width); + defsubr (&Sx_close_connection); + defsubr (&Sx_display_list); + defsubr (&Sx_server_vendor); + defsubr (&Sx_server_version); + defsubr (&Sx_display_screens); + defsubr (&Shaiku_get_version_string); + defsubr (&Sx_display_color_cells); + defsubr (&Sx_display_planes); + defsubr (&Shaiku_set_mouse_absolute_pixel_position); + defsubr (&Shaiku_frame_geometry); + defsubr (&Shaiku_frame_edges); + defsubr (&Sx_double_buffered_p); + defsubr (&Sx_display_backing_store); + + tip_timer = Qnil; + staticpro (&tip_timer); + tip_frame = Qnil; + staticpro (&tip_frame); + tip_last_frame = Qnil; + staticpro (&tip_last_frame); + tip_last_string = Qnil; + staticpro (&tip_last_string); + tip_last_parms = Qnil; + staticpro (&tip_last_parms); + + DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size, + doc: /* SKIP: real doc in xfns.c. */); + Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40)); + + return; +} diff --git a/src/haikufont.c b/src/haikufont.c new file mode 100644 index 0000000000..a39094a32c --- /dev/null +++ b/src/haikufont.c @@ -0,0 +1,941 @@ +/* Font support for Haiku windowing + +Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include "lisp.h" +#include "dispextern.h" +#include "composite.h" +#include "blockinput.h" +#include "charset.h" +#include "frame.h" +#include "window.h" +#include "fontset.h" +#include "haikuterm.h" +#include "character.h" +#include "font.h" +#include "termchar.h" +#include "pdumper.h" +#include "haiku_support.h" + +#include +#include + +static Lisp_Object +haikufont_get_fallback_entity (void) +{ + Lisp_Object ent = font_make_entity (); + ASET (ent, FONT_TYPE_INDEX, Qhaiku); + ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku); + ASET (ent, FONT_FAMILY_INDEX, Qnil); + ASET (ent, FONT_ADSTYLE_INDEX, Qnil); + ASET (ent, FONT_REGISTRY_INDEX, Qiso10646_1); + ASET (ent, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO)); + FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnil); + FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnil); + FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnil); + + return ent; +} + +static Lisp_Object +haikufont_get_cache (struct frame *frame) +{ + return FRAME_DISPLAY_INFO (frame)->name_list_element; +} + +static Lisp_Object +haikufont_weight_to_lisp (int weight) +{ + switch (weight) + { + case HAIKU_THIN: + return Qthin; + case HAIKU_ULTRALIGHT: + return Qultra_light; + case HAIKU_EXTRALIGHT: + return Qextra_light; + case HAIKU_LIGHT: + return Qlight; + case HAIKU_SEMI_LIGHT: + return Qsemi_light; + case HAIKU_REGULAR: + return Qnormal; + case HAIKU_SEMI_BOLD: + return Qsemi_bold; + case HAIKU_BOLD: + return Qbold; + case HAIKU_EXTRA_BOLD: + return Qextra_bold; + case HAIKU_ULTRA_BOLD: + return Qultra_bold; + } + emacs_abort (); +} + +static int +haikufont_lisp_to_weight (Lisp_Object weight) +{ + if (EQ (weight, Qthin)) + return HAIKU_THIN; + if (EQ (weight, Qultra_light)) + return HAIKU_ULTRALIGHT; + if (EQ (weight, Qextra_light)) + return HAIKU_EXTRALIGHT; + if (EQ (weight, Qlight)) + return HAIKU_LIGHT; + if (EQ (weight, Qsemi_light)) + return HAIKU_SEMI_LIGHT; + if (EQ (weight, Qnormal)) + return HAIKU_REGULAR; + if (EQ (weight, Qsemi_bold)) + return HAIKU_SEMI_BOLD; + if (EQ (weight, Qbold)) + return HAIKU_BOLD; + if (EQ (weight, Qextra_bold)) + return HAIKU_EXTRA_BOLD; + if (EQ (weight, Qultra_bold)) + return HAIKU_ULTRA_BOLD; + + emacs_abort (); +} + +static Lisp_Object +haikufont_slant_to_lisp (enum haiku_font_slant slant) +{ + switch (slant) + { + case NO_SLANT: + emacs_abort (); + case SLANT_ITALIC: + return Qitalic; + case SLANT_REGULAR: + return Qnormal; + case SLANT_OBLIQUE: + return Qoblique; + } + emacs_abort (); +} + +static enum haiku_font_slant +haikufont_lisp_to_slant (Lisp_Object slant) +{ + if (EQ (slant, Qitalic) || + EQ (slant, Qreverse_italic)) + return SLANT_ITALIC; + if (EQ (slant, Qoblique) || + EQ (slant, Qreverse_oblique)) + return SLANT_OBLIQUE; + if (EQ (slant, Qnormal)) + return SLANT_REGULAR; + emacs_abort (); +} + +static Lisp_Object +haikufont_width_to_lisp (enum haiku_font_width width) +{ + switch (width) + { + case NO_WIDTH: + emacs_abort (); + case ULTRA_CONDENSED: + return Qultra_condensed; + case EXTRA_CONDENSED: + return Qextra_condensed; + case CONDENSED: + return Qcondensed; + case SEMI_CONDENSED: + return Qsemi_condensed; + case NORMAL_WIDTH: + return Qnormal; + case SEMI_EXPANDED: + return Qsemi_expanded; + case EXPANDED: + return Qexpanded; + case EXTRA_EXPANDED: + return Qextra_expanded; + case ULTRA_EXPANDED: + return Qultra_expanded; + } + + emacs_abort (); +} + +static enum haiku_font_width +haikufont_lisp_to_width (Lisp_Object lisp) +{ + if (EQ (lisp, Qultra_condensed)) + return ULTRA_CONDENSED; + if (EQ (lisp, Qextra_condensed)) + return EXTRA_CONDENSED; + if (EQ (lisp, Qcondensed)) + return CONDENSED; + if (EQ (lisp, Qsemi_condensed)) + return SEMI_CONDENSED; + if (EQ (lisp, Qnormal)) + return NORMAL_WIDTH; + if (EQ (lisp, Qexpanded)) + return EXPANDED; + if (EQ (lisp, Qextra_expanded)) + return EXTRA_EXPANDED; + if (EQ (lisp, Qultra_expanded)) + return ULTRA_EXPANDED; + emacs_abort (); +} + +static int +haikufont_maybe_handle_special_family (Lisp_Object family, + struct haiku_font_pattern *ptn) +{ + CHECK_SYMBOL (family); + + if (EQ (family, Qmonospace) || EQ (family, Qfixed) || + EQ (family, Qdefault)) + { + BFont_populate_fixed_family (ptn); + return 1; + } + else if (EQ (family, intern ("Sans Serif"))) + { + BFont_populate_plain_family (ptn); + return 1; + } + return 0; +} + +static Lisp_Object +haikufont_pattern_to_entity (struct haiku_font_pattern *ptn) +{ + Lisp_Object ent = font_make_entity (); + ASET (ent, FONT_TYPE_INDEX, Qhaiku); + ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku); + ASET (ent, FONT_FAMILY_INDEX, Qdefault); + ASET (ent, FONT_ADSTYLE_INDEX, Qnil); + ASET (ent, FONT_REGISTRY_INDEX, Qiso10646_1); + ASET (ent, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO)); + FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnormal); + FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnormal); + FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnormal); + + if (ptn->specified & FSPEC_FAMILY) + ASET (ent, FONT_FAMILY_INDEX, intern (ptn->family)); + else + ASET (ent, FONT_FAMILY_INDEX, Qdefault); + + if (ptn->specified & FSPEC_STYLE) + ASET (ent, FONT_ADSTYLE_INDEX, intern (ptn->style)); + else + { + if (ptn->specified & FSPEC_WEIGHT) + FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, + haikufont_weight_to_lisp (ptn->weight)); + if (ptn->specified & FSPEC_SLANT) + FONT_SET_STYLE (ent, FONT_SLANT_INDEX, + haikufont_slant_to_lisp (ptn->slant)); + if (ptn->specified & FSPEC_WIDTH) + FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, + haikufont_width_to_lisp (ptn->width)); + } + + if (ptn->specified & FSPEC_SPACING) + ASET (ent, FONT_SPACING_INDEX, + make_fixnum (ptn->mono_spacing_p ? + FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + return ent; +} + +static void +haikufont_spec_or_entity_to_pattern (Lisp_Object ent, + int list_p, + struct haiku_font_pattern *ptn) +{ + Lisp_Object tem; + ptn->specified = 0; + + tem = AREF (ent, FONT_ADSTYLE_INDEX); + if (!NILP (tem)) + { + ptn->specified |= FSPEC_STYLE; + strncpy ((char *) &ptn->style, + SSDATA (SYMBOL_NAME (tem)), + sizeof ptn->style - 1); + } + + tem = FONT_SLANT_SYMBOLIC (ent); + if (!NILP (tem)) + { + ptn->specified |= FSPEC_SLANT; + ptn->slant = haikufont_lisp_to_slant (tem); + } + + tem = FONT_WEIGHT_SYMBOLIC (ent); + if (!NILP (tem)) + { + ptn->specified |= FSPEC_WEIGHT; + ptn->weight = haikufont_lisp_to_weight (tem); + } + + tem = FONT_WIDTH_SYMBOLIC (ent); + if (!NILP (tem)) + { + ptn->specified |= FSPEC_WIDTH; + ptn->width = haikufont_lisp_to_width (tem); + } + + tem = AREF (ent, FONT_SPACING_INDEX); + if (FIXNUMP (tem)) + { + ptn->specified |= FSPEC_SPACING; + ptn->mono_spacing_p = XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL; + } + + tem = AREF (ent, FONT_FAMILY_INDEX); + if (!NILP (tem) && + (list_p && !haikufont_maybe_handle_special_family (tem, ptn))) + { + ptn->specified |= FSPEC_FAMILY; + strncpy ((char *) &ptn->family, + SSDATA (SYMBOL_NAME (tem)), + sizeof ptn->family - 1); + } + + tem = assq_no_quit (QCscript, AREF (ent, FONT_EXTRA_INDEX)); + if (!NILP (tem)) + { + tem = assq_no_quit (XCDR (tem), Vscript_representative_chars); + + if (CONSP (tem) && VECTORP (XCDR (tem))) + { + tem = XCDR (tem); + + int count = 0; + + for (int j = 0; j < ASIZE (tem); ++j) + if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j))) + ++count; + + if (count) + { + ptn->specified |= FSPEC_NEED_ONE_OF; + ptn->need_one_of_len = count; + ptn->need_one_of = xmalloc (count * sizeof *ptn->need_one_of); + count = 0; + for (int j = 0; j < ASIZE (tem); ++j) + if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j))) + { + ptn->need_one_of[j] = XFIXNAT (AREF (tem, j)); + ++count; + } + } + } + else if (CONSP (tem) && CONSP (XCDR (tem))) + { + int count = 0; + + for (Lisp_Object it = XCDR (tem); CONSP (it); it = XCDR (it)) + if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (it))) + ++count; + + if (count) + { + ptn->specified |= FSPEC_WANTED; + ptn->want_chars_len = count; + ptn->wanted_chars = xmalloc (count * sizeof *ptn->wanted_chars); + count = 0; + + for (tem = XCDR (tem); CONSP (tem); tem = XCDR (tem)) + if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (tem))) + { + ptn->wanted_chars[count] = XFIXNAT (XCAR (tem)); + ++count; + } + } + } + } + + tem = assq_no_quit (QClang, AREF (ent, FONT_EXTRA_INDEX)); + if (CONSP (tem)) + { + tem = XCDR (tem); + if (EQ (tem, Qzh)) + { + ptn->specified |= FSPEC_LANGUAGE; + ptn->language = LANGUAGE_CN; + } + else if (EQ (tem, Qko)) + { + ptn->specified |= FSPEC_LANGUAGE; + ptn->language = LANGUAGE_KO; + } + else if (EQ (tem, Qjp)) + { + ptn->specified |= FSPEC_LANGUAGE; + ptn->language = LANGUAGE_JP; + } + } +} + +static void +haikufont_done_with_query_pattern (struct haiku_font_pattern *ptn) +{ + if (ptn->specified & FSPEC_WANTED) + xfree (ptn->wanted_chars); + + if (ptn->specified & FSPEC_NEED_ONE_OF) + xfree (ptn->need_one_of); +} + +static Lisp_Object +haikufont_match (struct frame *f, Lisp_Object font_spec) +{ + block_input (); + Lisp_Object tem = Qnil; + struct haiku_font_pattern ptn; + haikufont_spec_or_entity_to_pattern (font_spec, 0, &ptn); + ptn.specified &= ~FSPEC_FAMILY; + struct haiku_font_pattern *found = BFont_find (&ptn); + haikufont_done_with_query_pattern (&ptn); + if (found) + { + tem = haikufont_pattern_to_entity (found); + haiku_font_pattern_free (found); + } + unblock_input (); + return !NILP (tem) ? tem : haikufont_get_fallback_entity (); +} + +static Lisp_Object +haikufont_list (struct frame *f, Lisp_Object font_spec) +{ + block_input (); + Lisp_Object lst = Qnil; + struct haiku_font_pattern ptn; + haikufont_spec_or_entity_to_pattern (font_spec, 1, &ptn); + struct haiku_font_pattern *found = BFont_find (&ptn); + haikufont_done_with_query_pattern (&ptn); + if (found) + { + for (struct haiku_font_pattern *pt = found; + pt; pt = pt->next) + lst = Fcons (haikufont_pattern_to_entity (pt), lst); + haiku_font_pattern_free (found); + } + unblock_input (); + return lst; +} + +static unsigned int +haikufont_encode_char (struct font *font, int c) +{ + struct haikufont_info *info = (struct haikufont_info *) font; + + if (c < HAVE_CHAR_CACHE_MAX && c < info->charc_size && info->have_char_cache[c]) + return info->have_char_cache[c] < 0 ? FONT_INVALID_CODE : c; + + if (c < HAVE_CHAR_CACHE_MAX) + { + int min_size = c + 1; + if (info->charc_size < min_size) + { + ptrdiff_t current = info->charc_size; + info->charc_size = min_size + min_size % 256; + info->met_cache = xrealloc (info->met_cache, info->charc_size * + sizeof *info->met_cache); + info->have_char_cache = xrealloc (info->have_char_cache, info->charc_size * + sizeof *info->have_char_cache); + memset (&info->have_char_cache[current], 0, + sizeof *info->have_char_cache * (info->charc_size - current)); + memset (&info->met_cache[current], 0, + sizeof *info->met_cache * (info->charc_size - current)); + } + info->have_char_cache[c] = -1; + } + if (!BFont_have_char_p (((struct haikufont_info *) font)->be_font, c)) + { + if (c < HAVE_CHAR_CACHE_MAX) + { + info->have_char_cache[c] = -1; + } + return FONT_INVALID_CODE; + } + if (c < HAVE_CHAR_CACHE_MAX) + info->have_char_cache[c] = 1; + + return c; +} + +static int +haikufont_have_char (Lisp_Object font, int c) +{ + if (FONT_ENTITY_P (font)) + return -1; + + return haikufont_encode_char (XFONT_OBJECT (font), c) + != FONT_INVALID_CODE; +} + +static Lisp_Object +haikufont_open (struct frame *f, Lisp_Object font_entity, int x) +{ + struct haikufont_info *font_info; + struct haiku_font_pattern ptn; + struct font *font; + void *be_font; + Lisp_Object font_object; + Lisp_Object tem; + + block_input (); + if (x <= 0) + { + /* Get pixel size from frame instead */ + tem = get_frame_param (f, Qfontsize); + x = NILP (tem) ? 0 : XFIXNAT (tem); + } + + haikufont_spec_or_entity_to_pattern (font_entity, 1, &ptn); + + if (BFont_open_pattern (&ptn, &be_font, x)) + { + haikufont_done_with_query_pattern (&ptn); + unblock_input (); + return Qnil; + } + + haikufont_done_with_query_pattern (&ptn); + + font_object = font_make_object (VECSIZE (struct haikufont_info), + font_entity, x); + + ASET (font_object, FONT_TYPE_INDEX, Qhaiku); + font_info = (struct haikufont_info *) XFONT_OBJECT (font_object); + font = (struct font *) font_info; + + font_info->charc_size = 256; + font_info->met_cache = xmalloc (font_info->charc_size * + sizeof *font_info->met_cache); + font_info->have_char_cache = xmalloc (font_info->charc_size * + sizeof *font_info->met_cache); + + memset (font_info->met_cache, 0, font_info->charc_size * + sizeof *font_info->met_cache); + + memset (font_info->have_char_cache, 0, font_info->charc_size * + sizeof *font_info->met_cache); + + if (!font) + { + unblock_input (); + return Qnil; + } + + font_info->be_font = be_font; + + font->pixel_size = 0; + font->driver = &haikufont_driver; + font->encoding_charset = -1; + font->repertory_charset = -1; + font->default_ascent = 0; + font->vertical_centering = 0; + font->baseline_offset = 0; + font->relative_compose = 0; + + font->props[FONT_FULLNAME_INDEX] = + build_unibyte_string ("fixed"); + + int px_size, min_width, max_width, + avg_width, height, space_width, ascent, + descent, underline_pos, underline_thickness; + + BFont_dat (be_font, &px_size, &min_width, + &max_width, &avg_width, &height, + &space_width, &ascent, &descent, + &underline_pos, &underline_thickness); + + font->pixel_size = px_size; + font->min_width = min_width; + font->max_width = max_width; + font->average_width = avg_width; + font->height = height; + font->space_width = space_width; + font->ascent = ascent; + font->descent = descent; + font->default_ascent = ascent; + font->underline_position = underline_pos; + font->underline_thickness = underline_thickness; + + font->vertical_centering = 0; + font->baseline_offset = 0; + font->relative_compose = 0; + + font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil); + + unblock_input (); + return font_object; +} + +static void +haikufont_close (struct font *font) +{ + struct haikufont_info *info = (struct haikufont_info *) font; + + block_input (); + if (info && info->be_font) + BFont_close (info->be_font); + unblock_input (); +} + +static void +haikufont_prepare_face (struct frame *f, struct face *face) +{ + +} + +static void +haikufont_glyph_extents (struct font *font, unsigned code, + struct font_metrics *metrics) +{ + struct haikufont_info *info = (struct haikufont_info *) font; + + if (code < HAVE_CHAR_CACHE_MAX && + info->met_cache[code].ascent != 0) + { + int min_size = code + 1; + if (info->charc_size < min_size) + { + info->charc_size = min_size + min_size % 256; + ptrdiff_t current = info->charc_size; + + info->charc_size = min_size + min_size % 256; + info->met_cache = xrealloc (info->met_cache, info->charc_size * + sizeof *info->met_cache); + info->have_char_cache = xrealloc (info->have_char_cache, info->charc_size * + sizeof *info->have_char_cache); + memset (&info->have_char_cache[current], 0, + sizeof *info->have_char_cache * (info->charc_size - current)); + memset (&info->met_cache[current], 0, + sizeof *info->met_cache * (info->charc_size - current)); + } + + *metrics = info->met_cache[code]; + return; + } + + unsigned char utf8[MAX_MULTIBYTE_LENGTH]; + memset (utf8, 0, MAX_MULTIBYTE_LENGTH); + CHAR_STRING (code, utf8); + int advance, lb, rb; + BFont_char_bounds (info->be_font, (const char *) utf8, &advance, &lb, &rb); + + metrics->lbearing = lb; + metrics->rbearing = rb; + metrics->width = advance; + metrics->ascent = font->ascent; + metrics->descent = font->descent; + + if (code < HAVE_CHAR_CACHE_MAX) + { + int min_size = code + 1; + if (info->charc_size < min_size) + { + ptrdiff_t current = info->charc_size; + + info->charc_size = min_size + min_size % 256; + info->met_cache = xrealloc (info->met_cache, info->charc_size * + sizeof *info->met_cache); + info->have_char_cache = xrealloc (info->have_char_cache, info->charc_size * + sizeof *info->have_char_cache); + memset (&info->have_char_cache[current], 0, + sizeof *info->have_char_cache * (info->charc_size - current)); + memset (&info->met_cache[current], 0, + sizeof *info->met_cache * (info->charc_size - current)); + } + info->met_cache[code] = *metrics; + } +} + +static void +haikufont_text_extents (struct font *font, const unsigned int *code, + int nglyphs, struct font_metrics *metrics) +{ + int totalwidth = 0; + memset (metrics, 0, sizeof (struct font_metrics)); + + block_input (); + for (int i = 0; i < nglyphs; i++) + { + struct font_metrics m; + haikufont_glyph_extents (font, code[i], &m); + if (metrics) + { + if (totalwidth + m.lbearing < metrics->lbearing) + metrics->lbearing = totalwidth + m.lbearing; + if (totalwidth + m.rbearing > metrics->rbearing) + metrics->rbearing = totalwidth + m.rbearing; + if (m.ascent > metrics->ascent) + metrics->ascent = m.ascent; + if (m.descent > metrics->descent) + metrics->descent = m.descent; + } + totalwidth += m.width; + } + + unblock_input (); + + if (metrics) + metrics->width = totalwidth; +} + +static Lisp_Object +haikufont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct haikufont_info *font = + (struct haikufont_info *) CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + int *advance, *lb, *rb; + ptrdiff_t glyph_len, len, i, b_len; + Lisp_Object tem; + char *b; + uint32_t *mb_buf; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + b_len = 0; + b = xmalloc (b_len); + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = b_len; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = c; + unsigned char mb[MAX_MULTIBYTE_LENGTH]; + int slen = CHAR_STRING (c, mb); + + b = xrealloc (b, b_len = (b_len + slen)); + if (len == 1) + b[b_len - slen] = mb[0]; + else + memcpy (b + b_len - slen, mb, slen); + } + + advance = alloca (len * sizeof *advance); + lb = alloca (len * sizeof *lb); + rb = alloca (len * sizeof *rb); + + eassert (font->be_font); + BFont_nchar_bounds (font->be_font, b, advance, lb, rb, len); + xfree (b); + + for (i = 0; i < len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + if (NILP (tem)) + { + tem = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, tem); + } + + LGLYPH_SET_FROM (tem, i); + LGLYPH_SET_TO (tem, i); + LGLYPH_SET_CHAR (tem, mb_buf[i]); + LGLYPH_SET_CODE (tem, mb_buf[i]); + + LGLYPH_SET_WIDTH (tem, advance[i]); + LGLYPH_SET_LBEARING (tem, lb[i]); + LGLYPH_SET_RBEARING (tem, rb[i]); + LGLYPH_SET_ASCENT (tem, font->font.ascent); + LGLYPH_SET_DESCENT (tem, font->font.descent); + } + + unblock_input (); + + return make_fixnum (len); +} + +static int +haikufont_draw (struct glyph_string *s, int from, int to, + int x, int y, bool with_background) +{ + struct frame *f = s->f; + struct face *face = s->face; + struct font_info *info = (struct font_info *) s->font; + unsigned char mb[MAX_MULTIBYTE_LENGTH]; + void *view = FRAME_HAIKU_VIEW (f); + + if (s->hl == DRAW_MOUSE_FACE) + face = FACE_FROM_ID_OR_NULL (s->f, + MOUSE_HL_INFO (s->f)->mouse_face_face_id); + if (!face) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + + block_input (); + prepare_face_for_display (s->f, face); + + BView_draw_lock (view); + BView_StartClip (view); + if (with_background && !s->background_filled_p) + { + int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); + int vx, vy, width, height; + vx = s->x; + vy = s->y; + width = s->width; + height = FONT_HEIGHT (face->font); + if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) + vx += max (s->face->box_vertical_line_width, 0); + + + int mbox_line_width = max (s->face->box_vertical_line_width, 0); + + if (s->row->full_width_p) + { + if (vx <= fibw + 1 + mbox_line_width) + { + width += vx - mbox_line_width; + vx = mbox_line_width; + } + if (FRAME_PIXEL_WIDTH (s->f) - (vx + width) + <= fibw+1) + width += fibw; + } + if (s->face->box == FACE_NO_BOX) + { + /* Expand unboxed top row over internal border. */ + if (vy <= fibw + 1 + mbox_line_width) + { + height += vy; + vy = 0; + } + } + else + { + int correction = abs (s->face->box_horizontal_line_width) + 1; + vy += correction; + height -= 2 * correction; + correction = abs (s->face->box_vertical_line_width) + 1; + vx += correction; + width -= 2 * correction; + } + BView_SetHighColor (view, s->hl == DRAW_CURSOR ? + FRAME_CURSOR_COLOR (s->f).pixel : face->background); + + BView_FillRectangle (view, vx, vy, width, height); + s->background_filled_p = 1; + } + + if (s->left_overhang && s->clip_head && !s->for_overlaps) + { + /* XXX: Why is this neccessary? */ + BView_ClipToRect (view, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); + } + + if (s->hl == DRAW_CURSOR) + BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg); + else + BView_SetHighColor (view, face->foreground); + + BView_MovePenTo (view, x, y); + BView_SetFont (view, ((struct haikufont_info *) info)->be_font); + + if (from == to) + { + int len = CHAR_STRING (s->char2b[from], mb); + BView_DrawString (view, (char *) mb, len); + } + else + { + ptrdiff_t b_len = 0; + char *b = xmalloc (b_len); + + for (int idx = from; idx < to; ++idx) + { + int len = CHAR_STRING (s->char2b[idx], mb); + b = xrealloc (b, b_len = (b_len + len)); + if (len == 1) + b[b_len - len] = mb[0]; + else + memcpy (b + b_len - len, mb, len); + } + + BView_DrawString (view, b, b_len); + xfree (b); + } + BView_EndClip (view); + BView_draw_unlock (view); + unblock_input (); + return 1; +} + +struct font_driver const haikufont_driver = + { + .type = LISPSYM_INITIALLY (Qhaiku), + .case_sensitive = true, + .get_cache = haikufont_get_cache, + .has_char = haikufont_have_char, + .list = haikufont_list, + .match = haikufont_match, + .draw = haikufont_draw, + .open_font = haikufont_open, + .close_font = haikufont_close, + .prepare_face = haikufont_prepare_face, + .encode_char = haikufont_encode_char, + .text_extents = haikufont_text_extents, + .shape = haikufont_shape + }; + +void +syms_of_haikufont (void) +{ + DEFSYM (Qfontsize, "fontsize"); + DEFSYM (Qfixed, "fixed"); + DEFSYM (Qplain, "plain"); + DEFSYM (Qultra_light, "ultra-light"); + DEFSYM (Qthin, "thin"); + DEFSYM (Qreverse_italic, "reverse-italic"); + DEFSYM (Qreverse_oblique, "reverse-oblique"); + DEFSYM (Qmonospace, "monospace"); + DEFSYM (Qultra_condensed, "ultra-condensed"); + DEFSYM (Qextra_condensed, "extra-condensed"); + DEFSYM (Qcondensed, "condensed"); + DEFSYM (Qsemi_condensed, "semi-condensed"); + DEFSYM (Qsemi_expanded, "semi-expanded"); + DEFSYM (Qexpanded, "expanded"); + DEFSYM (Qextra_expanded, "extra-expanded"); + DEFSYM (Qultra_expanded, "ultra-expanded"); + DEFSYM (Qzh, "zh"); + DEFSYM (Qko, "ko"); + DEFSYM (Qjp, "jp"); +} diff --git a/src/haikugui.h b/src/haikugui.h new file mode 100644 index 0000000000..cfc693fb55 --- /dev/null +++ b/src/haikugui.h @@ -0,0 +1,106 @@ +/* Haiku window system support + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#ifndef _HAIKU_GUI_H_ +#define _HAIKU_GUI_H_ + +#ifdef _cplusplus +extern "C" +{ +#endif + +typedef struct haiku_char_struct +{ + int rbearing; + int lbearing; + int width; + int ascent; + int descent; +} XCharStruct; + +struct haiku_rect +{ + int x, y; + int width, height; +}; + +typedef void *haiku; + +typedef haiku Emacs_Pixmap; +typedef haiku Emacs_Window; +typedef haiku Emacs_Cursor; +typedef haiku Drawable; + +#define NativeRectangle struct haiku_rect +#define CONVERT_TO_EMACS_RECT(xr, nr) \ + ((xr).x = (nr).x, \ + (xr).y = (nr).y, \ + (xr).width = (nr).width, \ + (xr).height = (nr).height) + +#define CONVERT_FROM_EMACS_RECT(xr, nr) \ + ((nr).x = (xr).x, \ + (nr).y = (xr).y, \ + (nr).width = (xr).width, \ + (nr).height = (xr).height) + +#define STORE_NATIVE_RECT(nr, px, py, pwidth, pheight) \ + ((nr).x = (px), \ + (nr).y = (py), \ + (nr).width = (pwidth), \ + (nr).height = (pheight)) + +#define ForgetGravity 0 +#define NorthWestGravity 1 +#define NorthGravity 2 +#define NorthEastGravity 3 +#define WestGravity 4 +#define CenterGravity 5 +#define EastGravity 6 +#define SouthWestGravity 7 +#define SouthGravity 8 +#define SouthEastGravity 9 +#define StaticGravity 10 + +#define NoValue 0x0000 +#define XValue 0x0001 +#define YValue 0x0002 +#define WidthValue 0x0004 +#define HeightValue 0x0008 +#define AllValues 0x000F +#define XNegative 0x0010 +#define YNegative 0x0020 + +#define USPosition (1L << 0) /* user specified x, y */ +#define USSize (1L << 1) /* user specified width, height */ +#define PPosition (1L << 2) /* program specified position */ +#define PSize (1L << 3) /* program specified size */ +#define PMinSize (1L << 4) /* program specified minimum size */ +#define PMaxSize (1L << 5) /* program specified maximum size */ +#define PResizeInc (1L << 6) /* program specified resize increments */ +#define PAspect (1L << 7) /* program specified min, max aspect ratios */ +#define PBaseSize (1L << 8) /* program specified base for incrementing */ +#define PWinGravity (1L << 9) /* program specified window gravity */ + +typedef haiku Window; +typedef int Display; + +#ifdef _cplusplus +}; +#endif +#endif /* _HAIKU_GUI_H_ */ diff --git a/src/haikumenu.c b/src/haikumenu.c new file mode 100644 index 0000000000..b134772a91 --- /dev/null +++ b/src/haikumenu.c @@ -0,0 +1,565 @@ +/* Haiku window system support + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include "lisp.h" +#include "keyboard.h" +#include "menu.h" +#include "buffer.h" +#include "blockinput.h" + +#include "haikuterm.h" +#include "haiku_support.h" + +static Lisp_Object *volatile menu_item_selection; + +int popup_activated_p = 0; + +struct submenu_stack_cell +{ + void *parent_menu; + void *pane; +}; + +static void +digest_menu_items (void *first_menu, int start, int menu_items_used, + int mbar_p) +{ + void **menus, **panes; + ssize_t menu_len = (menu_items_used + 1 - start) * sizeof *menus; + ssize_t pane_len = (menu_items_used + 1 - start) * sizeof *panes; + + menus = alloca (menu_len); + panes = alloca (pane_len); + + int i = start, menu_depth = 0; + + memset (menus, 0, menu_len); + memset (panes, 0, pane_len); + + void *menu = first_menu; + + menus[0] = first_menu; + + while (i < menu_items_used) + { + if (NILP (AREF (menu_items, i))) + { + menus[++menu_depth] = menu; + i++; + } + else if (EQ (AREF (menu_items, i), Qlambda)) + { + panes[menu_depth] = NULL; + menu = panes[--menu_depth] ? panes[menu_depth] : menus[menu_depth]; + i++; + } + else if (EQ (AREF (menu_items, i), Qquote)) + i += 1; + else if (EQ (AREF (menu_items, i), Qt)) + { + Lisp_Object pane_name, prefix; + const char *pane_string; + + if (menu_items_n_panes == 1) + { + i += MENU_ITEMS_PANE_LENGTH; + continue; + } + + pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); + prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); + + if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) + { + pane_name = ENCODE_UTF_8 (pane_name); + ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); + } + + pane_string = (NILP (pane_name) + ? "" : SSDATA (pane_name)); + if (!NILP (prefix)) + pane_string++; + + if (strcmp (pane_string, "")) + { + panes[menu_depth] = + menu = BMenu_new_submenu (menus[menu_depth], pane_string, 1); + } + + i += MENU_ITEMS_PANE_LENGTH; + } + else + { + Lisp_Object item_name, enable, descrip, def, selected; + item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); + enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); + descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); + def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); + selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); + + if (STRINGP (item_name) && STRING_MULTIBYTE (item_name)) + { + item_name = ENCODE_UTF_8 (item_name); + ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); + } + + if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) + { + descrip = ENCODE_UTF_8 (descrip); + ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); + } + + if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used && + NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH))) + menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable)); + else if (NILP (def) && menu_separator_name_p (SSDATA (item_name))) + BMenu_add_separator (menu); + else if (!mbar_p) + BMenu_add_item (menu, SSDATA (item_name), + !NILP (def) ? aref_addr (menu_items, i) : NULL, + !NILP (enable), !NILP (selected)); + else + BMenu_add_item (menu, SSDATA (item_name), + !NILP (def) ? (void *) (intptr_t) i : NULL, + !NILP (enable), !NILP (selected)); + + i += MENU_ITEMS_ITEM_LENGTH; + } + } +} + +static Lisp_Object +haiku_dialog_show (struct frame *f, Lisp_Object title, + Lisp_Object header, const char **error_name) +{ + int i, nb_buttons = 0; + + *error_name = NULL; + + if (menu_items_n_panes > 1) + { + *error_name = "Multiple panes in dialog box"; + return Qnil; + } + + Lisp_Object pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME); + i = MENU_ITEMS_PANE_LENGTH; + + if (STRING_MULTIBYTE (pane_name)) + pane_name = ENCODE_UTF_8 (pane_name); + + block_input (); + void *alert = BAlert_new (SSDATA (pane_name), NILP (header) ? HAIKU_INFO_ALERT : + HAIKU_IDEA_ALERT); + + Lisp_Object vals[10]; + + while (i < menu_items_used) + { + Lisp_Object item_name, enable, descrip, value; + item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); + enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); + descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); + value = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + + if (NILP (item_name)) + { + BAlert_delete (alert); + *error_name = "Submenu in dialog items"; + unblock_input (); + return Qnil; + } + + if (EQ (item_name, Qquote)) + { + i++; + } + + if (nb_buttons >= 9) + { + BAlert_delete (alert); + *error_name = "Too many dialog items"; + unblock_input (); + return Qnil; + } + + if (STRING_MULTIBYTE (item_name)) + item_name = ENCODE_UTF_8 (item_name); + if (!NILP (descrip) && STRING_MULTIBYTE (descrip)) + descrip = ENCODE_UTF_8 (descrip); + + void *button = BAlert_add_button (alert, SSDATA (item_name)); + + BButton_set_enabled (button, !NILP (enable)); + if (!NILP (descrip)) + BView_set_tooltip (button, SSDATA (descrip)); + + vals[nb_buttons] = value; + ++nb_buttons; + i += MENU_ITEMS_ITEM_LENGTH; + } + + int32_t val = BAlert_go (alert); + unblock_input (); + + if (val < 0) + quit (); + else + return vals[val]; + + return Qnil; +} + +Lisp_Object +haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) +{ + Lisp_Object title; + const char *error_name = NULL; + Lisp_Object selection; + ptrdiff_t specpdl_count = SPECPDL_INDEX (); + + check_window_system (f); + + /* Decode the dialog items from what was specified. */ + title = Fcar (contents); + CHECK_STRING (title); + record_unwind_protect_void (unuse_menu_items); + + if (NILP (Fcar (Fcdr (contents)))) + /* No buttons specified, add an "Ok" button so users can pop down + the dialog. Also, the lesstif/motif version crashes if there are + no buttons. */ + contents = list2 (title, Fcons (build_string ("Ok"), Qt)); + + list_of_panes (list1 (contents)); + + /* Display them in a dialog box. */ + block_input (); + selection = haiku_dialog_show (f, title, header, &error_name); + unblock_input (); + + unbind_to (specpdl_count, Qnil); + discard_menu_items (); + + if (error_name) + error ("%s", error_name); + return selection; +} + +Lisp_Object +haiku_menu_show (struct frame *f, int x, int y, int menuflags, + Lisp_Object title, const char **error_name) +{ + int i = 0, submenu_depth = 0; + void *view = FRAME_HAIKU_VIEW (f); + void *menu; + + Lisp_Object *subprefix_stack = + alloca (menu_items_used * sizeof (Lisp_Object)); + + eassert (FRAME_HAIKU_P (f)); + + *error_name = NULL; + + if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) + { + *error_name = "Empty menu"; + return Qnil; + } + + block_input (); + if (STRINGP (title) && STRING_MULTIBYTE (title)) + title = ENCODE_UTF_8 (title); + + menu = BPopUpMenu_new (STRINGP (title) ? SSDATA (title) : NULL); + digest_menu_items (menu, 0, menu_items_used, 0); + BView_convert_to_screen (view, &x, &y); + unblock_input (); + + menu_item_selection = BMenu_run (menu, x, y); + + FRAME_DISPLAY_INFO (f)->grabbed = 0; + + if (menu_item_selection) + { + Lisp_Object prefix, entry; + + prefix = entry = Qnil; + i = 0; + while (i < menu_items_used) + { + if (NILP (AREF (menu_items, i))) + { + subprefix_stack[submenu_depth++] = prefix; + prefix = entry; + i++; + } + else if (EQ (AREF (menu_items, i), Qlambda)) + { + prefix = subprefix_stack[--submenu_depth]; + i++; + } + else if (EQ (AREF (menu_items, i), Qt)) + { + prefix + = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); + i += MENU_ITEMS_PANE_LENGTH; + } + /* Ignore a nil in the item list. + It's meaningful only for dialog boxes. */ + else if (EQ (AREF (menu_items, i), Qquote)) + i += 1; + else + { + entry + = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + if (menu_item_selection == aref_addr (menu_items, i)) + { + if (menuflags & MENU_KEYMAPS) + { + int j; + + entry = list1 (entry); + if (!NILP (prefix)) + entry = Fcons (prefix, entry); + for (j = submenu_depth - 1; j >= 0; j--) + if (!NILP (subprefix_stack[j])) + entry = Fcons (subprefix_stack[j], entry); + } + BPopUpMenu_delete (menu); + return entry; + } + i += MENU_ITEMS_ITEM_LENGTH; + } + } + } + else if (!(menuflags & MENU_FOR_CLICK)) + { + BPopUpMenu_delete (menu); + quit (); + } + BPopUpMenu_delete (menu); + return Qnil; +} + +void +free_frame_menubar (struct frame *f) +{ + FRAME_MENU_BAR_LINES (f) = 0; + FRAME_MENU_BAR_HEIGHT (f) = 0; + FRAME_EXTERNAL_MENU_BAR (f) = 0; + + block_input (); + void *mbar = FRAME_HAIKU_MENU_BAR (f); + if (mbar) + BMenuBar_delete (mbar); + unblock_input (); + + adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines); +} + +void +initialize_frame_menubar (struct frame *f) +{ + /* This function is called before the first chance to redisplay + the frame. It has to be, so the frame will have the right size. */ + fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); + set_frame_menubar (f, true); +} + +void +set_frame_menubar (struct frame *f, bool deep_p) +{ + void *mbar = FRAME_HAIKU_MENU_BAR (f); + void *view = FRAME_HAIKU_VIEW (f); + + int first_time_p = 0; + + if (!mbar) + { + mbar = FRAME_HAIKU_MENU_BAR (f) = BMenuBar_new (view); + first_time_p = 1; + } + + Lisp_Object items; + struct buffer *prev = current_buffer; + Lisp_Object buffer; + ptrdiff_t specpdl_count = SPECPDL_INDEX (); + int previous_menu_items_used = f->menu_bar_items_used; + Lisp_Object *previous_items + = alloca (previous_menu_items_used * sizeof *previous_items); + + XSETFRAME (Vmenu_updating_frame, f); + + if (!deep_p) + { + FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 0; + items = FRAME_MENU_BAR_ITEMS (f); + Lisp_Object string; + + block_input (); + int count = BMenu_count_items (mbar); + + int i; + for (i = 0; i < ASIZE (items); i += 4) + { + string = AREF (items, i + 1); + + if (!STRINGP (string)) + break; + + if (STRING_MULTIBYTE (string)) + string = ENCODE_UTF_8 (string); + + if (i / 4 < count) + { + void *it = BMenu_item_at (mbar, i / 4); + BMenu_item_set_label (it, SSDATA (string)); + } + else + BMenu_new_menu_bar_submenu (mbar, SSDATA (string)); + } + + if (i / 4 < count) + BMenu_delete_from (mbar, i / 4, count - i / 4 + 1); + unblock_input (); + + f->menu_bar_items_used = 0; + } + else + { + /* If we are making a new widget, its contents are empty, + do always reinitialize them. */ + if (first_time_p) + previous_menu_items_used = 0; + buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents; + specbind (Qinhibit_quit, Qt); + /* Don't let the debugger step into this code + because it is not reentrant. */ + specbind (Qdebug_on_next_call, Qnil); + + record_unwind_save_match_data (); + if (NILP (Voverriding_local_map_menu_flag)) + { + specbind (Qoverriding_terminal_local_map, Qnil); + specbind (Qoverriding_local_map, Qnil); + } + + set_buffer_internal_1 (XBUFFER (buffer)); + + /* Run the Lucid hook. */ + safe_run_hooks (Qactivate_menubar_hook); + + /* If it has changed current-menubar from previous value, + really recompute the menubar from the value. */ + if (! NILP (Vlucid_menu_bar_dirty_flag)) + call0 (Qrecompute_lucid_menubar); + safe_run_hooks (Qmenu_bar_update_hook); + fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); + + items = FRAME_MENU_BAR_ITEMS (f); + + /* Save the frame's previous menu bar contents data. */ + if (previous_menu_items_used) + memcpy (previous_items, xvector_contents (f->menu_bar_vector), + previous_menu_items_used * word_size); + + /* Fill in menu_items with the current menu bar contents. + This can evaluate Lisp code. */ + save_menu_items (); + menu_items = f->menu_bar_vector; + menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; + init_menu_items (); + int i; + int count = BMenu_count_items (mbar); + int subitems = ASIZE (items) / 4; + + int *submenu_start, *submenu_end, *submenu_n_panes; + Lisp_Object *submenu_names; + + submenu_start = alloca ((subitems + 1) * sizeof *submenu_start); + submenu_end = alloca (subitems * sizeof *submenu_end); + submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes); + submenu_names = alloca (subitems * sizeof (Lisp_Object)); + + for (i = 0; i < subitems; ++i) + { + Lisp_Object key, string, maps; + + key = AREF (items, i * 4); + string = AREF (items, i * 4 + 1); + maps = AREF (items, i * 4 + 2); + + if (NILP (string)) + break; + + if (STRINGP (string) && STRING_MULTIBYTE (string)) + string = ENCODE_UTF_8 (string); + + submenu_start[i] = menu_items_used; + menu_items_n_panes = 0; + parse_single_submenu (key, string, maps); + submenu_n_panes[i] = menu_items_n_panes; + submenu_end[i] = menu_items_used; + submenu_names[i] = string; + } + finish_menu_items (); + submenu_start[i] = -1; + + block_input (); + for (i = 0; submenu_start[i] >= 0; ++i) + { + void *mn = NULL; + if (i < count) + mn = BMenu_item_get_menu (BMenu_item_at (mbar, i)); + if (mn) + BMenu_delete_all (mn); + else + mn = BMenu_new_menu_bar_submenu (mbar, SSDATA (submenu_names[i])); + + menu_items_n_panes = submenu_n_panes[i]; + digest_menu_items (mn, submenu_start[i], submenu_end[i], 1); + } + unblock_input (); + + set_buffer_internal_1 (prev); + + FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 1; + fset_menu_bar_vector (f, menu_items); + f->menu_bar_items_used = menu_items_used; + } + unbind_to (specpdl_count, Qnil); +} + +DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, + 0, 0, 0, doc: /* SKIP: real doc in xmenu.c. */) + (void) +{ + return popup_activated_p ? Qt : Qnil; +} + +void +syms_of_haikumenu (void) +{ + DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); + + defsubr (&Smenu_or_popup_active_p); + return; +} diff --git a/src/haikuselect.c b/src/haikuselect.c new file mode 100644 index 0000000000..c17c23583b --- /dev/null +++ b/src/haikuselect.c @@ -0,0 +1,134 @@ +/* Haiku window system selection support. Hey Emacs, this is -*- C++ -*- + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include "lisp.h" +#include "blockinput.h" +#include "coding.h" +#include "haikuselect.h" +#include "haikuterm.h" + +DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data, + 2, 2, 0, + doc: /* Retrieve content typed as NAME from the clipboard +CLIPBOARD. CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or +`CLIPBOARD'. NAME is a MIME type denoting the type of the data to +fetch. */) + (Lisp_Object clipboard, Lisp_Object name) +{ + CHECK_SYMBOL (clipboard); + CHECK_STRING (name); + char *dat; + ssize_t len; + + block_input (); + if (EQ (clipboard, QPRIMARY)) + dat = BClipboard_find_primary_selection_data (SSDATA (name), &len); + else if (EQ (clipboard, QSECONDARY)) + dat = BClipboard_find_secondary_selection_data (SSDATA (name), &len); + else if (EQ (clipboard, QCLIPBOARD)) + dat = BClipboard_find_system_data (SSDATA (name), &len); + else + { + unblock_input (); + signal_error ("Bad clipboard", clipboard); + } + unblock_input (); + + if (!dat) + return Qnil; + + Lisp_Object str = make_unibyte_string (dat, len); + Lisp_Object lispy_type = Qnil; + + if (!strcmp (SSDATA (name), "text/utf-8") || + !strcmp (SSDATA (name), "text/plain")) + { + if (string_ascii_p (str)) + lispy_type = QSTRING; + else + lispy_type = QUTF8_STRING; + } + + if (!NILP (lispy_type)) + Fput_text_property (make_fixnum (0), make_fixnum (len), + Qforeign_selection, lispy_type, str); + + block_input (); + BClipboard_free_data (dat); + unblock_input (); + + return str; +} + +DEFUN ("haiku-selection-put", Fhaiku_selection_put, Shaiku_selection_put, + 3, 3, 0, + doc: /* Add or remove content from the clipboard CLIPBOARD. +CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or `CLIPBOARD'. NAME +is a MIME type denoting the type of the data to add. DATA is the +string that will be placed in the clipboard, or nil if the content is +to be removed. If NAME is the string `text/utf-8' or the string +`text/plain', encode it as UTF-8 before storing it into the +clipboard. */) + (Lisp_Object clipboard, Lisp_Object name, Lisp_Object data) +{ + CHECK_SYMBOL (clipboard); + CHECK_STRING (name); + if (!NILP (data)) + CHECK_STRING (data); + + block_input (); + /* It seems that Haiku applications counter-intuitively expect + UTF-8 data in both text/utf-8 and text/plain. */ + if (!NILP (data) && STRING_MULTIBYTE (data) && + (!strcmp (SSDATA (name), "text/utf-8") || + !strcmp (SSDATA (name), "text/plain"))) + data = ENCODE_UTF_8 (data); + + char *dat = !NILP (data) ? SSDATA (data) : NULL; + ptrdiff_t len = !NILP (data) ? SBYTES (data) : 0; + + if (EQ (clipboard, QPRIMARY)) + BClipboard_set_primary_selection_data (SSDATA (name), dat, len); + else if (EQ (clipboard, QSECONDARY)) + BClipboard_set_secondary_selection_data (SSDATA (name), dat, len); + else if (EQ (clipboard, QCLIPBOARD)) + BClipboard_set_system_data (SSDATA (name), dat, len); + else + { + unblock_input (); + signal_error ("Bad clipboard", clipboard); + } + unblock_input (); + + return Qnil; +} + +void +syms_of_haikuselect (void) +{ + DEFSYM (QSECONDARY, "SECONDARY"); + DEFSYM (QCLIPBOARD, "CLIPBOARD"); + DEFSYM (QSTRING, "STRING"); + DEFSYM (QUTF8_STRING, "UTF8_STRING"); + DEFSYM (Qforeign_selection, "foreign-selection"); + + defsubr (&Shaiku_selection_data); + defsubr (&Shaiku_selection_put); +} diff --git a/src/haikuselect.h b/src/haikuselect.h new file mode 100644 index 0000000000..000c83b4dd --- /dev/null +++ b/src/haikuselect.h @@ -0,0 +1,64 @@ +/* Haiku window system selection support. Hey Emacs, this is -*- C++ -*- + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#ifndef _HAIKU_SELECT_H_ +#define _HAIKU_SELECT_H_ + +#ifdef __cplusplus +#include +#endif + +#ifdef __cplusplus +#include +extern "C" +{ + extern void init_haiku_select (void); +#endif + + /* Whether or not the selection was recently changed. */ + extern int selection_state_flag; + + /* Find a string with the MIME type TYPE in the system clipboard. */ + extern char * + BClipboard_find_system_data (const char *type, ssize_t *len); + + /* Ditto, but for the primary selection and not clipboard. */ + extern char * + BClipboard_find_primary_selection_data (const char *type, ssize_t *len); + + /* Ditto, this time for the secondary selection. */ + extern char * + BClipboard_find_secondary_selection_data (const char *type, ssize_t *len); + + extern void + BClipboard_set_system_data (const char *type, const char *data, ssize_t len); + + extern void + BClipboard_set_primary_selection_data (const char *type, const char *data, + ssize_t len); + + extern void + BClipboard_set_secondary_selection_data (const char *type, const char *data, + ssize_t len); + + /* Free the returned data. */ + extern void BClipboard_free_data (void *ptr); +#ifdef __cplusplus +}; +#endif +#endif /* _HAIKU_SELECT_H_ */ diff --git a/src/haikuterm.c b/src/haikuterm.c new file mode 100644 index 0000000000..8b080c1bcb --- /dev/null +++ b/src/haikuterm.c @@ -0,0 +1,3095 @@ +/* Haiku window system support + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#include + +#include "dispextern.h" +#include "frame.h" +#include "lisp.h" +#include "haikugui.h" +#include "keyboard.h" +#include "haikuterm.h" +#include "blockinput.h" +#include "termchar.h" +#include "termhooks.h" +#include "menu.h" +#include "buffer.h" +#include "haiku_support.h" +#include "thread.h" +#include "window.h" + +#include + +struct haiku_display_info *x_display_list = NULL; +extern frame_parm_handler haiku_frame_parm_handlers[]; + +static void **fringe_bmps; +static int fringe_bitmap_fillptr = 0; + +char * +get_keysym_name (int keysym) +{ + static char value[16]; + sprintf (value, "%d", keysym); + return value; +} + +static struct frame * +haiku_window_to_frame (void *window) +{ + Lisp_Object tail, tem; + struct frame *f; + + FOR_EACH_FRAME (tail, tem) + { + f = XFRAME (tem); + if (!FRAME_HAIKU_P (f)) + continue; + + eassert (FRAME_DISPLAY_INFO (f) == x_display_list); + + if (FRAME_HAIKU_WINDOW (f) == window) + return f; + } + + return 0; +} + +static void +haiku_coords_from_parent (struct frame *f, int *x, int *y) +{ + struct frame *p = FRAME_PARENT_FRAME (f); + eassert (p); + + for (struct frame *parent = p; parent; + parent = FRAME_PARENT_FRAME (parent)) + { + *x -= parent->left_pos; + *y -= parent->top_pos; + } +} + +static void +haiku_delete_terminal (struct terminal *terminal) +{ + emacs_abort (); +} + +static const char * +get_string_resource (void *ignored, const char *name, const char *class) +{ + return NULL; +} + +static void +haiku_clip_to_string (struct glyph_string *s) +{ + struct haiku_rect r[2]; + int n = get_glyph_string_clip_rects (s, (struct haiku_rect *) &r, 2); + + if (n) + BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[0].x, r[0].y, + r[0].width, r[0].height); + if (n > 1) + { + BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[1].x, r[1].y, + r[1].width, r[1].height); + } + + s->num_clips = n; +} + +static void +haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst) +{ + BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y, + s->width, s->height); + dst->num_clips = 1; +} + +static void +haiku_flip_buffers (struct frame *f) +{ + void *view = FRAME_OUTPUT_DATA (f)->view; + BView_draw_lock (view); + FRAME_DIRTY_P (f) = 0; + EmacsView_flip_and_blit (view); + BView_draw_unlock (view); +} + +static void +haiku_frame_up_to_date (struct frame *f) +{ + block_input (); + FRAME_MOUSE_UPDATE (f); + if (FRAME_DIRTY_P (f) && !buffer_flipping_blocked_p ()) + haiku_flip_buffers (f); + unblock_input (); +} + +static void +haiku_buffer_flipping_unblocked_hook (struct frame *f) +{ + if (FRAME_DIRTY_P (f)) + haiku_flip_buffers (f); +} + +/* Set the clipping region to the inverse of all scroll bars in the + frame F. This ensures we never clear a scrollbar by accident. */ +static void +haiku_inverse_clip_to_scroll_bars (struct frame *f) +{ + Lisp_Object tem; + void *view = FRAME_HAIKU_VIEW (f); + + for (tem = FRAME_SCROLL_BARS (f); VECTORLIKEP (tem); + tem = XSCROLL_BAR (tem)->next) + { + struct scroll_bar *sb = XSCROLL_BAR (tem); + if (sb->scroll_bar) + { + BView_ClipToInverseRect (view, sb->left, sb->top, + sb->width, sb->height); + } + } +} + +static void +haiku_clear_frame_area (struct frame *f, int x, int y, + int width, int height) +{ + void *vw = FRAME_HAIKU_VIEW (f); + block_input (); + BView_draw_lock (vw); + BView_StartClip (vw); + haiku_inverse_clip_to_scroll_bars (f); + BView_SetHighColor (vw, FRAME_BACKGROUND_PIXEL (f)); + BView_FillRectangle (vw, x, y, width, height); + BView_EndClip (vw); + BView_draw_unlock (vw); + unblock_input (); +} + +static void +haiku_clear_frame (struct frame *f) +{ + void *view = FRAME_HAIKU_VIEW (f); + BView_StartClip (view); + BView_draw_lock (view); + haiku_inverse_clip_to_scroll_bars (f); + BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f)); + BView_FillRectangle (view, 0, 0, FRAME_PIXEL_WIDTH (f), + FRAME_PIXEL_HEIGHT (f)); + BView_draw_unlock (view); + BView_EndClip (view); +} + +/* Give frame F the font FONT-OBJECT as its default font. The return + value is FONT-OBJECT. FONTSET is an ID of the fontset for the + frame. If it is negative, generate a new fontset from + FONT-OBJECT. */ + +static Lisp_Object +haiku_new_font (struct frame *f, Lisp_Object font_object, int fontset) +{ + struct font *font = XFONT_OBJECT (font_object); + if (fontset < 0) + fontset = fontset_from_font (font_object); + + FRAME_FONTSET (f) = fontset; + if (FRAME_FONT (f) == font) + return font_object; + + FRAME_FONT (f) = font; + FRAME_BASELINE_OFFSET (f) = font->baseline_offset; + FRAME_COLUMN_WIDTH (f) = font->average_width; + + int ascent, descent; + get_font_ascent_descent (font, &ascent, &descent); + FRAME_LINE_HEIGHT (f) = ascent + descent; + FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); + + int unit = FRAME_COLUMN_WIDTH (f); + if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) + FRAME_CONFIG_SCROLL_BAR_COLS (f) + = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; + else + FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit; + + if (FRAME_HAIKU_WINDOW (f)) + { + adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), + FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), + 3, false, Qfont); + + haiku_clear_under_internal_border (f); + } + return font_object; +} + +static void +haiku_rehighlight (void) +{ + eassert (x_display_list && !x_display_list->next); + + block_input (); + + struct frame *old_hl = x_display_list->highlight_frame; + + if (x_display_list->focused_frame) + { + x_display_list->highlight_frame + = ((FRAMEP (FRAME_FOCUS_FRAME (x_display_list->focused_frame))) + ? XFRAME (FRAME_FOCUS_FRAME (x_display_list->focused_frame)) + : x_display_list->focused_frame); + if (!FRAME_LIVE_P (x_display_list->highlight_frame)) + { + fset_focus_frame (x_display_list->focused_frame, Qnil); + x_display_list->highlight_frame = x_display_list->focused_frame; + } + } + else + x_display_list->highlight_frame = 0; + + if (old_hl) + gui_update_cursor (old_hl, true); + + if (x_display_list->highlight_frame) + gui_update_cursor (x_display_list->highlight_frame, true); + unblock_input (); +} + +static void +haiku_frame_raise_lower (struct frame *f, bool raise_p) +{ + if (raise_p) + { + BWindow_activate (FRAME_HAIKU_WINDOW (f)); + flush_frame (f); + } +} + +static void +haiku_new_focus_frame (struct frame *frame) +{ + eassert (x_display_list && !x_display_list->next); + + block_input (); + if (frame != x_display_list->focused_frame) + { + if (x_display_list->focused_frame && + x_display_list->focused_frame->auto_lower) + haiku_frame_raise_lower (x_display_list->focused_frame, 0); + + x_display_list->focused_frame = frame; + + if (frame && frame->auto_raise) + haiku_frame_raise_lower (frame, 1); + } + unblock_input (); + + haiku_rehighlight (); +} + +static void +haiku_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + haiku_set_name (f, arg, 0); +} + +static void +haiku_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) +{ + haiku_query_color (FRAME_BACKGROUND_PIXEL (f), bgcolor); +} + +static bool +haiku_defined_color (struct frame *f, + const char *name, + Emacs_Color *color, + bool alloc, + bool make_index) +{ + return !haiku_get_color (name, color); +} + +static void +haiku_draw_plain_background (struct glyph_string *s, struct face *face, + int box_line_width) +{ + void *view = FRAME_HAIKU_VIEW (s->f); + BView_StartClip (view); + if (s->hl == DRAW_CURSOR) + BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel); + else + BView_SetHighColor (view, face->background_defaulted_p ? + FRAME_BACKGROUND_PIXEL (s->f) : + face->background); + BView_FillRectangle (view, s->x, s->y + box_line_width, + s->background_width, + s->height - 2 * box_line_width); + BView_EndClip (view); +} + +static void +haiku_draw_stipple_background (struct glyph_string *s, struct face *face, + int box_line_width) +{ +} + +static void +haiku_maybe_draw_background (struct glyph_string *s, int force_p) +{ + if ((s->first_glyph->type != IMAGE_GLYPH) && + (!s->background_filled_p || s->hl == DRAW_MOUSE_FACE)) + { + int box_line_width = max (s->face->box_horizontal_line_width, 0); + if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width + || FONT_TOO_HIGH (s->font) + || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) + { + struct face *face; + if (s->hl == DRAW_MOUSE_FACE) + { + face = FACE_FROM_ID_OR_NULL (s->f, + MOUSE_HL_INFO (s->f)->mouse_face_face_id); + if (!face) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + } + else + face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + if (!face->stipple) + haiku_draw_plain_background (s, face, box_line_width); + else + haiku_draw_stipple_background (s, face, box_line_width); + s->background_filled_p = 1; + } + } +} + +/* Adapted from xterm `x_draw_box_rect' */ +static void +haiku_draw_box_rect (struct glyph_string *s, + int left_x, int top_y, int right_x, int bottom_y, int hwidth, + int vwidth, bool left_p, bool right_p, struct haiku_rect *clip_rect) +{ + void *view = FRAME_HAIKU_VIEW (s->f); + + BView_StartClip (view); + BView_SetHighColor (view, s->face->box_color); + if (clip_rect) + BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width, + clip_rect->height); + BView_FillRectangle (view, left_x, top_y, right_x - left_x, hwidth); + if (left_p) + BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y); + + BView_FillRectangle (view, left_x, bottom_y - hwidth, + right_x - left_x, hwidth); + if (right_p) + BView_FillRectangle (view, right_x - vwidth, top_y, vwidth, bottom_y - top_y); + BView_EndClip (view); +} + +static void +haiku_calculate_relief_colors (struct glyph_string *s, + uint32_t *rgbout_w, uint32_t *rgbout_b) +{ + struct face *face = s->face; + + if (s->hl == DRAW_MOUSE_FACE) + face = FACE_FROM_ID_OR_NULL (s->f, + MOUSE_HL_INFO (s->f)->mouse_face_face_id); + if (!face && s->hl == DRAW_MOUSE_FACE) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + + if (!face) + face = s->face; + + prepare_face_for_display (s->f, s->face); + + uint32_t rgbin = face->use_box_color_for_shadows_p ? + face->box_color : face->background; + + double h, cs, l; + rgb_color_hsl (rgbin, &h, &cs, &l); + + hsl_color_rgb (h, cs, fmin (1.0, l * 0.7), rgbout_b); + hsl_color_rgb (h, cs, fmin (1.0, l * 1.1), rgbout_w); +} + +static void +haiku_draw_relief_rect (struct glyph_string *s, + int left_x, int top_y, int right_x, int bottom_y, + int hwidth, int vwidth, bool raised_p, bool top_p, bool bot_p, + bool left_p, bool right_p, + struct haiku_rect *clip_rect) +{ + uint32_t color_white; + uint32_t color_black; + + haiku_calculate_relief_colors (s, &color_white, &color_black); + + void *view = FRAME_HAIKU_VIEW (s->f); + BView_StartClip (view); + BView_SetHighColor (view, raised_p ? color_white : color_black); + + if (clip_rect) + BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width, + clip_rect->height); + if (top_p) + BView_FillRectangle (view, left_x, top_y, right_x - left_x, hwidth); + if (left_p) + BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y); + BView_SetHighColor (view, !raised_p ? color_white : color_black); + if (bot_p) + BView_FillRectangle (view, left_x, bottom_y - hwidth, + right_x - left_x, hwidth); + if (right_p) + BView_FillRectangle (view, right_x - vwidth, top_y, vwidth, bottom_y - top_y); + + BView_EndClip (view); +} + +static void +haiku_mouse_face_colors (struct glyph_string *s, uint32_t *fg, + uint32_t *bg) +{ + int face_id; + struct face *face; + + /* What face has to be used last for the mouse face? */ + face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id; + face = FACE_FROM_ID_OR_NULL (s->f, face_id); + if (face == NULL) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + + if (s->first_glyph->type == CHAR_GLYPH) + face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil); + else + face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil); + s->face = FACE_FROM_ID (s->f, face_id); + prepare_face_for_display (s->f, s->face); + + if (fg) + *fg = face->foreground; + if (bg) + *bg = face->background; +} + +static void +haiku_draw_underwave (struct glyph_string *s, int width, int x) +{ + int wave_height = 3, wave_length = 2; + int y, dx, dy, odd, xmax; + dx = wave_length; + dy = wave_height - 1; + y = s->ybase - wave_height + 3; + + float ax, ay, bx, by; + xmax = x + width; + + void *view = FRAME_HAIKU_VIEW (s->f); + + BView_StartClip (view); + BView_ClipToRect (view, x, y, width, wave_height); + ax = x - ((int) (x) % dx) + (float) 0.5; + bx = ax + dx; + odd = (int) (ax / dx) % 2; + ay = by = y + 0.5; + + if (odd) + ay += dy; + else + by += dy; + + while (ax <= xmax) + { + BView_StrokeLine (view, ax, ay, bx, by); + ax = bx, ay = by; + bx += dx, by = y + 0.5 + odd * dy; + odd = !odd; + } + BView_EndClip (view); +} + +static void +haiku_draw_text_decoration (struct glyph_string *s, struct face *face, + uint8_t dcol, int width, int x) +{ + if (s->for_overlaps) + return; + + void *view = FRAME_HAIKU_VIEW (s->f); + BView_draw_lock (view); + BView_StartClip (view); + + if (s->face->underline) + { + if (s->hl == DRAW_CURSOR) + BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg); + else if (!face->underline_defaulted_p) + BView_SetHighColor (view, face->underline_color); + else + BView_SetHighColor (view, dcol); + + if (s->face->underline == FACE_UNDER_WAVE) + haiku_draw_underwave (s, width, x); + else if (s->face->underline == FACE_UNDER_LINE) + { + unsigned long thickness, position; + int y; + + if (s->prev && + s->prev->face->underline == FACE_UNDER_LINE) + { + /* We use the same underline style as the previous one. */ + thickness = s->prev->underline_thickness; + position = s->prev->underline_position; + } + else + { + struct font *font = font_for_underline_metrics (s); + unsigned long minimum_offset; + bool underline_at_descent_line; + bool use_underline_position_properties; + Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE + (Qunderline_minimum_offset, s->w)); + + if (FIXNUMP (val)) + minimum_offset = max (0, XFIXNUM (val)); + else + minimum_offset = 1; + + val = (WINDOW_BUFFER_LOCAL_VALUE + (Qx_underline_at_descent_line, s->w)); + underline_at_descent_line + = !(NILP (val) || EQ (val, Qunbound)); + + val = (WINDOW_BUFFER_LOCAL_VALUE + (Qx_use_underline_position_properties, s->w)); + use_underline_position_properties + = !(NILP (val) || EQ (val, Qunbound)); + + /* Get the underline thickness. Default is 1 pixel. */ + if (font && font->underline_thickness > 0) + thickness = font->underline_thickness; + else + thickness = 1; + if (underline_at_descent_line) + position = (s->height - thickness) - (s->ybase - s->y); + else + { + /* Get the underline position. This is the + recommended vertical offset in pixels from + the baseline to the top of the underline. + This is a signed value according to the + specs, and its default is + + ROUND ((maximum descent) / 2), with + ROUND(x) = floor (x + 0.5) */ + + if (use_underline_position_properties + && font && font->underline_position >= 0) + position = font->underline_position; + else if (font) + position = (font->descent + 1) / 2; + else + position = minimum_offset; + } + position = max (position, minimum_offset); + } + /* Check the sanity of thickness and position. We should + avoid drawing underline out of the current line area. */ + if (s->y + s->height <= s->ybase + position) + position = (s->height - 1) - (s->ybase - s->y); + if (s->y + s->height < s->ybase + position + thickness) + thickness = (s->y + s->height) - (s->ybase + position); + s->underline_thickness = thickness; + s->underline_position = position; + y = s->ybase + position; + + BView_FillRectangle (view, s->x, y, s->width, thickness); + } + } + + if (s->face->overline_p) + { + unsigned long dy = 0, h = 1; + if (s->hl == DRAW_CURSOR) + BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg); + else if (!face->overline_color_defaulted_p) + BView_SetHighColor (view, face->overline_color); + else + BView_SetHighColor (view, dcol); + + BView_FillRectangle (view, s->x, s->y + dy, s->width, h); + } + + if (s->face->strike_through_p) + { + /* Y-coordinate and height of the glyph string's first + glyph. We cannot use s->y and s->height because those + could be larger if there are taller display elements + (e.g., characters displayed with a larger font) in the + same glyph row. */ + int glyph_y = s->ybase - s->first_glyph->ascent; + int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; + /* Strike-through width and offset from the glyph string's + top edge. */ + unsigned long h = 1; + unsigned long dy = (glyph_height - h) / 2; + + if (s->hl == DRAW_CURSOR) + BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg); + else if (!face->overline_color_defaulted_p) + BView_SetHighColor (view, face->overline_color); + else + BView_SetHighColor (view, dcol); + + BView_FillRectangle (view, s->x, glyph_y + dy, s->width, h); + } + + BView_EndClip (view); + BView_draw_unlock (view); +} + +static void +haiku_draw_string_box (struct glyph_string *s) +{ + int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x; + bool raised_p, left_p, right_p; + struct glyph *last_glyph; + struct haiku_rect clip_rect; + + last_x = ((s->row->full_width_p && !s->w->pseudo_window_p) + ? WINDOW_RIGHT_EDGE_X (s->w) + : window_box_right (s->w, s->area)); + + /* The glyph that may have a right box line. For static + compositions and images, the right-box flag is on the first glyph + of the glyph string; for other types it's on the last glyph. */ + if (s->cmp || s->img) + last_glyph = s->first_glyph; + else if (s->first_glyph->type == COMPOSITE_GLYPH + && s->first_glyph->u.cmp.automatic) + { + /* For automatic compositions, we need to look up the last glyph + in the composition. */ + struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area]; + struct glyph *g = s->first_glyph; + for (last_glyph = g++; + g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id + && g->slice.cmp.to < s->cmp_to; + last_glyph = g++) + ; + } + else + last_glyph = s->first_glyph + s->nchars - 1; + + vwidth = eabs (s->face->box_vertical_line_width); + hwidth = eabs (s->face->box_horizontal_line_width); + raised_p = s->face->box == FACE_RAISED_BOX; + left_x = s->x; + right_x = (s->row->full_width_p && s->extends_to_end_of_line_p + ? last_x + : min (last_x, s->x + s->background_width)); + top_y = s->y; + bottom_y = top_y + s->height; + + left_p = (s->first_glyph->left_box_line_p + || (s->hl == DRAW_MOUSE_FACE + && (s->prev == NULL + || s->prev->hl != s->hl))); + right_p = (last_glyph->right_box_line_p + || (s->hl == DRAW_MOUSE_FACE + && (s->next == NULL + || s->next->hl != s->hl))); + + get_glyph_string_clip_rect (s, &clip_rect); + + if (s->face->box == FACE_SIMPLE_BOX) + haiku_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth, + vwidth, left_p, right_p, &clip_rect); + else + haiku_draw_relief_rect (s, left_x, top_y, right_x, bottom_y, hwidth, + vwidth, raised_p, true, true, left_p, right_p, + &clip_rect); +} + +static void +haiku_draw_glyph_string_foreground (struct glyph_string *s) +{ + int i, x; + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->x + max (s->face->box_vertical_line_width, 0); + else + x = s->x; + + void *view = FRAME_HAIKU_VIEW (s->f); + + if (s->font_not_found_p) + { + BView_StartClip (view); + if (s->hl == DRAW_CURSOR) + BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg); + else + BView_SetHighColor (view, s->face->foreground); + for (i = 0; i < s->nchars; ++i) + { + struct glyph *g = s->first_glyph + i; + BView_StrokeRectangle (view, x, s->y, g->pixel_width, + s->height); + x += g->pixel_width; + } + BView_EndClip (view); + } + else + { + struct font *ft = s->font; + int off = ft->baseline_offset; + int y; + + if (ft->vertical_centering) + off = VCENTER_BASELINE_OFFSET (ft, s->f) - off; + y = s->ybase - off; + if (s->for_overlaps || (s->background_filled_p && s->hl != DRAW_CURSOR)) + ft->driver->draw (s, 0, s->nchars, x, y, false); + else + ft->driver->draw (s, 0, s->nchars, x, y, true); + + if (s->face->overstrike) + ft->driver->draw (s, 0, s->nchars, x + 1, y, false); + } +} + +static void +haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s) +{ + struct glyph *glyph = s->first_glyph; + unsigned char2b[8]; + int x, i, j; + + /* If first glyph of S has a left box line, start drawing the text + of S to the right of that box line. */ + if (s->face && s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->x + max (s->face->box_vertical_line_width, 0); + else + x = s->x; + + s->char2b = char2b; + + for (i = 0; i < s->nchars; i++, glyph++) + { +#ifdef GCC_LINT + enum { PACIFY_GCC_BUG_81401 = 1 }; +#else + enum { PACIFY_GCC_BUG_81401 = 0 }; +#endif + char buf[7 + PACIFY_GCC_BUG_81401]; + char *str = NULL; + int len = glyph->u.glyphless.len; + + if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM) + { + if (len > 0 + && CHAR_TABLE_P (Vglyphless_char_display) + && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) + >= 1)) + { + Lisp_Object acronym + = (! glyph->u.glyphless.for_no_font + ? CHAR_TABLE_REF (Vglyphless_char_display, + glyph->u.glyphless.ch) + : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); + if (STRINGP (acronym)) + str = SSDATA (acronym); + } + } + else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE) + { + unsigned int ch = glyph->u.glyphless.ch; + eassume (ch <= MAX_CHAR); + sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch); + str = buf; + } + + if (str) + { + int upper_len = (len + 1) / 2; + + /* It is assured that all LEN characters in STR is ASCII. */ + for (j = 0; j < len; j++) + char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF; + + s->font->driver->draw (s, 0, upper_len, + x + glyph->slice.glyphless.upper_xoff, + s->ybase + glyph->slice.glyphless.upper_yoff, + false); + s->font->driver->draw (s, upper_len, len, + x + glyph->slice.glyphless.lower_xoff, + s->ybase + glyph->slice.glyphless.lower_yoff, + false); + } + BView_StartClip (FRAME_HAIKU_VIEW (s->f)); + if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE) + BView_FillRectangle (FRAME_HAIKU_VIEW (s->f), + x, s->ybase - glyph->ascent, + glyph->pixel_width - 1, + glyph->ascent + glyph->descent - 1); + BView_EndClip (FRAME_HAIKU_VIEW (s->f)); + x += glyph->pixel_width; + } +} + +static void +haiku_draw_stretch_glyph_string (struct glyph_string *s) +{ + eassert (s->first_glyph->type == STRETCH_GLYPH); + + if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p) + { + int width, background_width = s->background_width; + int x = s->x; + + if (!s->row->reversed_p) + { + int left_x = window_box_left_offset (s->w, TEXT_AREA); + + if (x < left_x) + { + background_width -= left_x - x; + x = left_x; + } + } + else + { + /* In R2L rows, draw the cursor on the right edge of the + stretch glyph. */ + int right_x = window_box_right (s->w, TEXT_AREA); + if (x + background_width > right_x) + background_width -= x - right_x; + x += background_width; + } + + width = min (FRAME_COLUMN_WIDTH (s->f), background_width); + + haiku_maybe_draw_background (s, 1); + + if (width < background_width) + { + int y = s->y; + int w = background_width - width, h = s->height; + + if (!s->face->stipple) + { + uint32_t bkg; + if (s->hl == DRAW_MOUSE_FACE) + haiku_mouse_face_colors (s, NULL, &bkg); + else + bkg = s->face->background; + + void *view = FRAME_HAIKU_VIEW (s->f); + + BView_StartClip (view); + BView_SetHighColor (view, bkg); + BView_FillRectangle (view, x, y, w, h); + BView_EndClip (view); + } + } + } + else if (!s->background_filled_p) + { + int background_width = s->background_width; + int x = s->x, text_left_x = window_box_left_offset (s->w, TEXT_AREA); + if (x < text_left_x && !s->row->mode_line_p) + { + int left_x = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s->w); + int right_x = text_left_x; + + if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (s->w)) + left_x += WINDOW_LEFT_FRINGE_WIDTH (s->w); + else + right_x -= WINDOW_LEFT_FRINGE_WIDTH (s->w); + + /* Adjust X and BACKGROUND_WIDTH to fit inside the space + between LEFT_X and RIGHT_X. */ + if (x < left_x) + { + background_width -= left_x - x; + x = left_x; + } + if (x + background_width > right_x) + background_width = right_x - x; + } + + if (background_width > 0) + { + void *view = FRAME_HAIKU_VIEW (s->f); + BView_StartClip (view); + uint32_t bkg; + if (s->hl == DRAW_MOUSE_FACE) + haiku_mouse_face_colors (s, NULL, &bkg); + else if (s->hl == DRAW_CURSOR) + bkg = FRAME_CURSOR_COLOR (s->f).pixel; + else + bkg = s->face->background; + + BView_SetHighColor (view, bkg); + BView_FillRectangle (view, x, s->y, background_width, s->height); + BView_EndClip (view); + } + } + s->background_filled_p = 1; +} + +static void +haiku_start_clip (struct glyph_string *s) +{ + void *view = FRAME_HAIKU_VIEW (s->f); + BView_draw_lock (view); + BView_StartClip (view); +} + +static void +haiku_end_clip (struct glyph_string *s) +{ + void *view = FRAME_HAIKU_VIEW (s->f); + BView_draw_unlock (view); + BView_EndClip (view); +} + +static void +haiku_clip_to_row (struct window *w, struct glyph_row *row, + enum glyph_row_area area) +{ + struct frame *f = WINDOW_XFRAME (w); + int window_x, window_y, window_width; + int x, y, width, height; + + window_box (w, area, &window_x, &window_y, &window_width, 0); + + x = window_x; + y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y)); + y = max (y, window_y); + width = window_width; + height = row->visible_height; + + BView_ClipToRect (FRAME_HAIKU_VIEW (f), x, y, width, height); +} + +static void +haiku_update_begin (struct frame *f) +{ + void *view = FRAME_HAIKU_VIEW (f); + BView_draw_lock (view); +} + +static void +haiku_update_end (struct frame *f) +{ + void *view = FRAME_HAIKU_VIEW (f); + BView_draw_unlock (view); + MOUSE_HL_INFO (f)->mouse_face_defer = false; + flush_frame (f); +} + +static void +haiku_draw_composite_glyph_string_foreground (struct glyph_string *s) +{ + int i, j, x; + struct font *font = s->font; + void *view = FRAME_HAIKU_VIEW (s->f); + + /* If first glyph of S has a left box line, start drawing the text + of S to the right of that box line. */ + if (s->face && s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->x + max (s->face->box_vertical_line_width, 0); + else + x = s->x; + + /* S is a glyph string for a composition. S->cmp_from is the index + of the first character drawn for glyphs of this composition. + S->cmp_from == 0 means we are drawing the very first character of + this composition. */ + + /* Draw a rectangle for the composition if the font for the very + first character of the composition could not be loaded. */ + + if (s->font_not_found_p && !s->cmp_from) + { + BView_StartClip (view); + if (s->hl == DRAW_CURSOR) + BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg); + else + BView_SetHighColor (view, s->face->foreground); + BView_StrokeRectangle (view, s->x, s->y, s->width - 1, s->height - 1); + BView_EndClip (view); + } + else if (!s->first_glyph->u.cmp.automatic) + { + int y = s->ybase; + + for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++) + /* TAB in a composition means display glyphs with padding + space on the left or right. */ + if (COMPOSITION_GLYPH (s->cmp, j) != '\t') + { + int xx = x + s->cmp->offsets[j * 2]; + int yy = y - s->cmp->offsets[j * 2 + 1]; + + font->driver->draw (s, j, j + 1, xx, yy, false); + if (s->face->overstrike) + font->driver->draw (s, j, j + 1, xx + 1, yy, false); + } + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + Lisp_Object glyph; + int y = s->ybase; + int width = 0; + + for (i = j = s->cmp_from; i < s->cmp_to; i++) + { + glyph = LGSTRING_GLYPH (gstring, i); + if (NILP (LGLYPH_ADJUSTMENT (glyph))) + width += LGLYPH_WIDTH (glyph); + else + { + int xoff, yoff, wadjust; + + if (j < i) + { + font->driver->draw (s, j, i, x, y, false); + if (s->face->overstrike) + font->driver->draw (s, j, i, x + 1, y, false); + x += width; + } + xoff = LGLYPH_XOFF (glyph); + yoff = LGLYPH_YOFF (glyph); + wadjust = LGLYPH_WADJUST (glyph); + font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false); + if (s->face->overstrike) + font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, + false); + x += wadjust; + j = i + 1; + width = 0; + } + } + if (j < i) + { + font->driver->draw (s, j, i, x, y, false); + if (s->face->overstrike) + font->driver->draw (s, j, i, x + 1, y, false); + } + } +} + +static void +haiku_draw_image_relief (struct glyph_string *s) +{ + int x1, y1, thick; + bool raised_p, top_p, bot_p, left_p, right_p; + int extra_x, extra_y; + struct haiku_rect r; + int x = s->x; + int y = s->ybase - image_ascent (s->img, s->face, &s->slice); + + /* If first glyph of S has a left box line, start drawing it to the + right of that line. */ + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p + && s->slice.x == 0) + x += max (s->face->box_vertical_line_width, 0); + + /* If there is a margin around the image, adjust x- and y-position + by that margin. */ + if (s->slice.x == 0) + x += s->img->hmargin; + if (s->slice.y == 0) + y += s->img->vmargin; + + if (s->hl == DRAW_IMAGE_SUNKEN + || s->hl == DRAW_IMAGE_RAISED) + { + thick = (tab_bar_button_relief < 0 + ? DEFAULT_TAB_BAR_BUTTON_RELIEF + : (tool_bar_button_relief < 0 + ? DEFAULT_TOOL_BAR_BUTTON_RELIEF + : min (tool_bar_button_relief, 1000000))); + raised_p = s->hl == DRAW_IMAGE_RAISED; + } + else + { + thick = eabs (s->img->relief); + raised_p = s->img->relief > 0; + } + + x1 = x + s->slice.width - 1; + y1 = y + s->slice.height - 1; + + extra_x = extra_y = 0; + if (s->face->id == TAB_BAR_FACE_ID) + { + if (CONSP (Vtab_bar_button_margin) + && FIXNUMP (XCAR (Vtab_bar_button_margin)) + && FIXNUMP (XCDR (Vtab_bar_button_margin))) + { + extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)); + extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)); + } + else if (FIXNUMP (Vtab_bar_button_margin)) + extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin); + } + + if (s->face->id == TOOL_BAR_FACE_ID) + { + if (CONSP (Vtool_bar_button_margin) + && FIXNUMP (XCAR (Vtool_bar_button_margin)) + && FIXNUMP (XCDR (Vtool_bar_button_margin))) + { + extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin)); + extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin)); + } + else if (FIXNUMP (Vtool_bar_button_margin)) + extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin); + } + + top_p = bot_p = left_p = right_p = false; + + if (s->slice.x == 0) + x -= thick + extra_x, left_p = true; + if (s->slice.y == 0) + y -= thick + extra_y, top_p = true; + if (s->slice.x + s->slice.width == s->img->width) + x1 += thick + extra_x, right_p = true; + if (s->slice.y + s->slice.height == s->img->height) + y1 += thick + extra_y, bot_p = true; + + get_glyph_string_clip_rect (s, &r); + haiku_draw_relief_rect (s, x, y, x1, y1, thick, thick, raised_p, + top_p, bot_p, left_p, right_p, &r); +} + +static void +haiku_draw_image_glyph_string (struct glyph_string *s) +{ + struct face *face; + + if (s->hl == DRAW_MOUSE_FACE) + { + face = FACE_FROM_ID_OR_NULL (s->f, + MOUSE_HL_INFO (s->f)->mouse_face_face_id); + if (!face) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + } + else + face = s->face; + + int box_line_hwidth = max (s->face->box_vertical_line_width, 0); + int box_line_vwidth = max (s->face->box_horizontal_line_width, 0); + + int x, y; + int height, width; + + height = s->height; + if (s->slice.y == 0) + height -= box_line_vwidth; + if (s->slice.y + s->slice.height >= s->img->height) + height -= box_line_vwidth; + + width = s->background_width; + x = s->x; + if (s->first_glyph->left_box_line_p + && s->slice.x == 0) + { + x += box_line_hwidth; + width -= box_line_hwidth; + } + + y = s->y; + if (s->slice.y == 0) + y += box_line_vwidth; + + void *view = FRAME_HAIKU_VIEW (s->f); + void *bitmap = s->img->pixmap; + + /* Fill background with face under the image. Do it only if row is + taller than image or if image has a clip mask to reduce + flickering. */ + s->stippled_p = s->face->stipple != 0; + if (height > s->slice.height + || s->img->hmargin + || s->img->vmargin + || s->img->mask + || s->img->pixmap == 0 + || s->width != s->background_width) + { + BView_draw_lock (view); + BView_StartClip (view); + BView_SetHighColor (view, face->background); + BView_FillRectangle (view, x, y, width, height); + BView_EndClip (view); + BView_draw_unlock (view); + } + + if (bitmap) + { + struct haiku_rect nr; + Emacs_Rectangle cr, ir, r; + + get_glyph_string_clip_rect (s, &nr); + CONVERT_TO_EMACS_RECT (cr, nr); + x = s->x; + y = s->ybase - image_ascent (s->img, s->face, &s->slice); + + if (s->slice.x == 0) + x += s->img->hmargin; + if (s->slice.y == 0) + y += s->img->vmargin; + + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p + && s->slice.x == 0) + x += max (s->face->box_vertical_line_width, 0); + + ir.x = x; + ir.y = y; + ir.width = s->slice.width; + ir.height = s->slice.height; + r = ir; + + void *mask = s->img->mask; + + if (gui_intersect_rectangles (&cr, &ir, &r)) + { + BView_draw_lock (view); + BView_StartClip (view); + + haiku_clip_to_string (s); + if (s->img->have_be_transforms_p) + { + bitmap = BBitmap_transform_bitmap (bitmap, + s->img->mask, + face->background, + s->img->be_rotate, + s->img->width, + s->img->height); + mask = NULL; + } + + BView_DrawBitmap (view, bitmap, + s->slice.x + r.x - x, + s->slice.y + r.y - y, + r.width, r.height, + r.x, r.y, r.width, r.height); + if (mask) + BView_DrawMask (mask, view, + s->slice.x + r.x - x, + s->slice.y + r.y - y, + r.width, r.height, + r.x, r.y, r.width, r.height, + face->background); + + if (s->img->have_be_transforms_p) + BBitmap_free (bitmap); + BView_EndClip (view); + BView_draw_unlock (view); + } + + if (s->hl == DRAW_CURSOR) + { + BView_draw_lock (view); + BView_StartClip (view); + BView_SetPenSize (view, 1); + BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel); + BView_StrokeRectangle (view, r.x, r.y, r.width, r.height); + BView_EndClip (view); + BView_draw_unlock (view); + } + } + + if (!s->for_overlaps && s->face->box != FACE_NO_BOX) + haiku_draw_string_box (s); + + if (s->img->relief + || s->hl == DRAW_IMAGE_RAISED + || s->hl == DRAW_IMAGE_SUNKEN) + haiku_draw_image_relief (s); +} + +static void +haiku_draw_glyph_string (struct glyph_string *s) +{ + block_input (); + prepare_face_for_display (s->f, s->face); + + if (s->next && s->right_overhang && !s->for_overlaps) + { + int width; + struct glyph_string *next; + + for (width = 0, next = s->next; + next && width < s->right_overhang; + width += next->width, next = next->next) + if (next->first_glyph->type != IMAGE_GLYPH) + { + prepare_face_for_display (s->f, s->next->face); + haiku_start_clip (s->next); + haiku_clip_to_string (s->next); + if (next->first_glyph->type != STRETCH_GLYPH) + haiku_maybe_draw_background (s->next, 1); + else + haiku_draw_stretch_glyph_string (s->next); + next->num_clips = 0; + haiku_end_clip (s); + } + } + + haiku_start_clip (s); + haiku_inverse_clip_to_scroll_bars (s->f); + + if (!s->for_overlaps && s->face->box != FACE_NO_BOX + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) + { + haiku_clip_to_string (s); + haiku_maybe_draw_background (s, 1); + haiku_draw_string_box (s); + } + else if (!s->clip_head && !s->clip_tail && + ((s->prev && s->left_overhang && s->prev->hl != s->hl) || + (s->next && s->right_overhang && s->next->hl != s->hl))) + haiku_clip_to_string_exactly (s, s); + else + haiku_clip_to_string (s); + + if (s->for_overlaps) + s->background_filled_p = 1; + + switch (s->first_glyph->type) + { + case COMPOSITE_GLYPH: + if (s->for_overlaps || (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic)) + s->background_filled_p = 1; + else + haiku_maybe_draw_background (s, 1); + haiku_draw_composite_glyph_string_foreground (s); + break; + case CHAR_GLYPH: + if (s->for_overlaps) + s->background_filled_p = 1; + else + haiku_maybe_draw_background (s, 0); + haiku_draw_glyph_string_foreground (s); + break; + case STRETCH_GLYPH: + haiku_draw_stretch_glyph_string (s); + break; + case IMAGE_GLYPH: + haiku_draw_image_glyph_string (s); + break; + case GLYPHLESS_GLYPH: + if (s->for_overlaps) + s->background_filled_p = 1; + else + haiku_maybe_draw_background (s, 1); + haiku_draw_glyphless_glyph_string_foreground (s); + break; + } + + if (!s->for_overlaps) + { + uint32_t dcol; + struct face *face; + if (s->hl == DRAW_MOUSE_FACE) + { + face = FACE_FROM_ID_OR_NULL (s->f, + MOUSE_HL_INFO (s->f)->mouse_face_face_id); + if (!face) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + } + else + face = s->face; + dcol = face->foreground; + + haiku_draw_text_decoration (s, face, dcol, s->width, s->x); + + if (s->prev) + { + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->hl = s->hl; + prev->face = s->face; + haiku_start_clip (s); + haiku_clip_to_string_exactly (s, prev); + if (prev->first_glyph->type == CHAR_GLYPH) + haiku_draw_glyph_string_foreground (prev); + else + haiku_draw_composite_glyph_string_foreground (prev); + haiku_end_clip (s); + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } + } + + if (s->next) + { + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + haiku_start_clip (s); + haiku_clip_to_string_exactly (s, next); + if (next->first_glyph->type == CHAR_GLYPH) + haiku_draw_glyph_string_foreground (next); + else + haiku_draw_composite_glyph_string_foreground (next); + haiku_end_clip (s); + next->background_filled_p = 0; + next->hl = save; + next->face = save_face; + next->clip_head = next; + next->num_clips = 0; + } + } + } + s->num_clips = 0; + haiku_end_clip (s); + unblock_input (); +} + +static void +haiku_after_update_window_line (struct window *w, + struct glyph_row *desired_row) +{ + eassert (w); + struct frame *f; + int width, height; + + if (!desired_row->mode_line_p && !w->pseudo_window_p) + desired_row->redraw_fringe_bitmaps_p = true; + if (windows_or_buffers_changed + && desired_row->full_width_p + && (f = XFRAME (w->frame), + width = FRAME_INTERNAL_BORDER_WIDTH (f), + width != 0) + && (height = desired_row->visible_height, + height > 0)) + { + int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); + int face_id = + !NILP (Vface_remapping_alist) + ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) + : INTERNAL_BORDER_FACE_ID; + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + + block_input (); + if (face) + { + void *view = FRAME_HAIKU_VIEW (f); + BView_StartClip (view); + BView_SetHighColor (view, face->background_defaulted_p ? + FRAME_BACKGROUND_PIXEL (f) : face->background); + BView_FillRectangle (view, 0, y, width, height); + BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width, + y, width, height); + BView_EndClip (view); + } + else + { + haiku_clear_frame_area (f, 0, y, width, height); + haiku_clear_frame_area (f, FRAME_PIXEL_WIDTH (f) - width, + y, width, height); + } + unblock_input (); + } +} + +static void +haiku_set_window_size (struct frame *f, bool change_gravity, + int width, int height) +{ + if (FRAME_HAIKU_WINDOW (f)) + { + block_input (); + BWindow_resize (FRAME_HAIKU_WINDOW (f), width, height); + unblock_input (); + } +} + +static void +haiku_draw_window_cursor (struct window *w, + struct glyph_row *glyph_row, + int x, int y, + enum text_cursor_kinds cursor_type, + int cursor_width, bool on_p, bool active_p) +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + + struct glyph *phys_cursor_glyph; + struct glyph *cursor_glyph; + + void *view = FRAME_HAIKU_VIEW (f); + + int fx, fy, h, cursor_height; + + if (!on_p) + return; + + if (cursor_type == NO_CURSOR) + { + w->phys_cursor_width = 0; + return; + } + + w->phys_cursor_on_p = true; + w->phys_cursor_type = cursor_type; + + phys_cursor_glyph = get_phys_cursor_glyph (w); + + if (!phys_cursor_glyph) + { + if (glyph_row->exact_window_width_line_p + && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) + { + glyph_row->cursor_in_fringe_p = 1; + draw_fringe_bitmap (w, glyph_row, 0); + } + return; + } + + get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); + + if (cursor_type == BAR_CURSOR) + { + if (cursor_width < 1) + cursor_width = max (FRAME_CURSOR_WIDTH (f), 1); + if (cursor_width < w->phys_cursor_width) + w->phys_cursor_width = cursor_width; + } + else if (cursor_type == HBAR_CURSOR) + { + cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width; + if (cursor_height > glyph_row->height) + cursor_height = glyph_row->height; + if (h > cursor_height) + fy += h - cursor_height; + h = cursor_height; + } + + if (glyph_row->exact_window_width_line_p + && (glyph_row->reversed_p + ? (w->phys_cursor.hpos < 0) + : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]))) + { + glyph_row->cursor_in_fringe_p = true; + draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p); + return; + } + + if (cursor_type == HOLLOW_BOX_CURSOR && + phys_cursor_glyph->type != IMAGE_GLYPH) + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + + BView_StartClip (view); + BView_SetHighColor (view, FRAME_CURSOR_COLOR (f).pixel); + haiku_clip_to_row (w, glyph_row, TEXT_AREA); + + switch (cursor_type) + { + default: + case DEFAULT_CURSOR: + case NO_CURSOR: + break; + case HBAR_CURSOR: + BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h); + break; + case BAR_CURSOR: + cursor_glyph = get_phys_cursor_glyph (w); + if (cursor_glyph->resolved_level & 1) + BView_FillRectangle (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width, + fy, w->phys_cursor_width, h); + else + BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h); + break; + case HOLLOW_BOX_CURSOR: + if (phys_cursor_glyph->type != IMAGE_GLYPH) + { + BView_SetPenSize (view, 1); + BView_StrokeRectangle (view, fx, fy, w->phys_cursor_width, h); + } + else + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + break; + case FILLED_BOX_CURSOR: + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + } + BView_EndClip (view); +} + +static void +haiku_show_hourglass (struct frame *f) +{ + if (FRAME_OUTPUT_DATA (f)->hourglass_p) + return; + + block_input (); + FRAME_OUTPUT_DATA (f)->hourglass_p = 1; + + if (FRAME_HAIKU_VIEW (f)) + BView_set_view_cursor (FRAME_HAIKU_VIEW (f), + FRAME_OUTPUT_DATA (f)->hourglass_cursor); + unblock_input (); +} + +static void +haiku_hide_hourglass (struct frame *f) +{ + if (!FRAME_OUTPUT_DATA (f)->hourglass_p) + return; + + block_input (); + FRAME_OUTPUT_DATA (f)->hourglass_p = 0; + + if (FRAME_HAIKU_VIEW (f)) + BView_set_view_cursor (FRAME_HAIKU_VIEW (f), + FRAME_OUTPUT_DATA (f)->current_cursor); + unblock_input (); +} + +static void +haiku_compute_glyph_string_overhangs (struct glyph_string *s) +{ + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) + { + struct font_metrics metrics; + + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; + } + else if (s->cmp) + { + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; + } +} + +static void +haiku_draw_vertical_window_border (struct window *w, + int x, int y_0, int y_1) +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + struct face *face; + + face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); + void *view = FRAME_HAIKU_VIEW (f); + BView_StartClip (view); + if (face) + BView_SetHighColor (view, face->foreground); + BView_StrokeLine (view, x, y_0, x, y_1); + BView_EndClip (view); +} + +static void +haiku_set_scroll_bar_default_width (struct frame *f) +{ + int unit = FRAME_COLUMN_WIDTH (f); + FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = BScrollBar_default_size (0) + 1; + FRAME_CONFIG_SCROLL_BAR_COLS (f) = + (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; +} + +static void +haiku_set_scroll_bar_default_height (struct frame *f) +{ + int height = FRAME_LINE_HEIGHT (f); + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = BScrollBar_default_size (1) + 1; + FRAME_CONFIG_SCROLL_BAR_LINES (f) = + (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height; +} + +static void +haiku_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID); + struct face *face_first + = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); + struct face *face_last + = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); + unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); + unsigned long color_first = (face_first + ? face_first->foreground + : FRAME_FOREGROUND_PIXEL (f)); + unsigned long color_last = (face_last + ? face_last->foreground + : FRAME_FOREGROUND_PIXEL (f)); + void *view = FRAME_HAIKU_VIEW (f); + + BView_StartClip (view); + + if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3)) + /* A vertical divider, at least three pixels wide: Draw first and + last pixels differently. */ + { + BView_SetHighColor (view, color_first); + BView_StrokeLine (view, x0, y0, x0, y1); + BView_SetHighColor (view, color); + BView_StrokeLine (view, x0 + 1, y0, x0 + 1, y1); + BView_SetHighColor (view, color_last); + BView_StrokeLine (view, x1 - 1, y0, x1 - 1, y1); + } + BView_EndClip (view); +} + +static void +haiku_condemn_scroll_bars (struct frame *frame) +{ + if (!NILP (FRAME_SCROLL_BARS (frame))) + { + if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) + { + /* Prepend scrollbars to already condemned ones. */ + Lisp_Object last = FRAME_SCROLL_BARS (frame); + + while (!NILP (XSCROLL_BAR (last)->next)) + last = XSCROLL_BAR (last)->next; + + XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame); + XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last; + } + + fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame)); + fset_scroll_bars (frame, Qnil); + } +} + +static void +haiku_redeem_scroll_bar (struct window *w) +{ + struct scroll_bar *bar; + Lisp_Object barobj; + struct frame *f; + + if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) + { + bar = XSCROLL_BAR (w->vertical_scroll_bar); + /* Unlink it from the condemned list. */ + f = XFRAME (WINDOW_FRAME (w)); + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar)) + /* It's not condemned. Everything's fine. */ + goto horizontal; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + w->vertical_scroll_bar)) + fset_condemned_scroll_bars (f, bar->next); + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + emacs_abort (); + } + else + XSCROLL_BAR (bar->prev)->next = bar->next; + + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (barobj, bar); + fset_scroll_bars (f, barobj); + if (! NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + } + horizontal: + if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)) + { + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + /* Unlink it from the condemned list. */ + f = XFRAME (WINDOW_FRAME (w)); + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar)) + /* It's not condemned. Everything's fine. */ + return; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + w->horizontal_scroll_bar)) + fset_condemned_scroll_bars (f, bar->next); + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + emacs_abort (); + } + else + XSCROLL_BAR (bar->prev)->next = bar->next; + + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (barobj, bar); + fset_scroll_bars (f, barobj); + if (! NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + } +} + +static void +haiku_judge_scroll_bars (struct frame *f) +{ + Lisp_Object bar, next; + + bar = FRAME_CONDEMNED_SCROLL_BARS (f); + + /* Clear out the condemned list now so we won't try to process any + more events on the hapless scroll bars. */ + fset_condemned_scroll_bars (f, Qnil); + + for (; ! NILP (bar); bar = next) + { + struct scroll_bar *b = XSCROLL_BAR (bar); + + haiku_scroll_bar_remove (b); + + next = b->next; + b->next = b->prev = Qnil; + } + + /* Now there should be no references to the condemned scroll bars, + and they should get garbage-collected. */ +} + +static struct scroll_bar * +haiku_scroll_bar_create (struct window *w, int left, int top, + int width, int height, bool horizontal_p) +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + Lisp_Object barobj; + + void *sb = NULL; + void *vw = FRAME_HAIKU_VIEW (f); + + block_input (); + struct scroll_bar *bar + = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER); + + XSETWINDOW (bar->window, w); + bar->top = top; + bar->left = left; + bar->width = width; + bar->height = height; + bar->position = 0; + bar->total = 0; + bar->dragging = 0; + bar->update = -1; + bar->horizontal = horizontal_p; + + sb = BScrollBar_make_for_view (vw, horizontal_p, + left, top, left + width - 1, + top + height - 1, bar); + + BView_publish_scroll_bar (vw, left, top, width, height); + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + bar->scroll_bar = sb; + XSETVECTOR (barobj, bar); + fset_scroll_bars (f, barobj); + + if (!NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + + unblock_input (); + return bar; +} + +static void +haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position) +{ + eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)); + Lisp_Object barobj; + struct scroll_bar *bar; + int top, height, left, width; + int window_x, window_width; + + /* Get window dimensions. */ + window_box (w, ANY_AREA, &window_x, 0, &window_width, 0); + left = window_x; + width = window_width; + top = WINDOW_SCROLL_BAR_AREA_Y (w); + height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w); + + block_input (); + + if (NILP (w->horizontal_scroll_bar)) + { + bar = haiku_scroll_bar_create (w, left, top, width, height, true); + BView_scroll_bar_update (bar->scroll_bar, portion, whole, position); + bar->update = position; + bar->position = position; + bar->total = whole; + } + else + { + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + + if (bar->left != left || bar->top != top || + bar->width != width || bar->height != height) + { + void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w)); + BView_forget_scroll_bar (view, bar->left, bar->top, + bar->width, bar->height); + BView_move_frame (bar->scroll_bar, left, top, + left + width - 1, top + height - 1); + BView_publish_scroll_bar (view, left, top, width, height); + bar->left = left; + bar->top = top; + bar->width = width; + bar->height = height; + } + + if (!bar->dragging) + { + BView_scroll_bar_update (bar->scroll_bar, portion, whole, position); + BView_invalidate (bar->scroll_bar); + } + } + bar->position = position; + bar->total = whole; + XSETVECTOR (barobj, bar); + wset_horizontal_scroll_bar (w, barobj); + unblock_input (); +} + +static void +haiku_set_vertical_scroll_bar (struct window *w, + int portion, int whole, int position) +{ + eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w)); + Lisp_Object barobj; + struct scroll_bar *bar; + int top, height, left, width; + int window_y, window_height; + + /* Get window dimensions. */ + window_box (w, ANY_AREA, 0, &window_y, 0, &window_height); + top = window_y; + height = window_height; + + /* Compute the left edge and the width of the scroll bar area. */ + left = WINDOW_SCROLL_BAR_AREA_X (w); + width = WINDOW_SCROLL_BAR_AREA_WIDTH (w); + block_input (); + + if (NILP (w->vertical_scroll_bar)) + { + bar = haiku_scroll_bar_create (w, left, top, width, height, false); + BView_scroll_bar_update (bar->scroll_bar, portion, whole, position); + bar->position = position; + bar->total = whole; + } + else + { + bar = XSCROLL_BAR (w->vertical_scroll_bar); + + if (bar->left != left || bar->top != top || + bar->width != width || bar->height != height) + { + void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w)); + BView_forget_scroll_bar (view, bar->left, bar->top, + bar->width, bar->height); + BView_move_frame (bar->scroll_bar, left, top, + left + width - 1, top + height - 1); + flush_frame (WINDOW_XFRAME (w)); + BView_publish_scroll_bar (view, left, top, width, height); + bar->left = left; + bar->top = top; + bar->width = width; + bar->height = height; + } + + if (!bar->dragging) + { + BView_scroll_bar_update (bar->scroll_bar, portion, whole, position); + bar->update = position; + BView_invalidate (bar->scroll_bar); + } + } + + bar->position = position; + bar->total = whole; + + XSETVECTOR (barobj, bar); + wset_vertical_scroll_bar (w, barobj); + unblock_input (); +} + +static void +haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row, + struct draw_fringe_bitmap_params *p) +{ + void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w))); + struct face *face = p->face; + + BView_draw_lock (view); + BView_StartClip (view); + + haiku_clip_to_row (w, row, ANY_AREA); + if (p->bx >= 0) + { + BView_SetHighColor (view, face->background); + BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny); + } + + if (p->which && p->which < fringe_bitmap_fillptr) + { + void *bitmap = fringe_bmps[p->which]; + + uint32_t col; + + if (!p->cursor_p) + col = face->foreground; + else if (p->overlay_p) + col = face->background; + else + col = FRAME_CURSOR_COLOR (XFRAME (WINDOW_FRAME (w))).pixel; + +#if 0 /* See comment in BView_DrawFringeBitmap. */ + BView_SetLowColor (view, col); + BView_DrawBitmapWithEraseOp (view, bitmap, p->x, p->y, p->wd, p->h); +#else + BView_DrawFringeBitmap (bitmap, view, p->x, p->y, + p->wd, p->h, col | ((unsigned) 255 << 24)); +#endif + } + BView_EndClip (view); + BView_draw_unlock (view); +} + +static void +haiku_define_fringe_bitmap (int which, unsigned short *bits, + int h, int wd) +{ + if (which >= fringe_bitmap_fillptr) + { + int i = fringe_bitmap_fillptr; + fringe_bitmap_fillptr = which + 20; + fringe_bmps = !i ? xmalloc (fringe_bitmap_fillptr * sizeof (void *)) : + xrealloc (fringe_bmps, fringe_bitmap_fillptr * sizeof (void *)); + + while (i < fringe_bitmap_fillptr) + fringe_bmps[i++] = NULL; + } + + fringe_bmps[which] = BBitmap_new (wd, h, 1); + BBitmap_import_mono_bits (fringe_bmps[which], bits, wd, h); +} + +static void +haiku_destroy_fringe_bitmap (int which) +{ + if (which >= fringe_bitmap_fillptr) + return; + + if (fringe_bmps[which]) + BBitmap_free (fringe_bmps[which]); + fringe_bmps[which] = NULL; +} + +static void +haiku_scroll_run (struct window *w, struct run *run) +{ + struct frame *f = XFRAME (w->frame); + void *view = FRAME_HAIKU_VIEW (f); + int x, y, width, height, from_y, to_y, bottom_y; + window_box (w, ANY_AREA, &x, &y, &width, &height); + + from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); + to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y); + bottom_y = y + height; + + if (to_y < from_y) + { + /* Scrolling up. Make sure we don't copy part of the mode + line at the bottom. */ + if (from_y + run->height > bottom_y) + height = bottom_y - from_y; + else + height = run->height; + } + else + { + /* Scrolling down. Make sure we don't copy over the mode line. + at the bottom. */ + if (to_y + run->height > bottom_y) + height = bottom_y - to_y; + else + height = run->height; + } + + if (!height) + return; + + block_input (); + gui_clear_cursor (w); + BView_draw_lock (view); + BView_StartClip (view); + BView_CopyBits (view, x, from_y, width, height, + x, to_y, width, height); + BView_EndClip (view); + BView_draw_unlock (view); + + unblock_input (); +} + +static void +haiku_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, + enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y, + Time *timestamp) +{ + block_input (); + if (!fp) + return; + Lisp_Object frame, tail; + struct frame *f1 = NULL; + FOR_EACH_FRAME (tail, frame) + XFRAME (frame)->mouse_moved = false; + + if (gui_mouse_grabbed (x_display_list) && !EQ (track_mouse, Qdropping)) + f1 = x_display_list->last_mouse_frame; + + if (!f1 || FRAME_TOOLTIP_P (f1)) + f1 = ((EQ (track_mouse, Qdropping) && gui_mouse_grabbed (x_display_list)) + ? x_display_list->last_mouse_frame + : NULL); + + if (!f1 && insist > 0) + f1 = SELECTED_FRAME (); + + if (f1) + { + int sx, sy; + void *view = FRAME_HAIKU_VIEW (f1); + if (view) + { + BView_get_mouse (view, &sx, &sy); + + remember_mouse_glyph (f1, sx, sy, &x_display_list->last_mouse_glyph); + x_display_list->last_mouse_glyph_frame = f1; + + *bar_window = Qnil; + *part = scroll_bar_above_handle; + *fp = f1; + XSETINT (*x, sx); + XSETINT (*y, sy); + } + } + + unblock_input (); +} + +static void +haiku_flush (struct frame *f) +{ + if (FRAME_VISIBLE_P (f)) + BWindow_Flush (FRAME_HAIKU_WINDOW (f)); +} + +static void +haiku_define_frame_cursor (struct frame *f, Emacs_Cursor cursor) +{ + if (f->tooltip) + return; + block_input (); + if (!f->pointer_invisible && FRAME_HAIKU_VIEW (f)) + { + BView_set_view_cursor (FRAME_HAIKU_VIEW (f), cursor); + } + unblock_input (); + FRAME_OUTPUT_DATA (f)->current_cursor = cursor; +} + +static void +haiku_update_window_end (struct window *w, bool cursor_on_p, + bool mouse_face_overwritten_p) +{ + +} + +static struct redisplay_interface haiku_redisplay_interface = + { + haiku_frame_parm_handlers, + gui_produce_glyphs, + gui_write_glyphs, + gui_insert_glyphs, + gui_clear_end_of_line, + haiku_scroll_run, + haiku_after_update_window_line, + NULL, + haiku_update_window_end, + haiku_flush, + gui_clear_window_mouse_face, + gui_get_glyph_overhangs, + gui_fix_overlapping_area, + haiku_draw_fringe_bitmap, + haiku_define_fringe_bitmap, + haiku_destroy_fringe_bitmap, + haiku_compute_glyph_string_overhangs, + haiku_draw_glyph_string, + haiku_define_frame_cursor, + haiku_clear_frame_area, + haiku_clear_under_internal_border, + haiku_draw_window_cursor, + haiku_draw_vertical_window_border, + haiku_draw_window_divider, + 0, /* shift glyphs for insert */ + haiku_show_hourglass, + haiku_hide_hourglass, + 0 /* default font parameter */ + }; + +static int +haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) +{ + block_input (); + int message_count = 0; + void *buf; + ssize_t b_size; + + buf = alloca (200); + haiku_read_size (&b_size); + while (b_size >= 0) + { + enum haiku_event_type type; + struct input_event inev, inev2; + + if (b_size > 200) + emacs_abort (); + + EVENT_INIT (inev); + EVENT_INIT (inev2); + inev.kind = NO_EVENT; + inev2.kind = NO_EVENT; + inev.arg = Qnil; + inev2.arg = Qnil; + + haiku_read (&type, buf, b_size); + + switch (type) + { + case QUIT_REQUESTED: + { + struct haiku_quit_requested_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f) + continue; + + inev.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.frame_or_window, f); + break; + } + case FRAME_RESIZED: + { + struct haiku_resize_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f) + continue; + + int width = (int) b->px_widthf; + int height = (int) b->px_heightf; + + BView_resize_to (FRAME_HAIKU_VIEW (f), width, height); + if (width != FRAME_PIXEL_WIDTH (f) + || height != FRAME_PIXEL_HEIGHT (f) + || (f->new_size_p + && ((f->new_width >= 0 && width != f->new_width) + || (f->new_height >= 0 && height != f->new_height)))) + { + change_frame_size (f, width, height, false, true, false); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + haiku_clear_under_internal_border (f); + } + break; + } + case FRAME_EXPOSED: + { + struct haiku_expose_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f) + continue; + + expose_frame (f, b->x, b->y, b->width, b->height); + + haiku_clear_under_internal_border (f); + break; + } + case KEY_DOWN: + { + struct haiku_key_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + int non_ascii_p; + if (!f) + continue; + + BMapKey (b->kc, &non_ascii_p, &inev.code); + + if (!non_ascii_p) + inev.code = b->unraw_mb_char; + + if (non_ascii_p) + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + else + inev.kind = inev.code > 127 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : + ASCII_KEYSTROKE_EVENT; + + if (b->modifiers & HAIKU_MODIFIER_SHIFT) + inev.modifiers |= shift_modifier; + if (b->modifiers & HAIKU_MODIFIER_CTRL) + inev.modifiers |= ctrl_modifier; + if (b->modifiers & HAIKU_MODIFIER_ALT) + inev.modifiers |= meta_modifier; + + XSETFRAME (inev.frame_or_window, f); + break; + } + case ACTIVATION: + { + struct haiku_activation_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f) + continue; + + if ((x_display_list->focus_event_frame != f && b->activated_p) || + (x_display_list->focus_event_frame == f && !b->activated_p)) + { + haiku_new_focus_frame (b->activated_p ? f : NULL); + if (b->activated_p) + x_display_list->focus_event_frame = f; + else + x_display_list->focus_event_frame = NULL; + inev.kind = b->activated_p ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT; + XSETFRAME (inev.frame_or_window, f); + } + + break; + } + case MOUSE_MOTION: + { + struct haiku_mouse_motion_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f) + continue; + + Lisp_Object frame; + XSETFRAME (frame, f); + + if (b->just_exited_p) + { + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); + if (f == hlinfo->mouse_face_mouse_frame) + { + /* If we move outside the frame, then we're + certainly no longer on any text in the frame. */ + clear_mouse_face (hlinfo); + hlinfo->mouse_face_mouse_frame = 0; + } + + haiku_new_focus_frame (x_display_list->focused_frame); + help_echo_string = Qnil; + gen_help_event (Qnil, frame, Qnil, Qnil, 0); + } + else + { + struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + struct haiku_rect r = dpyinfo->last_mouse_glyph; + + dpyinfo->last_mouse_motion_x = b->x; + dpyinfo->last_mouse_motion_y = b->y; + dpyinfo->last_mouse_motion_frame = f; + + previous_help_echo_string = help_echo_string; + help_echo_string = Qnil; + + if (f != dpyinfo->last_mouse_glyph_frame || + b->x < r.x || b->x >= r.x + r.width || b->y < r.y || + b->y >= r.y + r.height) + { + f->mouse_moved = true; + dpyinfo->last_mouse_scroll_bar = NULL; + note_mouse_highlight (f, b->x, b->y); + remember_mouse_glyph (f, b->x, b->y, + &FRAME_DISPLAY_INFO (f)->last_mouse_glyph); + dpyinfo->last_mouse_glyph_frame = f; + gen_help_event (help_echo_string, frame, help_echo_window, + help_echo_object, help_echo_pos); + } + + if (MOUSE_HL_INFO (f)->mouse_face_hidden) + { + MOUSE_HL_INFO (f)->mouse_face_hidden = 0; + clear_mouse_face (MOUSE_HL_INFO (f)); + } + + if (!NILP (Vmouse_autoselect_window)) + { + static Lisp_Object last_mouse_window; + Lisp_Object window = window_from_coordinates (f, b->x, b->y, 0, 0, 0); + + if (WINDOWP (window) + && !EQ (window, last_mouse_window) + && !EQ (window, selected_window) + && (!NILP (focus_follows_mouse) + || (EQ (XWINDOW (window)->frame, + XWINDOW (selected_window)->frame)))) + { + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; + } + + last_mouse_window = window; + } + } + break; + } + case BUTTON_UP: + case BUTTON_DOWN: + { + struct haiku_button_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + int tab_bar_p = 0, tool_bar_p = 0; + + if (!f) + continue; + + struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + + if (b->modifiers & HAIKU_MODIFIER_SHIFT) + inev.modifiers |= shift_modifier; + if (b->modifiers & HAIKU_MODIFIER_CTRL) + inev.modifiers |= ctrl_modifier; + if (b->modifiers & HAIKU_MODIFIER_ALT) + inev.modifiers |= meta_modifier; + + /* Is this in the tab-bar? */ + if (WINDOWP (f->tab_bar_window) + && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window))) + { + Lisp_Object window; + int x = b->x; + int y = b->y; + + window = window_from_coordinates (f, x, y, 0, true, true); + tab_bar_p = EQ (window, f->tab_bar_window); + + if (tab_bar_p) + handle_tab_bar_click + (f, x, y, type == BUTTON_DOWN, inev.modifiers); + } + + if (WINDOWP (f->tool_bar_window) + && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) + { + Lisp_Object window; + int x = b->x; + int y = b->y; + + window = window_from_coordinates (f, x, y, 0, true, true); + tool_bar_p = EQ (window, f->tool_bar_window); + + if (tool_bar_p) + handle_tool_bar_click + (f, x, y, type == BUTTON_DOWN, inev.modifiers); + } + + if (type == BUTTON_UP) + { + inev.modifiers |= up_modifier; + dpyinfo->grabbed &= ~(1 << b->btn_no); + } + else + { + inev.modifiers |= down_modifier; + dpyinfo->last_mouse_frame = f; + dpyinfo->grabbed |= (1 << b->btn_no); + if (f && !tab_bar_p) + f->last_tab_bar_item = -1; + if (f && !tool_bar_p) + f->last_tool_bar_item = -1; + } + + if (!tab_bar_p && !tool_bar_p) + inev.kind = MOUSE_CLICK_EVENT; + inev.code = b->btn_no; + + inev.modifiers |= type == BUTTON_UP ? + up_modifier : down_modifier; + + XSETINT (inev.x, b->x); + XSETINT (inev.y, b->y); + + XSETFRAME (inev.frame_or_window, f); + break; + } + case ICONIFICATION: + { + struct haiku_iconification_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f) + continue; + + if (!b->iconified_p) + { + SET_FRAME_VISIBLE (f, 1); + SET_FRAME_ICONIFIED (f, 0); + inev.kind = DEICONIFY_EVENT; + + /* Haiku doesn't expose frames on deiconification. */ + SET_FRAME_GARBAGED (f); + expose_frame (f, 0, 0, 0, 0); + } + else + { + SET_FRAME_VISIBLE (f, 1); + SET_FRAME_ICONIFIED (f, 0); + inev.kind = ICONIFY_EVENT; + } + + XSETFRAME (inev.frame_or_window, f); + break; + } + case MOVE_EVENT: + { + struct haiku_move_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f) + continue; + + if (FRAME_PARENT_FRAME (f)) + haiku_coords_from_parent (f, &b->x, &b->y); + + if (b->x != f->left_pos || b->y != f->top_pos) + { + inev.kind = MOVE_FRAME_EVENT; + + XSETINT (inev.x, b->x); + XSETINT (inev.y, b->y); + + f->left_pos = b->x; + f->top_pos = b->y; + + if (FRAME_PARENT_FRAME (f)) + { + void *window = FRAME_HAIKU_WINDOW (FRAME_PARENT_FRAME (f)); + EmacsWindow_move_weak_child (window, b->window, b->x, b->y); + } + + XSETFRAME (inev.frame_or_window, f); + } + break; + } + case SCROLL_BAR_VALUE_EVENT: + { + struct haiku_scroll_bar_value_event *b = buf; + struct scroll_bar *bar = b->scroll_bar; + + struct window *w = XWINDOW (bar->window); + + if (bar->update != -1) + { + bar->update = -1; + break; + } + + if (bar->position != b->position) + { + inev.kind = bar->horizontal ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT : + SCROLL_BAR_CLICK_EVENT; + inev.part = bar->horizontal ? + scroll_bar_horizontal_handle : scroll_bar_handle; + + XSETINT (inev.x, b->position); + XSETINT (inev.y, bar->total); + XSETWINDOW (inev.frame_or_window, w); + } + break; + } + case SCROLL_BAR_DRAG_EVENT: + { + struct haiku_scroll_bar_drag_event *b = buf; + struct scroll_bar *bar = b->scroll_bar; + + bar->dragging = b->dragging_p; + if (!b->dragging_p && bar->horizontal) + set_horizontal_scroll_bar (XWINDOW (bar->window)); + else if (!b->dragging_p) + set_vertical_scroll_bar (XWINDOW (bar->window)); + break; + } + case WHEEL_MOVE_EVENT: + { + struct haiku_wheel_move_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + int x, y; + + if (!f) + continue; + BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y); + + if (b->modifiers & HAIKU_MODIFIER_SHIFT) + inev.modifiers |= shift_modifier; + if (b->modifiers & HAIKU_MODIFIER_CTRL) + inev.modifiers |= ctrl_modifier; + if (b->modifiers & HAIKU_MODIFIER_ALT) + inev.modifiers |= meta_modifier; + inev2.modifiers = inev.modifiers; + + if (b->delta_y) + { + inev.kind = WHEEL_EVENT; + inev.code = 0; + + XSETINT (inev.x, x); + XSETINT (inev.y, y); + XSETFRAME (inev.frame_or_window, f); + + inev.modifiers |= signbit (b->delta_y) ? + up_modifier : down_modifier; + } + + if (b->delta_x) + { + inev2.kind = HORIZ_WHEEL_EVENT; + inev2.code = 0; + + XSETINT (inev2.x, x); + XSETINT (inev2.y, y); + XSETFRAME (inev2.frame_or_window, f); + + inev2.modifiers |= signbit (b->delta_x) ? + up_modifier : down_modifier; + } + + break; + } + + case MENU_BAR_RESIZE: + { + struct haiku_menu_bar_resize_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f || !FRAME_EXTERNAL_MENU_BAR (f)) + continue; + + int old_height = FRAME_MENU_BAR_HEIGHT (f); + + FRAME_MENU_BAR_HEIGHT (f) = b->height + 1; + FRAME_MENU_BAR_LINES (f) = + (b->height + FRAME_LINE_HEIGHT (f)) / FRAME_LINE_HEIGHT (f); + + if (old_height != b->height) + { + adjust_frame_size (f, -1, -1, 3, true, Qmenu_bar_lines); + haiku_clear_under_internal_border (f); + } + break; + } + case MENU_BAR_OPEN: + case MENU_BAR_CLOSE: + { + struct haiku_menu_bar_state_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f || !FRAME_EXTERNAL_MENU_BAR (f)) + continue; + + if (type == MENU_BAR_OPEN) + { + if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p) + { + BView_draw_lock (FRAME_HAIKU_VIEW (f)); + /* This shouldn't be here, but nsmenu does it, so + it should probably be safe. */ + int was_waiting_for_input_p = waiting_for_input; + if (waiting_for_input) + waiting_for_input = 0; + set_frame_menubar (f, 1); + waiting_for_input = was_waiting_for_input_p; + BView_draw_unlock (FRAME_HAIKU_VIEW (f)); + } + popup_activated_p += 1; + } + else + { + if (!popup_activated_p) + emacs_abort (); + popup_activated_p -= 1; + } + break; + } + case MENU_BAR_SELECT_EVENT: + { + struct haiku_menu_bar_select_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f || !FRAME_EXTERNAL_MENU_BAR (f)) + continue; + + if (FRAME_OUTPUT_DATA (f)->menu_up_to_date_p) + find_and_call_menu_selection (f, f->menu_bar_items_used, + f->menu_bar_vector, b->ptr); + break; + } + case KEY_UP: + default: + break; + } + + haiku_read_size (&b_size); + + if (inev.kind != NO_EVENT) + { + kbd_buffer_store_event_hold (&inev, hold_quit); + ++message_count; + } + + if (inev2.kind != NO_EVENT) + { + kbd_buffer_store_event_hold (&inev2, hold_quit); + ++message_count; + } + } + + unblock_input (); + return message_count; +} + +static void +haiku_frame_rehighlight (struct frame *frame) +{ + haiku_rehighlight (); +} + +static void +haiku_delete_window (struct frame *f) +{ + check_window_system (f); + haiku_free_frame_resources (f); +} + +static void +haiku_free_pixmap (struct frame *f, Emacs_Pixmap pixmap) +{ + BBitmap_free (pixmap); +} + +static void +haiku_beep (struct frame *f) +{ + if (visible_bell) + { + void *view = FRAME_HAIKU_VIEW (f); + if (view) + { + block_input (); + BView_draw_lock (view); + BView_SetHighColor (view, FRAME_FOREGROUND_PIXEL (f)); + BView_FillRectangle (view, 0, 0, FRAME_PIXEL_WIDTH (f), + FRAME_PIXEL_HEIGHT (f)); + BView_EndTransaction (view); + flush_frame (f); + BView_draw_lock (f); + BView_draw_unlock (view); + + SET_FRAME_GARBAGED (f); + expose_frame (f, 0, 0, 0, 0); + unblock_input (); + } + } + else + haiku_ring_bell (); +} + +static void +haiku_toggle_invisible_pointer (struct frame *f, bool invisible_p) +{ + void *view = FRAME_HAIKU_VIEW (f); + + if (view) + { + block_input (); + BView_set_view_cursor (view, invisible_p ? + FRAME_OUTPUT_DATA (f)->no_cursor : + FRAME_OUTPUT_DATA (f)->current_cursor); + f->pointer_invisible = invisible_p; + unblock_input (); + } +} + +static struct terminal * +haiku_create_terminal (struct haiku_display_info *dpyinfo) +{ + struct terminal *terminal; + + terminal = create_terminal (output_haiku, &haiku_redisplay_interface); + + terminal->display_info.haiku = dpyinfo; + dpyinfo->terminal = terminal; + terminal->kboard = allocate_kboard (Qhaiku); + + terminal->iconify_frame_hook = haiku_iconify_frame; + terminal->ring_bell_hook = haiku_beep; + terminal->popup_dialog_hook = haiku_popup_dialog; + terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible; + terminal->set_frame_offset_hook = haiku_set_offset; + terminal->delete_terminal_hook = haiku_delete_terminal; + terminal->get_string_resource_hook = get_string_resource; + terminal->set_new_font_hook = haiku_new_font; + terminal->defined_color_hook = haiku_defined_color; + terminal->set_window_size_hook = haiku_set_window_size; + terminal->read_socket_hook = haiku_read_socket; + terminal->implicit_set_name_hook = haiku_implicitly_set_name; + terminal->mouse_position_hook = haiku_mouse_position; + terminal->delete_frame_hook = haiku_delete_window; + terminal->frame_up_to_date_hook = haiku_frame_up_to_date; + terminal->buffer_flipping_unblocked_hook = haiku_buffer_flipping_unblocked_hook; + terminal->clear_frame_hook = haiku_clear_frame; + terminal->change_tab_bar_height_hook = haiku_change_tab_bar_height; + terminal->change_tool_bar_height_hook = haiku_change_tool_bar_height; + terminal->set_vertical_scroll_bar_hook = haiku_set_vertical_scroll_bar; + terminal->set_horizontal_scroll_bar_hook = haiku_set_horizontal_scroll_bar; + terminal->set_scroll_bar_default_height_hook = haiku_set_scroll_bar_default_height; + terminal->set_scroll_bar_default_width_hook = haiku_set_scroll_bar_default_width; + terminal->judge_scroll_bars_hook = haiku_judge_scroll_bars; + terminal->condemn_scroll_bars_hook = haiku_condemn_scroll_bars; + terminal->redeem_scroll_bar_hook = haiku_redeem_scroll_bar; + terminal->update_begin_hook = haiku_update_begin; + terminal->update_end_hook = haiku_update_end; + terminal->frame_rehighlight_hook = haiku_frame_rehighlight; + terminal->query_frame_background_color = haiku_query_frame_background_color; + terminal->free_pixmap = haiku_free_pixmap; + terminal->frame_raise_lower_hook = haiku_frame_raise_lower; + terminal->menu_show_hook = haiku_menu_show; + terminal->toggle_invisible_pointer_hook = haiku_toggle_invisible_pointer; + + return terminal; +} + +struct haiku_display_info * +haiku_term_init (void) +{ + struct haiku_display_info *dpyinfo; + struct terminal *terminal; + + Lisp_Object color_file, color_map; + + block_input (); + Fset_input_interrupt_mode (Qnil); + + baud_rate = 19200; + + dpyinfo = xzalloc (sizeof *dpyinfo); + bzero (dpyinfo, sizeof *dpyinfo); + + haiku_io_init (); + + if (port_emacs_to_application < B_OK || + port_application_to_emacs < B_OK) + emacs_abort (); + + color_file = Fexpand_file_name (build_string ("rgb.txt"), + Fsymbol_value (intern ("data-directory"))); + + color_map = Fx_load_color_file (color_file); + if (NILP (color_map)) + fatal ("Could not read %s.\n", SDATA (color_file)); + + dpyinfo->color_map = color_map; + + dpyinfo->display = BApplication_setup (); + + BScreen_res (&dpyinfo->resx, &dpyinfo->resy); + + dpyinfo->next = x_display_list; + dpyinfo->n_planes = be_get_display_planes (); + x_display_list = dpyinfo; + + terminal = haiku_create_terminal (dpyinfo); + if (current_kboard == initial_kboard) + current_kboard = terminal->kboard; + + terminal->kboard->reference_count++; + /* Never delete haiku displays -- there can only ever be one, + anyhow */ + terminal->reference_count++; + terminal->name = xstrdup ("be"); + + dpyinfo->name_list_element = Fcons (build_string ("be"), Qnil); + dpyinfo->smallest_font_height = 1; + dpyinfo->smallest_char_width = 1; + + gui_init_fringe (terminal->rif); + unblock_input (); + + return dpyinfo; +} + +void +haiku_clear_under_internal_border (struct frame *f) +{ + if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) + { + int border = FRAME_INTERNAL_BORDER_WIDTH (f); + int width = FRAME_PIXEL_WIDTH (f); + int height = FRAME_PIXEL_HEIGHT (f); + int margin = FRAME_TOP_MARGIN_HEIGHT (f); + int face_id = + (FRAME_PARENT_FRAME (f) + ? (!NILP (Vface_remapping_alist) + ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID) + : CHILD_FRAME_BORDER_FACE_ID) + : (!NILP (Vface_remapping_alist) + ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) + : INTERNAL_BORDER_FACE_ID)); + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + void *view = FRAME_HAIKU_VIEW (f); + block_input (); + BView_draw_lock (view); + BView_StartClip (view); + + if (face) + BView_SetHighColor (view, face->background); + else + BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f)); + + BView_FillRectangle (view, 0, margin, width, border); + BView_FillRectangle (view, 0, 0, border, height); + BView_FillRectangle (view, 0, margin, width, border); + BView_FillRectangle (view, width - border, 0, border, height); + BView_FillRectangle (view, 0, height - border, width, border); + BView_EndClip (view); + BView_draw_unlock (view); + unblock_input (); + } +} + +void +mark_haiku_display (void) +{ + if (x_display_list) + mark_object (x_display_list->color_map); +} + +void +haiku_scroll_bar_remove (struct scroll_bar *bar) +{ + block_input (); + void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (XWINDOW (bar->window))); + BView_forget_scroll_bar (view, bar->left, bar->top, bar->width, bar->height); + BScrollBar_delete (bar->scroll_bar); + expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)), + bar->left, bar->top, bar->width, bar->height); + + if (bar->horizontal) + wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil); + else + wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil); + + unblock_input (); +}; + +void +syms_of_haikuterm (void) +{ + DEFVAR_BOOL ("haiku-initialized", ext_initialized, doc: /* Non-nil if the Haiku + terminal backend has been initialized. */); + + DEFVAR_BOOL ("x-use-underline-position-properties", + x_use_underline_position_properties, + doc: /* SKIP: real doc in xterm.c. */); + x_use_underline_position_properties = 0; + + DEFVAR_BOOL ("x-underline-at-descent-line", + x_underline_at_descent_line, + doc: /* SKIP: real doc in xterm.c. */); + x_underline_at_descent_line = 0; + + DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, + doc: /* SKIP: real doc in xterm.c. */); + Vx_toolkit_scroll_bars = Qt; + + DEFSYM (Qx_use_underline_position_properties, + "x-use-underline-position-properties"); + + DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); + + Fprovide (Qhaiku, Qnil); +} diff --git a/src/haikuterm.h b/src/haikuterm.h new file mode 100644 index 0000000000..f6c657cf4e --- /dev/null +++ b/src/haikuterm.h @@ -0,0 +1,266 @@ +/* Haiku window system support + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 3 of the License, or (at +your option) any later version. + +GNU Emacs 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 GNU Emacs. If not, see . */ + +#ifndef _HAIKU_TERM_H_ +#define _HAIKU_TERM_H_ + +#include + +#include "haikugui.h" +#include "frame.h" +#include "character.h" +#include "dispextern.h" +#include "font.h" + +#define C_FRAME struct frame * +#define C_FONT struct font * +#define C_TERMINAL struct terminal * + +#define HAVE_CHAR_CACHE_MAX 65535 + +extern int popup_activated_p ; +extern pthread_t app_thread_id; + +struct haikufont_info +{ + struct font font; + haiku be_font; + ptrdiff_t charc_size; + int *have_char_cache; + struct font_metrics *met_cache; +}; + +struct haiku_bitmap_record +{ + haiku img; + char *file; + int refcount; + int height, width, depth; +}; + +struct haiku_display_info +{ + /* Chain of all haiku_display_info structures. */ + struct haiku_display_info *next; + C_TERMINAL terminal; + + Lisp_Object name_list_element; + Lisp_Object color_map; + + int n_fonts; + + int smallest_char_width; + int smallest_font_height; + + struct frame *focused_frame; + struct frame *focus_event_frame; + struct frame *last_mouse_glyph_frame; + + struct haiku_bitmap_record *bitmaps; + ptrdiff_t bitmaps_size; + ptrdiff_t bitmaps_last; + + int grabbed; + int n_planes; + int color_p; + + Window root_window; + Lisp_Object rdb; + + Emacs_Cursor vertical_scroll_bar_cursor; + Emacs_Cursor horizontal_scroll_bar_cursor; + + Mouse_HLInfo mouse_highlight; + + C_FRAME highlight_frame; + C_FRAME last_mouse_frame; + C_FRAME last_mouse_motion_frame; + + int last_mouse_motion_x; + int last_mouse_motion_y; + + struct haiku_rect last_mouse_glyph; + + void *last_mouse_scroll_bar; + + haiku display; + + double resx, resy; +}; + +struct haiku_output +{ + Emacs_Cursor text_cursor; + Emacs_Cursor nontext_cursor; + Emacs_Cursor modeline_cursor; + Emacs_Cursor hand_cursor; + Emacs_Cursor hourglass_cursor; + Emacs_Cursor horizontal_drag_cursor; + Emacs_Cursor vertical_drag_cursor; + Emacs_Cursor left_edge_cursor; + Emacs_Cursor top_left_corner_cursor; + Emacs_Cursor top_edge_cursor; + Emacs_Cursor top_right_corner_cursor; + Emacs_Cursor right_edge_cursor; + Emacs_Cursor bottom_right_corner_cursor; + Emacs_Cursor bottom_edge_cursor; + Emacs_Cursor bottom_left_corner_cursor; + Emacs_Cursor no_cursor; + + Emacs_Cursor current_cursor; + + struct haiku_display_info *display_info; + + int baseline_offset; + int fontset; + + Emacs_Color cursor_color; + + Window window_desc, parent_desc; + char explicit_parent; + + int titlebar_height; + int toolbar_height; + + haiku window; + haiku view; + haiku menubar; + + int menu_up_to_date_p; + + C_FONT font; + + int hourglass_p; + uint32_t cursor_fg; + bool dirty_p; + + /* The pending position we're waiting for. */ + int pending_top, pending_left; +}; + +struct x_output +{ + /* Unused, makes term.c happy. */ +}; + +extern struct haiku_display_info *x_display_list; +extern struct font_driver const haikufont_driver; + +#ifdef HAVE_FREETYPE +extern struct font_driver const ftbefont_driver; +#ifdef HAVE_HARFBUZZ +extern struct font_driver ftbehbfont_driver; +#endif +#endif + +struct scroll_bar +{ + /* These fields are shared by all vectors. */ + union vectorlike_header header; + + /* The window we're a scroll bar for. */ + Lisp_Object window; + + /* The next and previous in the chain of scroll bars in this frame. */ + Lisp_Object next, prev; + + /* Fields after 'prev' are not traced by the GC. */ + + /* The position and size of the scroll bar in pixels, relative to the + frame. */ + int top, left, width, height; + + /* The actual scrollbar. */ + void *scroll_bar; + + /* Non-nil if the scroll bar handle is currently being dragged by + the user. */ + int dragging; + + /* The update position if we are waiting for a scrollbar update, or + -1. */ + int update; + + /* The last known position of this scrollbar. */ + int position; + + /* The total number of units inside this scrollbar. */ + int total; + + /* True if the scroll bar is horizontal. */ + bool horizontal; +}; + +#define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec)) + +#define FRAME_DIRTY_P(f) (FRAME_OUTPUT_DATA (f)->dirty_p) +#define MAKE_FRAME_DIRTY(f) (FRAME_DIRTY_P (f) = 1) +#define FRAME_OUTPUT_DATA(f) ((f)->output_data.haiku) +#define FRAME_HAIKU_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window) +#define FRAME_HAIKU_VIEW(f) ((MAKE_FRAME_DIRTY (f)), FRAME_OUTPUT_DATA (f)->view) +#define FRAME_HAIKU_MENU_BAR(f) (FRAME_OUTPUT_DATA (f)->menubar) +#define FRAME_DISPLAY_INFO(f) (FRAME_OUTPUT_DATA (f)->display_info) +#define FRAME_FONT(f) (FRAME_OUTPUT_DATA (f)->font) +#define FRAME_FONTSET(f) (FRAME_OUTPUT_DATA (f)->fontset) +#define FRAME_NATIVE_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window) +#define FRAME_BASELINE_OFFSET(f) (FRAME_OUTPUT_DATA (f)->baseline_offset) +#define FRAME_CURSOR_COLOR(f) (FRAME_OUTPUT_DATA (f)->cursor_color) + +extern void syms_of_haikuterm (void); +extern void syms_of_haikufns (void); +extern void syms_of_haikumenu (void); +extern void syms_of_haikufont (void); +extern void syms_of_haikuselect (void); +extern void init_haiku_select (void); + +extern void haiku_iconify_frame (struct frame *); +extern void haiku_visualize_frame (struct frame *); +extern void haiku_unvisualize_frame (struct frame *); +extern void haiku_set_offset (struct frame *, int, int, int); +extern void haiku_set_frame_visible_invisible (struct frame *, bool); +extern void haiku_free_frame_resources (struct frame *f); +extern void haiku_scroll_bar_remove (struct scroll_bar *bar); +extern void haiku_clear_under_internal_border (struct frame *f); +extern void haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p); + +extern struct haiku_display_info *haiku_term_init (void); + +extern void mark_haiku_display (void); + +extern int haiku_get_color (const char *name, Emacs_Color *color); +extern void haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval); +extern void haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval); +extern void haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval); +extern void haiku_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval); +extern void haiku_change_tab_bar_height (struct frame *f, int height); +extern void haiku_change_tool_bar_height (struct frame *f, int height); + +extern void haiku_query_color (uint32_t col, Emacs_Color *color); + +extern unsigned long haiku_get_pixel (haiku bitmap, int x, int y); +extern void haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel); + +extern Lisp_Object haiku_menu_show (struct frame *f, int x, int y, int menu_flags, + Lisp_Object title, const char **error_name); +extern Lisp_Object haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents); +extern void initialize_frame_menubar (struct frame *f); + +#ifdef HAVE_FREETYPE +extern void syms_of_ftbefont (void); +#endif +#endif /* _HAIKU_TERM_H_ */ diff --git a/src/image.c b/src/image.c index 206c7baa2f..c52c6e898b 100644 --- a/src/image.c +++ b/src/image.c @@ -20,6 +20,7 @@ Copyright (C) 1989, 1992-2021 Free Software Foundation, Inc. #include #include +#include #include /* Include this before including to work around bugs with @@ -135,6 +136,27 @@ #define PIX_MASK_DRAW 1 # define COLOR_TABLE_SUPPORT 1 #endif +#ifdef HAVE_HAIKU +#include "haiku_support.h" +typedef struct haiku_bitmap_record Bitmap_Record; + +#define GET_PIXEL(ximg, x, y) haiku_get_pixel (ximg, x, y) +#define PUT_PIXEL haiku_put_pixel +#define NO_PIXMAP 0 + +#define PIX_MASK_RETAIN 0 +#define PIX_MASK_DRAW 1 + +#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) +#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) +#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) +#define BLUE_FROM_ULONG(color) ((color) & 0xff) +#define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101) +#define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101) +#define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101) + +#endif + static void image_disable_image (struct frame *, struct image *); static void image_edge_detection (struct frame *, struct image *, Lisp_Object, Lisp_Object); @@ -465,7 +487,7 @@ image_create_bitmap_from_data (struct frame *f, char *bits, ptrdiff_t image_create_bitmap_from_file (struct frame *f, Lisp_Object file) { -#ifdef HAVE_NTGUI +#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU) return -1; /* W32_TODO : bitmap support */ #else Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); @@ -561,6 +583,10 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm) ns_release_object (bm->img); #endif +#ifdef HAVE_HAIKU + BBitmap_free (bm->img); +#endif + if (bm->file) { xfree (bm->file); @@ -2173,6 +2199,7 @@ compute_image_size (size_t width, size_t height, single step, but the maths for each element is much more complex and performing the steps separately makes for more readable code. */ +#ifndef HAVE_HAIKU typedef double matrix3x3[3][3]; static void @@ -2187,6 +2214,7 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result) result[i][j] = sum; } } +#endif /* not HAVE_HAIKU */ static void compute_image_rotation (struct image *img, double *rotation) @@ -2244,6 +2272,7 @@ image_set_transform (struct frame *f, struct image *img) double rotation = 0.0; compute_image_rotation (img, &rotation); +#ifndef HAVE_HAIKU # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS /* We want scale up operations to use a nearest neighbor filter to show real pixels instead of munging them, but scale down @@ -2414,6 +2443,34 @@ image_set_transform (struct frame *f, struct image *img) img->xform.eDx = matrix[2][0]; img->xform.eDy = matrix[2][1]; # endif +#else + if (rotation != 0 && + rotation != 90 && + rotation != 180 && + rotation != 270 && + rotation != 360) + { + image_error ("No native support for rotation by %g degrees", + make_float (rotation)); + return; + } + + rotation = fmod (rotation, 360.0); + + if (rotation == 90 || rotation == 270) + { + int w = width; + width = height; + height = w; + } + + img->have_be_transforms_p = rotation != 0 || (img->width != width) || (img->height != height); + img->be_rotate = rotation; + img->be_scale_x = 1.0 / (img->width / (double) width); + img->be_scale_y = 1.0 / (img->height / (double) height); + img->width = width; + img->height = height; +#endif /* not HAVE_HAIKU */ } #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ @@ -2820,6 +2877,29 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d return 1; #endif /* HAVE_X_WINDOWS */ +#ifdef HAVE_HAIKU + if (depth == 0) + depth = 24; + + if (depth != 24) + { + image_error ("Invalid image bit depth specified"); + return 0; + } + + *pixmap = BBitmap_new (width, height, depth == 1); + + if (*pixmap == NO_PIXMAP) + { + *pimg = NULL; + image_error ("Unable to create pixmap", Qnil, Qnil); + return 0; + } + + *pimg = *pixmap; + return 1; +#endif + #ifdef HAVE_NTGUI BITMAPINFOHEADER *header; @@ -3087,7 +3167,7 @@ image_unget_x_image_or_dc (struct image *img, bool mask_p, static Emacs_Pix_Container image_get_x_image (struct frame *f, struct image *img, bool mask_p) { -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined (HAVE_HAIKU) return !mask_p ? img->pixmap : img->mask; #elif defined HAVE_X_WINDOWS XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img; @@ -4016,19 +4096,26 @@ xbm_load (struct frame *f, struct image *img) ***********************************************************************/ #ifdef HAVE_XPM -#ifdef HAVE_NTGUI +/* XpmBe needs this too, despite the name of the define implying + Windows. */ +#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU) /* Indicate to xpm.h that we don't have Xlib. */ #define FOR_MSW /* simx.h in xpm defines XColor and XImage differently than Emacs. */ /* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */ +#ifndef HAVE_HAIKU #define XColor xpm_XColor #define XImage xpm_XImage #define Display xpm_Display +#endif + #ifdef CYGWIN #include "noX/xpm.h" -#else /* not CYGWIN */ +#elif defined (HAVE_NTGUI) #include "X11/xpm.h" -#endif /* not CYGWIN */ +#else +#include "xpm_be.h" /* In this case we use xpm_be.h for libXpmBe */ +#endif /* not CYGWIN and not HAVE_NTGUI*/ #undef FOR_MSW #undef XColor #undef XImage @@ -4352,8 +4439,10 @@ x_create_bitmap_from_xpm_data (struct frame *f, const char **bits) memset (&attrs, 0, sizeof attrs); +#ifndef HAVE_HAIKU attrs.visual = FRAME_X_VISUAL (f); attrs.colormap = FRAME_X_COLORMAP (f); +#endif attrs.valuemask |= XpmVisual; attrs.valuemask |= XpmColormap; @@ -4365,8 +4454,13 @@ x_create_bitmap_from_xpm_data (struct frame *f, const char **bits) xpm_init_color_cache (f, &attrs); #endif +#ifndef HAVE_HAIKU rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), (char **) bits, &bitmap, &mask, &attrs); +#else + rc = XpmCreateImageFromData (NULL, (char **) bits, &bitmap, &mask, &attrs); +#endif + if (rc != XpmSuccess) { XpmFreeAttributes (&attrs); @@ -4412,13 +4506,19 @@ xpm_load (struct frame *f, struct image *img) xpm_XImage * xpm_image = NULL, * xpm_mask = NULL; #endif /* HAVE_NTGUI */ +#ifdef HAVE_HAIKU + XImage *xpm_image = NULL, *xpm_mask = NULL; +#endif /* HAVE_HAIKU */ + /* Configure the XPM lib. Use the visual of frame F. Allocate close colors. Return colors allocated. */ memset (&attrs, 0, sizeof attrs); #ifndef HAVE_NTGUI +#ifndef HAVE_HAIKU attrs.visual = FRAME_X_VISUAL (f); attrs.colormap = FRAME_X_COLORMAP (f); +#endif attrs.valuemask |= XpmVisual; attrs.valuemask |= XpmColormap; #endif /* HAVE_NTGUI */ @@ -4535,9 +4635,14 @@ xpm_load (struct frame *f, struct image *img) &xpm_image, &xpm_mask, &attrs); #else +#ifndef HAVE_HAIKU rc = XpmReadFileToImage (FRAME_X_DISPLAY (f), SSDATA (file), &img->ximg, &img->mask_img, &attrs); +#else + rc = XpmReadFileToImage (NULL, SSDATA (file), + &xpm_image, &xpm_mask, &attrs); +#endif /* HAVE_HAIKU */ #endif /* HAVE_NTGUI */ } else @@ -4559,9 +4664,14 @@ xpm_load (struct frame *f, struct image *img) &xpm_image, &xpm_mask, &attrs); #else +#ifndef HAVE_HAIKU rc = XpmCreateImageFromBuffer (FRAME_X_DISPLAY (f), SSDATA (buffer), &img->ximg, &img->mask_img, &attrs); +#else + rc = XpmCreateImageFromBuffer (NULL, SSDATA (buffer), + &xpm_image, &xpm_mask, &attrs); +#endif /* HAVE_HAIKU */ #endif /* HAVE_NTGUI */ } @@ -4610,7 +4720,7 @@ xpm_load (struct frame *f, struct image *img) #else /* not ALLOC_XPM_COLORS */ int i; -#ifdef HAVE_NTGUI +#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU) /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap, plus some duplicate attributes. */ if (xpm_image && xpm_image->bitmap) @@ -4620,8 +4730,10 @@ xpm_load (struct frame *f, struct image *img) the bitmap, which is what we want. */ XImageFree (xpm_image); } + if (xpm_mask && xpm_mask->bitmap) { +#ifndef HAVE_HAIKU /* The mask appears to be inverted compared with what we expect. TODO: invert our expectations. See other places where we have to invert bits because our idea of masks is backwards. */ @@ -4630,14 +4742,17 @@ xpm_load (struct frame *f, struct image *img) PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT); SelectObject (hdc, old_obj); - +#endif /* not HAVE_HAIKU */ img->mask = xpm_mask->bitmap; XImageFree (xpm_mask); +#ifndef HAVE_HAIKU DeleteDC (hdc); +#endif /* not HAVE_HAIKU */ } - +#ifndef HAVE_HAIKU DeleteDC (hdc); -#endif /* HAVE_NTGUI */ +#endif /* not HAVE_HAIKU */ +#endif /* HAVE_NTGUI or HAVE_HAIKU */ /* Remember allocated colors. */ img->colors = xnmalloc (attrs.nalloc_pixels, sizeof *img->colors); @@ -5446,7 +5561,7 @@ lookup_rgb_color (struct frame *f, int r, int g, int b) { #ifdef HAVE_NTGUI return PALETTERGB (r >> 8, g >> 8, b >> 8); -#elif defined USE_CAIRO || defined HAVE_NS +#elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); #else xsignal1 (Qfile_error, @@ -5519,7 +5634,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) p = colors; for (y = 0; y < img->height; ++y) { -#if !defined USE_CAIRO && !defined HAVE_NS +#if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU Emacs_Color *row = p; for (x = 0; x < img->width; ++x, ++p) p->pixel = GET_PIXEL (ximg, x, y); @@ -5841,6 +5956,7 @@ image_disable_image (struct frame *f, struct image *img) { #ifndef HAVE_NTGUI #ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ +#ifndef HAVE_HAIKU #ifndef USE_CAIRO #define CrossForeground(f) BLACK_PIX_DEFAULT (f) @@ -5858,6 +5974,7 @@ #define MaskForeground(f) PIX_MASK_DRAW if (img->mask) image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height, MaskForeground (f)); +#endif /* !HAVE_HAIKU */ #endif /* !HAVE_NS */ #else HDC hdc, bmpdc; @@ -7060,6 +7177,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c) g = *p++ << 8; b = *p++ << 8; PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b)); + /* An alpha channel, aka mask channel, associates variable transparency with an image. Where other image formats support binary transparency---fully transparent or fully @@ -9339,7 +9457,8 @@ imagemagick_load_image (struct frame *f, struct image *img, init_color_table (); -#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && ! defined (HAVE_NS) +#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && \ + ! defined (HAVE_NS) && ! defined (HAVE_HAIKU) if (imagemagick_render_type != 0) { /* Magicexportimage is normally faster than pixelpushing. This @@ -10628,7 +10747,8 @@ DEFUN ("image-transforms-p", Fimage_transforms_p, Simage_transforms_p, 0, 1, 0, if (FRAME_WINDOW_P (f)) { #ifdef HAVE_NATIVE_TRANSFORMS -# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) +# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \ + || defined (HAVE_HAIKU) return list2 (Qscale, Qrotate90); # elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) int event_basep, error_basep; diff --git a/src/keyboard.c b/src/keyboard.c index f6139b30e7..07131b651d 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3870,7 +3870,7 @@ kbd_buffer_get_event (KBOARD **kbp, /* One way or another, wait until input is available; then, if interrupt handlers have not read it, read it now. */ -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) gobble_input (); #endif if (kbd_fetch_ptr != kbd_store_ptr) @@ -7139,7 +7139,7 @@ tty_read_avail_input (struct terminal *terminal, static void handle_async_input (void) { -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) while (1) { int nread = gobble_input (); @@ -7202,7 +7202,7 @@ totally_unblock_input (void) unblock_input_to (0); } -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) void handle_input_available_signal (int sig) @@ -7218,7 +7218,7 @@ deliver_input_available_signal (int sig) { deliver_process_signal (sig, handle_input_available_signal); } -#endif /* USABLE_SIGIO */ +#endif /* defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) */ /* User signal events. */ @@ -7288,7 +7288,7 @@ handle_user_signal (int sig) } p->npending++; -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) if (interrupt_input) handle_input_available_signal (sig); else @@ -11053,7 +11053,7 @@ DEFUN ("set-input-interrupt-mode", Fset_input_interrupt_mode, (Lisp_Object interrupt) { bool new_interrupt_input; -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) #ifdef HAVE_X_WINDOWS if (x_display_list != NULL) { @@ -11064,9 +11064,9 @@ DEFUN ("set-input-interrupt-mode", Fset_input_interrupt_mode, else #endif /* HAVE_X_WINDOWS */ new_interrupt_input = !NILP (interrupt); -#else /* not USABLE_SIGIO */ +#else /* not USABLE_SIGIO || USABLE_SIGPOLL */ new_interrupt_input = false; -#endif /* not USABLE_SIGIO */ +#endif /* not USABLE_SIGIO || USABLE_SIGPOLL */ if (new_interrupt_input != interrupt_input) { @@ -11493,12 +11493,16 @@ init_keyboard (void) sigaction (SIGQUIT, &action, 0); #endif /* not DOS_NT */ } -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) if (!noninteractive) { struct sigaction action; emacs_sigaction_init (&action, deliver_input_available_signal); +#ifdef USABLE_SIGIO sigaction (SIGIO, &action, 0); +#else + sigaction (SIGPOLL, &action, 0); +#endif } #endif diff --git a/src/lisp.h b/src/lisp.h index 7bfc69b647..4b4d97e959 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3316,7 +3316,7 @@ rarely_quit (unsigned short int count) /* Define if the windowing system provides a menu bar. */ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \ - || defined (HAVE_NS) || defined (USE_GTK) + || defined (HAVE_NS) || defined (USE_GTK) || defined (HAVE_HAIKU) #define HAVE_EXT_MENU_BAR true #endif @@ -4411,7 +4411,7 @@ fast_string_match_ignore_case (Lisp_Object regexp, Lisp_Object string) extern Lisp_Object tab_bar_items (Lisp_Object, int *); extern Lisp_Object tool_bar_items (Lisp_Object, int *); extern void discard_mouse_events (void); -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) void handle_input_available_signal (int); #endif extern Lisp_Object pending_funcalls; diff --git a/src/menu.c b/src/menu.c index d43360ec4e..51d6a98a67 100644 --- a/src/menu.c +++ b/src/menu.c @@ -50,7 +50,8 @@ Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2021 Free Software static bool have_boxes (void) { -#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined(HAVE_NS) +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined (HAVE_NS) \ + || defined (HAVE_HAIKU) if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))) return 1; #endif @@ -169,7 +170,7 @@ ensure_menu_items (int items) } } -#ifdef HAVE_EXT_MENU_BAR +#if defined (HAVE_EXT_MENU_BAR) || defined (HAVE_HAIKU) /* Begin a submenu. */ @@ -422,7 +423,8 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk AREF (item_properties, ITEM_PROPERTY_SELECTED), AREF (item_properties, ITEM_PROPERTY_HELP)); -#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \ + || defined (HAVE_NTGUI) || defined (HAVE_HAIKU) /* Display a submenu using the toolkit. */ if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)) && ! (NILP (map) || NILP (enabled))) @@ -872,6 +874,9 @@ update_submenu_strings (widget_value *first_wv) } } +#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */ +#ifdef HAVE_HAIKU + /* Find the menu selection and store it in the keyboard buffer. F is the frame the menu is on. MENU_BAR_ITEMS_USED is the length of VECTOR. @@ -959,8 +964,7 @@ find_and_call_menu_selection (struct frame *f, int menu_bar_items_used, SAFE_FREE (); } -#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */ - +#endif /* HAVE_HAIKU */ #ifdef HAVE_NS /* As above, but return the menu selection instead of storing in kb buffer. If KEYMAPS, return full prefixes to selection. */ diff --git a/src/process.c b/src/process.c index bfca165fca..eb8bd2cbb9 100644 --- a/src/process.c +++ b/src/process.c @@ -258,7 +258,7 @@ #define READ_OUTPUT_DELAY_MAX_MAX (READ_OUTPUT_DELAY_INCREMENT * 7) static void start_process_unwind (Lisp_Object); static void create_process (Lisp_Object, char **, Lisp_Object); -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) static bool keyboard_bit_set (fd_set *); #endif static void deactivate_process (Lisp_Object); @@ -5567,22 +5567,24 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, timeout = make_timespec (0, 0); #endif - /* Non-macOS HAVE_GLIB builds call thread_select in xgselect.c. */ -#if defined HAVE_GLIB && !defined HAVE_NS + /* Non-macOS HAVE_GLIB builds call thread_select in xgselect.c. + On Haiku, xg_select leads to crashes when dynamic menu-bar + items signal. */ +#if defined HAVE_GLIB && !defined HAVE_NS && !defined HAVE_HAIKU nfds = xg_select (max_desc + 1, &Available, (check_write ? &Writeok : 0), NULL, &timeout, NULL); -#elif defined HAVE_NS +#elif defined HAVE_NS && !defined HAVE_HAIKU /* And NS builds call thread_select in ns_select. */ nfds = ns_select (max_desc + 1, &Available, (check_write ? &Writeok : 0), NULL, &timeout, NULL); -#else /* !HAVE_GLIB */ +#else /* !HAVE_GLIB || HAVE_HAIKU */ nfds = thread_select (pselect, max_desc + 1, &Available, (check_write ? &Writeok : 0), NULL, &timeout, NULL); -#endif /* !HAVE_GLIB */ +#endif /* !HAVE_GLIB || HAVE_HAIKU */ #ifdef HAVE_GNUTLS /* Merge tls_available into Available. */ @@ -5700,7 +5702,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell))) break; -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) /* If we think we have keyboard input waiting, but didn't get SIGIO, go read it. This can happen with X on BSD after logging out. In that case, there really is no input and no SIGIO, @@ -5708,7 +5710,11 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, if (read_kbd && interrupt_input && keyboard_bit_set (&Available) && ! noninteractive) +#ifdef USABLE_SIGIO handle_input_available_signal (SIGIO); +#else + handle_input_available_signal (SIGPOLL); +#endif #endif /* If checking input just got us a size-change event from X, @@ -7702,7 +7708,7 @@ delete_gpm_wait_descriptor (int desc) # endif -# ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) /* Return true if *MASK has a bit set that corresponds to one of the keyboard input descriptors. */ diff --git a/src/sound.c b/src/sound.c index 9041076bdc..d42bc8550d 100644 --- a/src/sound.c +++ b/src/sound.c @@ -299,11 +299,15 @@ sound_perror (const char *msg) int saved_errno = errno; turn_on_atimers (1); -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) { sigset_t unblocked; sigemptyset (&unblocked); +#ifdef USABLE_SIGIO sigaddset (&unblocked, SIGIO); +#else + sigaddset (&unblocked, SIGPOLL); +#endif pthread_sigmask (SIG_UNBLOCK, &unblocked, 0); } #endif @@ -698,7 +702,7 @@ vox_open (struct sound_device *sd) vox_configure (struct sound_device *sd) { int val; -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) sigset_t oldset, blocked; #endif @@ -708,9 +712,13 @@ vox_configure (struct sound_device *sd) interrupted by a signal. Block the ones we know to cause troubles. */ turn_on_atimers (0); -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) sigemptyset (&blocked); +#ifdef USABLE_SIGIO sigaddset (&blocked, SIGIO); +#else + sigaddset (&blocked, SIGPOLL); +#endif pthread_sigmask (SIG_BLOCK, &blocked, &oldset); #endif @@ -744,7 +752,7 @@ vox_configure (struct sound_device *sd) } turn_on_atimers (1); -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) pthread_sigmask (SIG_SETMASK, &oldset, 0); #endif } @@ -760,10 +768,14 @@ vox_close (struct sound_device *sd) /* On GNU/Linux, it seems that the device driver doesn't like to be interrupted by a signal. Block the ones we know to cause troubles. */ -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) sigset_t blocked, oldset; sigemptyset (&blocked); +#ifdef USABLE_SIGIO sigaddset (&blocked, SIGIO); +#else + sigaddset (&blocked, SIGPOLL); +#endif pthread_sigmask (SIG_BLOCK, &blocked, &oldset); #endif turn_on_atimers (0); @@ -772,7 +784,7 @@ vox_close (struct sound_device *sd) ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL); turn_on_atimers (1); -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) pthread_sigmask (SIG_SETMASK, &oldset, 0); #endif diff --git a/src/sysdep.c b/src/sysdep.c index 8eaee22498..ef6af7e0c5 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -678,6 +678,9 @@ sys_subshell (void) #ifdef USABLE_SIGIO saved_handlers[3].code = SIGIO; saved_handlers[4].code = 0; +#elif defined (USABLE_SIGPOLL) + saved_handlers[3].code = SIGPOLL; + saved_handlers[4].code = 0; #else saved_handlers[3].code = 0; #endif @@ -788,6 +791,7 @@ init_sigio (int fd) } #ifndef DOS_NT +#ifdef F_SETOWN static void reset_sigio (int fd) { @@ -795,12 +799,13 @@ reset_sigio (int fd) fcntl (fd, F_SETFL, old_fcntl_flags[fd]); #endif } +#endif /* F_SETOWN */ #endif void request_sigio (void) { -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) sigset_t unblocked; if (noninteractive) @@ -810,7 +815,11 @@ request_sigio (void) # ifdef SIGWINCH sigaddset (&unblocked, SIGWINCH); # endif +# ifdef USABLE_SIGIO sigaddset (&unblocked, SIGIO); +# else + sigaddset (&unblocked, SIGPOLL); +# endif pthread_sigmask (SIG_UNBLOCK, &unblocked, 0); interrupts_deferred = 0; @@ -820,7 +829,7 @@ request_sigio (void) void unrequest_sigio (void) { -#ifdef USABLE_SIGIO +#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) sigset_t blocked; if (noninteractive) @@ -830,7 +839,11 @@ unrequest_sigio (void) # ifdef SIGWINCH sigaddset (&blocked, SIGWINCH); # endif +# ifdef USABLE_SIGIO sigaddset (&blocked, SIGIO); +# else + sigaddset (&blocked, SIGPOLL); +# endif pthread_sigmask (SIG_BLOCK, &blocked, 0); interrupts_deferred = 1; #endif @@ -1256,9 +1269,12 @@ init_sys_modes (struct tty_display_info *tty_out) /* This code added to insure that, if flow-control is not to be used, we have an unlocked terminal at the start. */ +#ifndef HAIKU /* On Haiku, TCXONC is a no-op and causes spurious + compiler warnings. */ #ifdef TCXONC if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TCXONC, 1); #endif +#endif /* HAIKU */ #ifdef TIOCSTART if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TIOCSTART, 0); #endif @@ -1674,6 +1690,8 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler) sigaddset (&action->sa_mask, SIGQUIT); #ifdef USABLE_SIGIO sigaddset (&action->sa_mask, SIGIO); +#elif defined (USABLE_SIGPOLL) + sigaddset (&action->sa_mask, SIGPOLL); #endif } @@ -2772,6 +2790,7 @@ cfsetspeed (struct termios *termios_p, speed_t vitesse) #ifdef B150 { 150, B150 }, #endif +#ifndef HAVE_TINY_SPEED_T #ifdef B200 { 200, B200 }, #endif @@ -2859,6 +2878,7 @@ cfsetspeed (struct termios *termios_p, speed_t vitesse) #ifdef B4000000 { 4000000, B4000000 }, #endif +#endif /* HAVE_TINY_SPEED_T */ }; /* Convert a numerical speed (e.g., 9600) to a Bnnn constant (e.g., diff --git a/src/termhooks.h b/src/termhooks.h index 1d3cdc8fe8..3d6bfd89d6 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -60,7 +60,8 @@ #define EMACS_TERMHOOKS_H output_x_window, output_msdos_raw, output_w32, - output_ns + output_ns, + output_haiku }; /* Input queue declarations and hooks. */ @@ -442,6 +443,7 @@ #define EVENT_INIT(event) memset (&(event), 0, sizeof (struct input_event)) struct x_display_info *x; /* xterm.h */ struct w32_display_info *w32; /* w32term.h */ struct ns_display_info *ns; /* nsterm.h */ + struct haiku_display_info *haiku; /* haikuterm.h */ } display_info; @@ -830,6 +832,9 @@ #define TERMINAL_FONT_CACHE(t) \ #elif defined (HAVE_NS) #define TERMINAL_FONT_CACHE(t) \ (t->type == output_ns ? t->display_info.ns->name_list_element : Qnil) +#elif defined (HAVE_HAIKU) +#define TERMINAL_FONT_CACHE(t) \ + (t->type == output_haiku ? t->display_info.haiku->name_list_element : Qnil) #endif extern struct terminal *decode_live_terminal (Lisp_Object); diff --git a/src/terminal.c b/src/terminal.c index b83adc596b..b5f244ee31 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -445,6 +445,8 @@ DEFUN ("terminal-live-p", Fterminal_live_p, Sterminal_live_p, 1, 1, 0, return Qpc; case output_ns: return Qns; + case output_haiku: + return Qhaiku; default: emacs_abort (); } diff --git a/src/verbose.mk.in b/src/verbose.mk.in index 50d6ea3200..35f96209ff 100644 --- a/src/verbose.mk.in +++ b/src/verbose.mk.in @@ -23,6 +23,7 @@ ifeq (${V},1) AM_V_AR = AM_V_at = AM_V_CC = +AM_V_CXX = AM_V_CCLD = AM_V_ELC = AM_V_GEN = @@ -33,6 +34,7 @@ else AM_V_AR = @echo " AR " $@; AM_V_at = @ AM_V_CC = @echo " CC " $@; +AM_V_CXX = @echo " CXX " $@; AM_V_CCLD = @echo " CCLD " $@; ifeq ($(HAVE_NATIVE_COMP),yes) ifeq ($(NATIVE_DISABLED),1) diff --git a/src/xdisp.c b/src/xdisp.c index e853c8c223..437ae5c869 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -15629,6 +15629,11 @@ redisplay_internal (void) } #endif +#if defined (HAVE_HAIKU) + if (popup_activated_p) + return; +#endif + /* I don't think this happens but let's be paranoid. */ if (redisplaying_p) return; @@ -25213,6 +25218,11 @@ display_menu_bar (struct window *w) return; #endif /* HAVE_NS */ +#ifdef HAVE_HAIKU + if (FRAME_HAIKU_P (f)) + return; +#endif /* HAVE_HAIKU */ + #if defined (USE_X_TOOLKIT) || defined (USE_GTK) eassert (!FRAME_WINDOW_P (f)); init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID); @@ -33535,6 +33545,11 @@ note_mouse_highlight (struct frame *f, int x, int y) return; #endif +#if defined (HAVE_HAIKU) + if (popup_activated_p) + return; +#endif + if (!f->glyphs_initialized_p || f->pointer_invisible) return; diff --git a/src/xfaces.c b/src/xfaces.c index 2273fb4fe4..d788fdb11a 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -246,6 +246,10 @@ #define GCGraphicsExposures 0 #ifdef HAVE_NS #define GCGraphicsExposures 0 #endif /* HAVE_NS */ + +#ifdef HAVE_HAIKU +#define GCGraphicsExposures 0 +#endif /* HAVE_HAIKU */ #endif /* HAVE_WINDOW_SYSTEM */ #include "buffer.h" @@ -555,8 +559,8 @@ x_free_gc (struct frame *f, Emacs_GC *gc) #endif /* HAVE_NTGUI */ -#ifdef HAVE_NS -/* NS emulation of GCs */ +#if defined (HAVE_NS) || defined (HAVE_HAIKU) +/* NS and Haiku emulation of GCs */ static Emacs_GC * x_create_gc (struct frame *f, diff --git a/src/xfns.c b/src/xfns.c index 0d0335c299..31c95db3e4 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -4416,7 +4416,8 @@ DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, Protocol used on TERMINAL and the 3rd number is the distributor-specific release number. For MS Windows, the 3 numbers report the OS major and minor version and build number. For Nextstep, the first 2 numbers are -hard-coded and the 3rd represents the OS version. +hard-coded and the 3rd represents the OS version. For Haiku, all 3 +numbers are hard-coded. See also the function `x-server-vendor'. diff --git a/src/xterm.c b/src/xterm.c index 1887c3255d..a75ca56a65 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -13685,7 +13685,7 @@ syms_of_xterm (void) A value of nil means Emacs doesn't use toolkit scroll bars. With the X Window system, the value is a symbol describing the X toolkit. Possible values are: gtk, motif, xaw, or xaw3d. -With MS Windows or Nextstep, the value is t. */); +With MS Windows, Haiku windowing or Nextstep, the value is t. */); #ifdef USE_TOOLKIT_SCROLL_BARS #ifdef USE_MOTIF Vx_toolkit_scroll_bars = intern_c_string ("motif");