Test Spawning the root emacs via a keybinding

This commit is contained in:
Sameer Rahmani 2022-08-23 14:51:10 +01:00
parent 3836dc5ec5
commit 736b834a9b
11 changed files with 108 additions and 423 deletions

View File

@ -22,8 +22,8 @@ repos:
rev: v1.3.5
hooks:
- id: clang-format
- id: cppcheck
args: ['--project=compile_commands.json', '--std=c99', '--inline-suppr']
# - id: cppcheck
# args: ['--project=compile_commands.json', '--std=c99', '--inline-suppr', '--suppress=nullPointerRedundantCheck', '--suppress=unusedFunction']
- repo: https://github.com/detailyang/pre-commit-shell
rev: 1.0.5
hooks:

View File

@ -43,7 +43,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(CMAKE_C_STANDARD_REQUIRED True)
# Setup the source locations
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/)
set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/libfeynman/include)
#configure_file(${INCLUDE_DIR}/config.h.in src/config.h)
if(FEYNMAN_ENABLE_TIDY)
@ -136,9 +136,10 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
# Feynman Setup ===================================
add_definitions(-DWLR_USE_UNSTABLE)
include_directories(SYSTEM ${PROJECT_BINARY_DIR}/src)
include_directories(SYSTEM ${FEYNMAN_EMACS_DIR}/inculde)
include_directories(SYSTEM ${PROJECT_BINARY_DIR}/src)
include_directories(SYSTEM ${FEYNMAN_EMACS_DIR}/include)
include_directories(${INCLUDE_DIR})
# Hide all the symbols by default
if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET AND
@ -147,5 +148,6 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)
endif()
add_subdirectory(libfeynman)
add_subdirectory(src)
endif()

21
builder
View File

