1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-07 04:10:27 -08:00
emacs/src/haiku.c
Po Lu 85a078e785 Add support for the Haiku operating system and its window system
* .gitignore: Add binaries specific to Haiku.

* Makefie.in (HAVE_BE_APP): New variable.
(install-arch-dep): Install Emacs and Emacs.pdmp when
using Haiku.

* configure.ac: Detect and configure for Haiku and
various related configurations.
(be-app, be-freetype, be-cairo): New options.
(HAVE_BE_APP, HAIKU_OBJ, HAIKU_CXX_OBJ)
(HAIKU_LIBS, HAIKU_CFLAGS): New variables.
(HAIKU, HAVE_TINY_SPEED_T): New define.
(emacs_config_features): Add BE_APP.

* doc/emacs/Makefile.in (EMACSSOURCES): Add Haiku
appendix.

* doc/emacs/emacs.texi: Add Haiku appendix to menus and
include it.

* doc/emacs/haiku.texi: New Haiku appendix.

* doc/lispref/display.texi (Defining Faces, Window Systems):
Explain meaning of `haiku' as a window system identifier.
(haiku-use-system-tooltips): Explain meaning of system
tooltips on
Haiku.

* doc/lispref/frames.texi (Multiple Terminals): Explain
meaning of haiku as a display type.
(Frame Layout): Clarify section for Haiku frames.
(Size Parameters): Explain limitations of fullwidth and
fullheight on Haiku.
(Management Parameters): Explain limitations of
inhibiting double buffering on builds with Cairo,
and the inability of frames with no-accept-focus to
receive keyboard input on Haiku.
(Font and Color Parameters): Explain the different font
backends available on Haiku.
(Raising and Lowering): Explain that lowering and
restacking frames doesn't work on Haiku.
(Child Frames): Explain oddities of child frame
visibility on Haiku.

* doc/lispref/os.texi (System Environment): Explain
meaning of haiku.
* etc/MACHINES: Add appropriate notices for Haiku.
* etc/NEWS: Document changes.
* etc/PROBLEMS: Document font spacing bug on Haiku.

* lib-src/Makefile.in: Build be-resources binary on
Haiku.
(CXX, CXXFLAGS, NON_CXX_FLAGS, ALL_CXXFLAGS)
(HAVE_BE_APP, HAIKU_LIBS, HAIKU_CFLAGS): New variables.
(DONT_INSTALL): Add be-resources binary if on Haiku.
(be-resources): New target.

* lib-src/be_resources: Add helper binary for setting
resources on the Emacs application.

* lib-src/emacsclient.c (decode_options): Set
alt_display to "be" on Haiku.

* lisp/cus-edit.el (custom-button, custom-button-mouse)
(custom-button-unraised, custom-button-pressed): Update
face definitions for Haiku.

* lisp/cus-start.el: Add haiku-debug-on-fatal-error and
haiku-use-system-tooltips.

* lisp/faces.el (face-valid-attribute-values): Clarify
attribute comment for Haiku.
(tool-bar): Add appropriate toolbar color for Haiku.

* lisp/frame.el (haiku-frame-geometry)
(haiku-mouse-absolute-pixel-position)
(haiku-set-mouse-absolute-pixel-position)
(haiku-frame-edges)
(haiku-frame-list-z-order): New function declarations.

(frame-geometry, frame-edges)
(mouse-absolute-pixel-position)
(set-mouse-absolute-pixel-position)
(frame-list-z-order): Call appropriate window system
functions on Haiku.

(display-mouse-p, display-graphic-p)
(display-images-p, display-pixel-height)
(display-pixel-width, display-mm-height)
(display-mm-width, display-backing-store)
(display-save-under, display-planes)
(display-color-cells, display-visual-class): Update type
tests for Haiku.

* lisp/international/mule-cmds.el
(set-coding-system-map): Also
prevent set-terminal-coding-system from appearing in the menu
bar on Haiku.

* lisp/loadup.el: Load Haiku-specific files when built
with Haiku, and don't rename newly built Emacs on Haiku as BFS
doesn't support hard links.

* lisp/menu-bar.el (menu-bar-open): Add for Haiku.

* lisp/mwheel.el (mouse-wheel-down-event): Expect
wheel-up on Haiku.
(mouse-wheel-up-event): Expect wheel-down on Haiku.
(mouse-wheel-left-event): Expect wheel-left on Haiku.
(mouse-wheel-right-event): Expect wheel-right on Haiku.

* lisp/net/browse-url.el
(browse-url--browser-defcustom-type):
Add option for WebPositive.
(browse-url-webpositive-program): New variable.
(browse-url-default-program): Search for WebPositive.
(browse-url-webpositive): New function.

* lisp/net/eww.el (eww-form-submit, eww-form-file)
(eww-form-checkbox, eww-form-select): Define faces
appropriately for Haiku.

* lisp/term/haiku-win.el: New file.

* lisp/tooltip.el (menu-or-popup-active-p): New function
declaration.
(tooltip-show-help): Don't use tooltips on Haiku when a
menu is active.

* lisp/version.el (haiku-get-version-string): New
function declaration.
(emacs-version): Add Haiku version string if
appropriate.

* src/Makefile.in: Also produce binary named "Emacs"
with Haiku resources set.

(CXX, HAIKU_OBJ, HAIKU_CXX_OBJ, HAIKU_LIBS)
(HAIKU_CFLAGS, HAVE_BE_APP, NON_CXX_FLAGS)
(ALL_CXX_FLAGS): New variables.

(.SUFFIXES): Add .cc.
(.cc.o): New target.
(base_obj): Add Haiku C objects.
(doc_obj, obj): Split objects that should scanned for
documentation into doc_obj.
(SOME_MACHINE_OBJECTS): Add appropriate Haiku C objects.
(all): Depend on Emacs and Emacs.pdmp on Haiku.
(LIBES): Add Haiku libraries.
(gl-stamp)
($(etc)/DOC): Scan doc_obj instead of obj
(temacs$(EXEEXT): Use C++ linker on Haiku.
(ctagsfiles3): New variable.
(TAGS): Scan C++ files.

* src/alloc.c (garbage_collect): Mark Haiku display.

* src/dispextern.h (HAVE_NATIVE_TRANSFORMS): Also enable
on Haiku.
(struct image): Add fields for Haiku transforms.
(RGB_PIXEL_COLOR): Define to unsigned long on Haiku as
well.
(sit_for): Also check USABLE_SIGPOLL.
(init_display_interactive): Set initial window system to
Haiku on Haiku builds.

* src/emacs.c (main): Define Haiku syms and init haiku
clipboard.
(shut_down_emacs): Quit BApplication on Haiku and
trigger debug
on aborts if haiku_debug_on_fatal_error.
(Vsystem_type): Update docstring.

* src/fileio.c (next-read-file-uses-dialog-p): Enable on
Haiku.

* src/filelock.c (WTMP_FILE): Only define if BOOT_TIME
is also defined.

* src/floatfns.c (double_integer_scale): Work around
Haiku libroot brain damage.

* src/font.c (syms_of_font): Define appropriate font
driver symbols for Haiku builds with various options.

* src/font.h: Also enable ftcrfont on Haiku builds with
Cairo.
(font_data_structures_may_be_ill_formed): Also enable on
Haiku builds that have Cairo.

* src/frame.c (Fframep): Update doc-string for Haiku
builds and return haiku if appropriate.
(syms_of_frame): New symbol `haiku'.

