From: Po Lu via Emacs news and miscellaneous discussions outside the scope of other Emacs mailing lists <emacs-tangents@gnu.org>
To: emacs-tangents@gnu.org
Subject: Request for icon
Date: Sat, 04 Sep 2021 19:20:10 +0800 [thread overview]
Message-ID: <87zgssfuz9.fsf@yahoo.com> (raw)
In-Reply-To: 87zgssfuz9.fsf.ref@yahoo.com
[-- Attachment #1: Type: text/plain, Size: 738 bytes --]
If there's anyone on this list who knows his way around vector graphics
design, and icon design in general, I would greatly appreciate it if he
made an icon for Emacs in compliance with the Haiku icon guidelines at:
https://www.haiku-os.org/development/icon-guidelines
Preferably, the icon should be in the Haiku vector icon format (HVIF),
which can be created with the Icon-O-Magic program distributed with
Haiku, but I will have no problem with SVG icons, as long as they have
at most 256 paths.
Anyone who's up to the task must also be willing to sign the FSF
copyright assignment papers.
If someone is interested in the progress of the Haiku port, I've
attached a patch below; it should apply cleanly on latest master.
Thanks!
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Emacs for Haiku --]
[-- Type: text/x-patch, Size: 697329 bytes --]
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 <thomas@suse.de> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#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 <thomas@suse.de>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#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 <thomas@suse.de>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#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 <config.h>
+#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 <config.h>
+#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 <config.h>
+#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 <config.h>
+#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 <config.h>
+#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 <https://www.gnu.org/licenses/>.
+
+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 <thomas@suse.de> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "XpmI.h"
+#include <sys/stat.h>
+#if !defined(FOR_MSW) && !defined(WIN32)
+#include <unistd.h>
+#endif
+#ifndef VAX11C
+#include <fcntl.h>
+#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 <config.h>
+#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 <thomas@suse.de> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "XpmI.h"
+#ifndef NO_ZPIPE
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#else
+#ifdef FOR_MSW
+#include <fcntl.h>
+#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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+/* 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 <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Xmd.h>
+#endif
+
+#ifdef VMS
+#include <unixio.h>
+#include <file.h>
+#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 <stdint.h> /* For SIZE_MAX */
+#endif
+#include <limits.h>
+#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 <string.h>
+#endif
+
+#ifdef NEED_STRCASECMP
+FUNC(xpmstrcasecmp, int, (char *s1, char *s2));
+#else
+#undef xpmstrcasecmp
+#define xpmstrcasecmp strcasecmp
+#include <strings.h>
+#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 <thomas@suse.de>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <ctype.h>
+#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 <MaximumIterations> colormap reads and sorts may be
+ * needed, and as many as <MaximumIterations> * <ColormapSize>
+ * 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 <thomas@suse.de> */
+
+#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 <config.h>
+#endif
+#include "XpmI.h"
+#endif
+#include <ctype.h>
+
+#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 <config.h>
+#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 <config.h>
+#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 <thomas@suse.de> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "XpmI.h"
+#include <ctype.h>
+#include <string.h>
+
+/**
+ * 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 <config.h>
+#endif
+#include "XpmI.h"
+#include <ctype.h>
+
+#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 <thomas@suse.de> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#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 <https://www.gnu.org/licenses/>. */
+
+/* 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 <stdint.h>
+
+#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 <malloc.h>
+# 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 <X11/Xlib.h>
+# include <X11/Xutil.h>
+# 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 <termios.h>])
+ 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 <fcntl.h>
+ #include <signal.h>
+ ]],
+ [[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.
+
\f
* 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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include <SupportDefs.h>
+#include <Path.h>
+#include <AppFileInfo.h>
+#include <TranslationUtils.h>
+#include <Application.h>
+#include <Catalog.h>
+
+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 <https://www.gnu.org/licenses/>.
+
+;;; 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 <time.h>
# 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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#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 <hb.h>
+#include <hb-ft.h>
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <View.h>
+#include <Region.h>
+#include <Font.h>
+#include <Window.h>
+#include <Bitmap.h>
+
+#include <cmath>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <Font.h>
+#include <Rect.h>
+#include <AffineTransform.h>
+
+#include <cstring>
+#include <cmath>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "haiku_support.h"
+
+#include <View.h>
+#include <Bitmap.h>
+#include <Point.h>
+#include <Region.h>
+
+#include <alloca.h>
+#include <cstddef>
+#include <cmath>
+#include <algorithm>
+
+#include <ft2build.h>
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <OS.h>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <Clipboard.h>
+
+#include <cstdlib>
+#include <cstring>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <Application.h>
+#include <AppFileInfo.h>
+#include <GraphicsDefs.h>
+#include <InterfaceDefs.h>
+#include <Bitmap.h>
+#include <Window.h>
+#include <DirectWindow.h>
+#include <View.h>
+#include <Screen.h>
+#include <Cursor.h>
+#include <UnicodeChar.h>
+#include <ScrollBar.h>
+#include <Region.h>
+#include <Menu.h>
+#include <MenuItem.h>
+#include <PopUpMenu.h>
+#include <MenuBar.h>
+#include <Beep.h>
+#include <Alert.h>
+#include <Button.h>
+#include <Path.h>
+#include <PathFinder.h>
+#include <WindowScreen.h>
+#include <Messenger.h>
+#include <fs_attr.h>
+
+#include <cmath>
+#include <cstring>
+#include <pthread.h>
+#include <stdint.h>
+
+#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<EmacsWindow *> (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<EmacsView *>(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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _HAIKU_SUPPORT_H
+#define _HAIKU_SUPPORT_H
+
+#include <stdint.h>
+
+#ifdef HAVE_FREETYPE
+#include <ft2build.h>
+#include <fontconfig/fontconfig.h>
+#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 <pthread.h>
+#include <OS.h>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <math.h>
+
+#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 ();
+}
+
+\f
+
+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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#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 <math.h>
+#include <stdlib.h>
+
+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 <https://www.gnu.org/licenses/>. */
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _HAIKU_SELECT_H_
+#define _HAIKU_SELECT_H_
+
+#ifdef __cplusplus
+#include <cstdio>
+#endif
+
+#ifdef __cplusplus
+#include <stdio.h>
+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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#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 <math.h>
+
+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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _HAIKU_TERM_H_
+#define _HAIKU_TERM_H_
+
+#include <pthread.h>
+
+#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 <config.h>
#include <fcntl.h>
+#include <math.h>
#include <unistd.h>
/* Include this before including <setjmp.h> 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) */
\f
/* 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;
\f
@@ -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");
parent reply other threads:[~2021-09-04 11:20 UTC|newest]
Thread overview: expand[flat|nested] mbox.gz Atom feed
[parent not found: <87zgssfuz9.fsf.ref@yahoo.com>]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87zgssfuz9.fsf@yahoo.com \
--to=emacs-tangents@gnu.org \
--cc=luangruo@yahoo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.