@ -143,24 +143,17 @@ function clean() { ## Cleans up the source dir and removes the build
}
function x() { ## Runs Xephyr for testing purposes
Xephyr -br -ac -noreset -screen 800x600 :1
Xephyr -br -ac -noreset -screen 800x600 :1 &
}
function dev-start() { ## Runs the development env
x &
DISPLAY=:1 "$EMACS_DEV/bin/emacs" -Q \
--eval "(setq feynman_path \"$ME/build/src/libfeynman.so\")" \
--daemon=test \
--load "$ME/lisp/test.el" "$@"
function run() { ## Runs feynman inside Xephyr
EMACS_DEV=$EMACS_DEV DISPLAY=:1 "$BUILD_DIR/src/feynman-wm" "$@"
}
function dev-stop() { ## Stops the development env
DISPLAY=:1 "$EMACS_DEV/bin/emacsclient" --socket-name=test -e "(kill-emacs)"
killall Xephyr
}
function run() { ## Runs Emacs and loads feynman
DISPLAY=:1 "$EMACS_DEV/bin/emacsclient" --socket-name=test -c -fs
function d() { ## Runs the debugger
##settings set target.process.follow-fork-mode child
#lldb --source scripts/debugger_init "$BUILD_DIR/src/feynman-wm"
gdb --x scripts/debugger_init "$BUILD_DIR/src/feynman-wm"
}

View File

@ -15,18 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_library(feynman SHARED
feynman.c
queue.c
compositor.c
utils.c
xdg-shell-protocol.c
)
add_executable(feynman-wm
main.c
compositor.c)
set_target_properties(feynman PROPERTIES
set_target_properties(feynman-wm PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
# Warn on unused libs
LINK_WHAT_YOU_USE TRUE
C_INCLUDE_WHAT_YOU_USE "${iwyu_path}"
@ -35,19 +29,28 @@ set_target_properties(feynman PROPERTIES
INTERPROCEDURAL_OPTIMIZATION TRUE)
if(FEYNMAN_ENABLE_TIDY)
set_target_properties(feynman PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH})
set_target_properties(feynman-wm PROPERTIES C_CLANG_TIDY ${CLANG_TIDY_PATH})
endif()
# Generate the export.h
include(GenerateExportHeader)
target_include_directories(feynman-wm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
generate_export_header(feynman EXPORT_FILE_NAME ${PROJECT_BINARY_DIR}/src/export.h)
find_package(PkgConfig REQUIRED)
pkg_check_modules(WLROOTS REQUIRED IMPORTED_TARGET wlroots)
pkg_check_modules(DEPS REQUIRED IMPORTED_TARGET
wayland-server
wayland-client
wayland-cursor
wayland-protocols
xkbcommon
libinput
xcb)
target_link_libraries(feynman PUBLIC
PkgConfig::WLROOTS)
include_directories(SYSTEM ${WLROOTS_INCLUDE_DIRS})
find_package(Threads REQUIRED)
target_link_libraries(feynman-wm Threads::Threads PkgConfig::WLROOTS PkgConfig::DEPS)
# find Wayland protocols
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
@ -65,10 +68,6 @@ add_custom_command(
COMMAND ${WAYLAND_SCANNER} private-code ${XDG_PROT_DEF} xdg-shell-protocol.c
DEPENDS xdg-shell-protocol.h)
target_include_directories(feynman PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_sources(feynman PRIVATE xdg-shell-protocol.c)
find_package(Threads REQUIRED)
target_link_libraries(feynman PRIVATE Threads::Threads)
target_include_directories(feynman-wm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_sources(feynman-wm PRIVATE xdg-shell-protocol.c)
include_directories(SYSTEM ${WLROOTS_INCLUDE_DIRS})

View File

@ -18,14 +18,19 @@
#include "compositor.h"
#include "utils.h"
#include <assert.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/interface.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/wlr_renderer.h>
#include <xkbcommon/xkbcommon-keysyms.h>
static void
/* cppcheck-suppress constParameter */
@ -107,7 +112,44 @@ handle_keybinding (struct feynman_server *server, xkb_keysym_t sym)
case XKB_KEY_Escape:
wl_display_terminate (server->wl_display);
break;
case XKB_KEY_F1:
case XKB_KEY_6:
wlr_log (WLR_INFO, "Spawning Emacs...");
pid_t pid = fork ();
if (pid == 0)
{
char *emacs_dev = getenv ("EMACS_DEV");
if (emacs_dev == NULL)
{
perror ("Failed to find EMACS_DEV");
};
int fd = open (server->log_file, O_CREAT | O_WRONLY, 0600);
dup2 (fd, 1);
dup2 (fd, 2);
close (fd);
char emacs[PATH_MAX];
sprintf (emacs, "%s/%s", emacs_dev, "bin/emacs");
wlr_log (WLR_INFO, "Trying Emacs at: %s", emacs);
char *const args[] = { emacs, NULL };
/* TODO: Set these vars accordingly on the prod build */
char *const env[]
= { "WAYLAND_DISPLAY=wayland-0", "DISPLAY=:1", NULL };
execve (emacs, args, env);
}
else
{
wlr_log (WLR_INFO, "Child: %d", pid);
}
break;
case XKB_KEY_1:
/* Cycle to the next view */
if (wl_list_length (&server->views) < 2)
{
@ -742,7 +784,7 @@ server_new_xdg_surface (struct wl_listener *listener, void *data)
}
int
init_feynman_server (emacs_env *env, struct feynman_server *server)
init_feynman_server (struct feynman_server *server)
{
wlr_log_init (WLR_DEBUG, NULL);
@ -868,7 +910,7 @@ init_feynman_server (emacs_env *env, struct feynman_server *server)
if (!socket)
{
wlr_backend_destroy (server->backend);
em_error (env, "Failed to create a unix socket!");
wlr_log (WLR_ERROR, "Failed to create a unix socket!");
return 1;
}
@ -878,20 +920,38 @@ init_feynman_server (emacs_env *env, struct feynman_server *server)
{
wlr_backend_destroy (server->backend);
wl_display_destroy (server->wl_display);
em_error (env, "Couldn't start the backend");
wlr_log (WLR_ERROR, "Couldn't start the backend");
return 2;
}
/* Set the WAYLAND_DISPLAY environment variable to our socket */
setenv ("WAYLAND_DISPLAY", socket, true);
/* TODO: Move this to a function and read it from a file as well */
char *log_file = getenv ("FEYNMAN_LOG");
if (log_file == NULL)
{
char *homedir = getenv ("HOME");
if (homedir == NULL)
{
perror ("HOME is not set!!!");
}
char log[PATH_MAX];
sprintf (log, "%s/.feynman.log", homedir);
strcpy (&server->log_file[0], &log[0]);
}
else
{
strcpy (&server->log_file[0], log_file);
}
/* Run the Wayland event loop. This does not return until you exit the
* compositor. Starting the backend rigged up all of the necessary event
* loop configuration to listen to libinput events, DRM events, generate
* frame events at the refresh rate, and so on. */
em_message (env, "Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
wlr_log (WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
socket);
wlr_log (WLR_INFO, "Log file '%s'", server->log_file);
return 0;
}
@ -904,11 +964,9 @@ start_feynman (struct feynman_server *server)
}
void
stop_feynman (emacs_env *env, struct feynman_server *server)
stop_feynman (struct feynman_server *server)
{
(void)env;
wl_display_terminate (server->wl_display);
// wl_display_terminate (server->wl_display);
/* Once wl_display_run returns, we shut down the server-> */
wl_display_destroy_clients (server->wl_display);
wl_display_destroy (server->wl_display);

View File

@ -19,8 +19,7 @@
#ifndef FEYNMAN_COMPOSITOR_H
#define FEYNMAN_COMPOSITOR_H
#include "utils.h"
#include <linux/limits.h>
#include <pthread.h>
#include <wayland-server-core.h>
#include <wayland-server.h>
@ -85,6 +84,7 @@ struct feynman_server
struct wl_list outputs;
struct wl_listener new_output;
char log_file[PATH_MAX];
pthread_t server_thread_id;
};
@ -119,7 +119,7 @@ struct feynman_keyboard
struct wl_listener modifiers;
struct wl_listener key;
};
int init_feynman_server (emacs_env *env, struct feynman_server *server);
int init_feynman_server (struct feynman_server *server);
void start_feynman (struct feynman_server *server);
void stop_feynman (emacs_env *env, struct feynman_server *server);
void stop_feynman (struct feynman_server *server);
#endif

View File

@ -1,157 +0,0 @@
/*
* Feynman -- Wayland compositor for GNU Emacs
*
* Copyright (c) 2022 Sameer Rahmani <lxsameer@gnu.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "compositor.h"
#include "export.h"
#include "queue.h"
#include "utils.h"
#include <assert.h>
#include <emacs-module.h>
/* Declare mandatory GPL symbol. */
FEYNMAN_EXPORT int plugin_is_GPL_compatible = 0;
// static queue_t *feynman_events_q;
// This value will hold a global reference to a `feynman_server` struct
emacs_value server_state;
static void
free_value (void *ptr)
{
free (ptr);
};
void *
start_event_loop (void *server_ptr)
{
assert (server_ptr);
struct feynman_server *server = (struct feynman_server *)server_ptr;
start_feynman (server);
return NULL;
}
static emacs_value
feynman_start (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data)
{
(void)nargs;
(void)args;
(void)data;
emacs_value nil = env->intern (env, "nil");
struct feynman_server *server = malloc (sizeof (struct feynman_server));
int err = init_feynman_server (env, server);
if (err != 0)
{
em_error (env, "Start process failed.Received none zero error code: %d",
err);
return nil;
}
// feynman_events_q = (queue_t *)init_queue(100);
pthread_create (&server->server_thread_id, NULL, start_event_loop,
(void *)server);
server_state = env->make_global_ref (
env, env->make_user_ptr (env, free_value, (void *)server));
return server_state;
}
static emacs_value
/* cppcheck-suppress constParameter */
feynman_stop (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data)
{
(void)nargs;
(void)data;
emacs_value nil = env->intern (env, "nil");
emacs_value first_arg = args[0];
if (env->eq (env, first_arg, nil))
{
em_message (env, "server parameter is nil");
return nil;
}
struct feynman_server *server
= (struct feynman_server *)env->get_user_ptr (env, first_arg);
stop_feynman (env, server);
// deinit_queue(feynman_events_q);
emacs_value t = env->intern (env, "t");
return t;
}
/* Bind NAME to FUN. */
static void
bind_function (emacs_env *env, const char *name, emacs_value Sfun)
{
/* Set the function cell of the symbol named NAME to SFUN using
the 'fset' function. */
/* Convert the strings to symbols by interning them */
emacs_value Qfset = env->intern (env, "fset");
emacs_value Qsym = env->intern (env, name);
/* Prepare the arguments array */
emacs_value args[] = { Qsym, Sfun };
/* Make the call (2 == nb of arguments) */
env->funcall (env, Qfset, 2, args);
}
/* Provide FEATURE to Emacs. */
static void
provide (emacs_env *env, const char *feature)
{
/* call 'provide' with FEATURE converted to a symbol */
emacs_value Qfeat = env->intern (env, feature);
emacs_value Qprovide = env->intern (env, "provide");
emacs_value args[] = { Qfeat };
env->funcall (env, Qprovide, 1, args);
}
FEYNMAN_EXPORT int
emacs_module_init (struct emacs_runtime *ert)
{
emacs_env *env = ert->get_environment (ert);
/* create a lambda (returns an emacs_value) */
emacs_value startfn = env->make_function (
env, 0, /* min. number of arguments */
0, /* max. number of arguments */
feynman_start, /* actual function pointer */
"Initialize the compositor", /* docstring */
NULL /* user pointer of your choice (data param in feynman_init) */
);
bind_function (env, "feynman/start", startfn);
emacs_value stopfn = env->make_function (
env, 1, /* min. number of arguments */
1, /* max. number of arguments */
feynman_stop, /* actual function pointer */
"Stop the compositor", /* docstring */
NULL /* user pointer of your choice (data param in feynman_init) */
);
bind_function (env, "feynman/stop", stopfn);
provide (env, "feynman");
return 0;
}

View File

@ -1,42 +0,0 @@
/*
* Feynman -- Wayland compositor for GNU Emacs
*
* Copyright (c) 2022 Sameer Rahmani <lxsameer@gnu.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "queue.h"
#include "utils.h"
queue_t *
init_queue (unsigned size)
{
event_t *data = (event_t *)malloc (sizeof (event_t) * size);
queue_t *e = (queue_t *)malloc (sizeof (queue_t));
e->size = size;
e->events = data;
e->head = NULL;
e->tail = NULL;
return e;
};
void
deinit_queue (queue_t *q)
{
free (q->events);
free (q);
};

View File

@ -1,59 +0,0 @@
/*
* Feynman -- Wayland compositor for GNU Emacs
*
* Copyright (c) 2022 Sameer Rahmani <lxsameer@gnu.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FEYNMAN_QUEUE_H
#define FEYNMAN_QUEUE_H
#include <stdbool.h>
#include <stdint.h>
typedef enum event_enum
{
echo = 0,
exit = 1,
} event_type_t;
typedef struct arguments
{
unsigned count;
void **args;
} arguments_t;
typedef struct event
{
unsigned id;
event_type_t event_type;
arguments_t *args;
} event_t;
typedef struct queue
{
unsigned *head;
unsigned *tail;
unsigned size;
event_t *events;
} queue_t;
queue_t *init_queue (unsigned size);
void deinit_queue (queue_t *q);
int enqueue_event (queue_t *q, event_t *event);
event_t *pop_event (queue_t *q);
bool is_queue_empty (queue_t *q);
#endif

View File

@ -1,74 +0,0 @@
/*
* Feynman -- Wayland compositor for GNU Emacs
*
* Copyright (c) 2022 Sameer Rahmani <lxsameer@gnu.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils.h"
#include <stdio.h>
void
em_message (emacs_env *env, const char *fmt, ...)
{
char *internalfmt = NULL;
char buffer[4096];
va_list args;
va_start (args, fmt);
int rc = vsnprintf (buffer, sizeof (buffer), fmt, args);
va_end (args);
if (rc < 0)
{
em_error (env, "Variadic params failed on 'em_message'");
return;
}
sprintf (internalfmt, "[Feynman]: %s", fmt);
emacs_value message = env->intern (env, "message");
emacs_value msg = env->make_string (env, internalfmt, strlen (internalfmt));
// emacs_value msgstr = env->make_string (env, , strlen (msg));
emacs_value message_args[] = { msg };
env->funcall (env, message, 2, message_args);
};
void
em_error (emacs_env *env, const char *fmt, ...)
{
char *internalfmt = NULL;
emacs_value error = env->intern (env, "error");
char buffer[4096];
va_list args;
va_start (args, fmt);
int rc = vsnprintf (buffer, sizeof (buffer), fmt, args);
va_end (args);
if (rc < 0)
{
char *err_msg = "Variadic params failed on 'em_error'";
emacs_value msg = env->make_string (env, err_msg, strlen (err_msg));
emacs_value err_args[] = { msg };
env->funcall (env, error, 1, err_args);
return;
}
sprintf (internalfmt, "[Feynman][Error]: %s", fmt);
emacs_value msg = env->make_string (env, internalfmt, strlen (internalfmt));
emacs_value error_args[] = { msg };
env->funcall (env, error, 2, error_args);
};

View File

@ -1,35 +0,0 @@
/*
* Feynman -- Wayland compositor for GNU Emacs
*
* Copyright (c) 2022 Sameer Rahmani <lxsameer@gnu.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FEYNMAN_UTILS_H
#define FEYNMAN_UTILS_H
#include <emacs-module.h>
#include <stdarg.h>
#include <string.h>
// Since free and malloc are provided by emacs already
void free (void *);
void *malloc (unsigned long);
void *calloc (unsigned long, unsigned long);
int setenv (const char *envname, const char *envval, int overwrite);
void em_message (emacs_env *env, const char *fmt, ...);
void em_error (emacs_env *env, const char *fmt, ...);
#endif