* src/frame.h (struct frame): Add output data for Haiku.
(FRAME_HAIKU_P): New macro.
(FRAME_WINDOW_P): Test for Haiku frames as well.

* src/ftcrfont.c (RED_FROM_ULONG, GREEN_FROM_ULONG)
(BLUE_FROM_ULONG): New macros.
(ftcrfont_draw): Add haiku specific code for Haiku
builds with Cairo.

* src/ftfont.c (ftfont_open): Set face.
(ftfont_has_char, ftfont_text_extents): Work around
crash.
(syms_of_ftfont): New symbol `mono'.

* src/ftfont.h (struct font_info): Enable Cairo-specific
fields for Cairo builds on Haiku.

* src/haiku_draw_support.cc:
* src/haiku_font_support.cc:
* src/haiku_io.c:
* src/haiku_select.cc:
* src/haiku_support.cc:
* src/haiku_support.h:
* src/haikufns.c:
* src/haikufont.c:
* src/haikugui.h:
* src/haikuimage.c:
* src/haikumenu.c:
* src/haikuselect.c:
* src/haikuselect.h:
* src/haikuterm.c:
* src/haikuterm.h: Add new files for Haiku windowing
support.

* src/haiku.c: Add new files for Haiku operating system
support.

* src/image.c: Implement image transforms and native XPM
support
on Haiku.

(GET_PIXEL, PUT_PIXEL, NO_PIXMAP)
(PIX_MASK_RETAIN, PIX_MASK_DRAW)
(RGB_TO_ULONG, RED_FROM_ULONG, GREEN_FROM_ULONG)
(BLUE_FROM_ULONG, RED16_FROM_ULONG, GREEN16_FROM_ULONG)
(BLUE16_FROM_ULONG): Define to appropriate values on
Haiku.

(image_create_bitmap_from_data): Add Haiku support.
(image_create_bitmap_from_file): Add TODO on Haiku.
(free_bitmap_record): Free bitmap on Haiku.
(image_size_in_bytes): Implement for Haiku bitmaps.
(image_set_transform): Implement on Haiku.
(image_create_x_image_and_pixmap_1): Implement on Haiku,
24-bit or 1-bit only.
(image_destroy_x_image, image_get_x_image): Use correct
img and pixmap values on Haiku.
(lookup_rgb_color): Use correct macro on Haiku.
(image_to_emacs_colors): Implement on Haiku.
(image_disable_image): Disable on Haiku.
(image_can_use_native_api): Test for translator presence
on Haiku.
(native_image_load): Use translator on Haiku.
(imagemagick_load_image): Add Haiku-specific quirks.
(Fimage_transforms_p): Allow rotate90 on Haiku.
(image_types): Enable native XPM support on Haiku.
(syms_of_image): Enable XPM images on Haiku.

* src/keyboard.c (kbd_buffer_get_event)
(handle_async_input, handle_input_available_signal)
(handle_user_signal, Fset_input_interrupt_mode)
(init_keyboard): Check for USABLE_SIGPOLL along with
USABLE_SIGIO.

* src/lisp.h (pD): Work around broken Haiku headers.
(HAVE_EXT_MENU_BAR): Define on Haiku.
(handle_input_available_signal): Enable if we just have
SIGPOLL as well.

* src/menu.c (have_boxes): Return true on Haiku.
(single_menu_item): Enable toolkit menus on Haiku.
(find_and_call_menu_selection): Also enable on Haiku.

* src/process.c (keyboard_bit_set): Enable with only
usable SIGPOLL.
(wait_reading_process_output): Test for SIGPOLL as well
as SIGIO availability.

* src/sound.c (sound_perror, vox_open)
(vox_configure, vox_close): Enable for usable SIGPOLL as
well.

* src/sysdep.c (sys_subshell): Enable for usable SIGPOLL.
(reset_sigio): Make conditional on F_SETOWN.
(request_sigio, unrequest_sigio)
(emacs_sigaction_init): Also handle SIGPOLLs.
(init_sys_modes): Disable TCXONC usage on Haiku, as it
doesn't have any ttys other than pseudo ttys, which don't
support C-s/C-q flow control, and causes compiler warnings.
(speeds): Disable high speeds if HAVE_TINY_SPEED_T.

* src/termhooks.h (enum output_method): Add output_haiku.
(struct terminal): Add Haiku display info.
(TERMINAL_FONT_CACHE): Enable for Haiku.

* src/terminal.c (Fterminal_live_p): Return `haiku' if
appropriate.
* src/verbose.mk.in (AM_V_CXX, AM_V_CXXLD): New logging
variables.

* src/xdisp.c (redisplay_internal)
(note_mouse_highlight): Return on Haiku if a popup is activated.
(display_menu_bar): Return on Haiku if frame is a Haiku
frame.

* src/xfaces.c (GCGraphicsExposures): Enable correctly on Haiku.
(x_create_gc): Enable dummy GC code on Haiku.

* src/xfns.c (x-server-version, x-file-dialog): Add
Haiku specifics to doc strings.

* src/xterm.c (syms_of_xterm): Add Haiku information to
doc string.
2021-11-20 21:46:07 +08:00

286 lines
7.2 KiB
C

/* Haiku subroutines that are general to the Haiku operating system.
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 "process.h"
#include "coding.h"
#include <kernel/OS.h>
#include <pwd.h>
#include <stdlib.h>
Lisp_Object
list_system_processes (void)
{
team_info info;
int32 cookie = 0;
Lisp_Object lval = Qnil;
while (get_next_team_info (&cookie, &info) == B_OK)
lval = Fcons (make_fixnum (info.team), lval);
return lval;
}
Lisp_Object
system_process_attributes (Lisp_Object pid)
{
CHECK_FIXNUM (pid);
team_info info;
Lisp_Object lval = Qnil;
thread_info inf;
area_info area;
team_id id = (team_id) XFIXNUM (pid);
struct passwd *g;
size_t mem = 0;
if (get_team_info (id, &info) != B_OK)
return Qnil;
bigtime_t everything = 0, vsample = 0;
bigtime_t cpu_eaten = 0, esample = 0;
lval = Fcons (Fcons (Qeuid, make_fixnum (info.uid)), lval);
lval = Fcons (Fcons (Qegid, make_fixnum (info.gid)), lval);
lval = Fcons (Fcons (Qthcount, make_fixnum (info.thread_count)), lval);
lval = Fcons (Fcons (Qcomm, build_string_from_utf8 (info.args)), lval);
g = getpwuid (info.uid);
if (g && g->pw_name)
lval = Fcons (Fcons (Quser, build_string (g->pw_name)), lval);
/* FIXME: Calculating this makes Emacs show up as using 100% CPU! */
for (int32 team_cookie = 0;
get_next_team_info (&team_cookie, &info) == B_OK;)
for (int32 thread_cookie = 0;
get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
{
if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
cpu_eaten += inf.user_time + inf.kernel_time;
everything += inf.user_time + inf.kernel_time;
}
sleep (0.05);
for (int32 team_cookie = 0;
get_next_team_info (&team_cookie, &info) == B_OK;)
for (int32 thread_cookie = 0;
get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
{
if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
esample += inf.user_time + inf.kernel_time;
vsample += inf.user_time + inf.kernel_time;
}
cpu_eaten = esample - cpu_eaten;
everything = vsample - everything;
if (everything)
lval = Fcons (Fcons (Qpcpu, make_float (((double) (cpu_eaten) /
(double) (everything)) * 100)),
lval);
else
lval = Fcons (Fcons (Qpcpu, make_float (0.0)), lval);
for (ssize_t area_cookie = 0;
get_next_area_info (id, &area_cookie, &area) == B_OK;)
mem += area.ram_size;
system_info sinfo;
get_system_info (&sinfo);
int64 max = (int64) sinfo.max_pages * B_PAGE_SIZE;
lval = Fcons (Fcons (Qpmem, make_float (((double) mem /
(double) max) * 100)),
lval);
lval = Fcons (Fcons (Qrss, make_fixnum (mem / 1024)), lval);
return lval;
}
/* Borrowed from w32 implementation. */
struct load_sample
{
time_t sample_time;
bigtime_t idle;
bigtime_t kernel;
bigtime_t user;
};
/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
static struct load_sample samples[16*60];
static int first_idx = -1, last_idx = -1;
static int max_idx = ARRAYELTS (samples);
static unsigned num_of_processors = 0;
static int
buf_next (int from)
{
int next_idx = from + 1;
if (next_idx >= max_idx)
next_idx = 0;
return next_idx;
}
static int
buf_prev (int from)
{
int prev_idx = from - 1;
if (prev_idx < 0)
prev_idx = max_idx - 1;
return prev_idx;
}
static double
getavg (int which)
{
double retval = -1.0;
double tdiff;
int idx;
double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
time_t now = samples[last_idx].sample_time;
if (first_idx != last_idx)
{
for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
{
tdiff = difftime (now, samples[idx].sample_time);
if (tdiff >= span - 2 * DBL_EPSILON * now)
{
long double sys =
(samples[last_idx].kernel + samples[last_idx].user) -
(samples[idx].kernel + samples[idx].user);
long double idl = samples[last_idx].idle - samples[idx].idle;
retval = (idl / (sys + idl)) * num_of_processors;
break;
}
if (idx == first_idx)
break;
}
}
return retval;
}
static void
sample_sys_load (bigtime_t *idle, bigtime_t *system, bigtime_t *user)
{
bigtime_t i = 0, s = 0, u = 0;
team_info info;
thread_info inf;
for (int32 team_cookie = 0;
get_next_team_info (&team_cookie, &info) == B_OK;)
for (int32 thread_cookie = 0;
get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
{
if (!strncmp (inf.name, "idle thread ", 12))
i += inf.user_time + inf.kernel_time;
else
s += inf.kernel_time, u += inf.user_time;
}
*idle = i;
*system = s;
*user = u;
}
int
getloadavg (double loadavg[], int nelem)
{
int elem;
bigtime_t idle, kernel, user;
time_t now = time (NULL);
if (num_of_processors <= 0)
{
system_info i;
if (get_system_info (&i) == B_OK)
num_of_processors = i.cpu_count;
}
/* If system time jumped back for some reason, delete all samples
whose time is later than the current wall-clock time. This
prevents load average figures from becoming frozen for prolonged
periods of time, when system time is reset backwards. */
if (last_idx >= 0)
{
while (difftime (now, samples[last_idx].sample_time) < -1.0)
{
if (last_idx == first_idx)
{
first_idx = last_idx = -1;
break;
}
last_idx = buf_prev (last_idx);
}
}
/* Store another sample. We ignore samples that are less than 1 sec
apart. */
if (last_idx < 0
|| (difftime (now, samples[last_idx].sample_time)
>= 1.0 - 2 * DBL_EPSILON * now))
{
sample_sys_load (&idle, &kernel, &user);
last_idx = buf_next (last_idx);
samples[last_idx].sample_time = now;
samples[last_idx].idle = idle;
samples[last_idx].kernel = kernel;
samples[last_idx].user = user;
/* If the buffer has more that 15 min worth of samples, discard
the old ones. */
if (first_idx == -1)
first_idx = last_idx;
while (first_idx != last_idx
&& (difftime (now, samples[first_idx].sample_time)
>= 15.0 * 60 + 2 * DBL_EPSILON * now))
first_idx = buf_next (first_idx);
}
for (elem = 0; elem < nelem; elem++)
{
double avg = getavg (elem);
if (avg < 0)
break;
loadavg[elem] = avg;
}
/* Always return at least one element, otherwise load-average
returns nil, and Lisp programs might decide we cannot measure
system load. For example, jit-lock-stealth-load's defcustom
might decide that feature is "unsupported". */
if (elem == 0)
loadavg[elem++] = 0.09; /* < display-time-load-average-threshold */
return elem;
}