Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
  • 18 commits
  • 18 files changed
  • 0 commit comments
  • 1 contributor
Commits on Mar 25, 2012
@dvdhrm eloop: catch EINTR in epoll_wait()
epoll_wait() returns EINTR even if using SA_RESTART for signals.
Therefore, catch EINTR and set count to zero.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
ac9df3a
@dvdhrm hook: delete by callback *and* data argument
When deleting a hook we should not search for the callback only. Otherwise
we might remove the wrong callback. Therefore, we now search for callback
and data argument. If multiple callbacks are registered with the same data
and cb, then we don't care which one is removed as this wouldn't make any
difference. They behave the same way, anyway.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
56f5eeb
@dvdhrm eloop: add shared signal callbacks
Our current signal source has the problem that a single signal event is
only delivered to one random registered source. This is the design of the
signalfd kernel feature. However, for signals like SIGCHLD it is often
desired to have multiple callbacks. Hence, while keeping the old
signal-source, we now also allow a shared signal source. It is registered
the same way as the old signal source but uses a shared hook.

We may remove the old source so we don't use it in the new implementation.
There are still problems when multiple eloops are used in a single
process and you register the same shared-signum in both eloops. However,
such a design is bad anyway, so we don't care.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
580b0a7
@dvdhrm main: use new shared signals
Use the shared signal-implementation instead of the generic signals.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
f545d96
@dvdhrm use pthread_sigmask instead of sigprocmask
pthread is already in our vmem due to our dependencies so link to it
explicitly and use pthread_sigmask to avoid buggy sigprocmask in
multi-threaded applications.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
9e87b85
@dvdhrm vt: use new shared signals
Use the new shared-signal backend so we can finally remove the old
signals.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
524cfb0
@dvdhrm eloop: remove old signal sources
Remove the old non-shared signal sources in favor of shared-signals.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
21f6bbb
@dvdhrm pty: fix race when starting child
We should do fork() as the last operation when starting the child.
Currently, if our eloop-add() fails, we have a started child but return
failure to the caller. Therefore, the child will stay alive but we do not
use it.

We now perform all startup correctly before fork()'ing so we are always
safe when starting the child.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
6bcc736
@dvdhrm pty: fix wrong fd check
FDs may be 0 so check for >= and not > for fds.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
0392fb8
@dvdhrm pty: correctly terminate when child_setup fails
We currently return "ret" when child setup fails, however, we should
rather call exit(). Also avoid cleaning up as this is impossible here
anyway.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
e0546ad
@dvdhrm pty: random fixes
Fix some random coding-style issues and adjust to new eloop-rules.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
5cdf947
@dvdhrm pty: fix using right fd
Use right fd when spawning child process.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
3935a77
@dvdhrm eloop: wait for all childs
Move child-waiting into the eloop subsystem so all childs are always
correctly freed.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
9a2e025
@dvdhrm pty: avoid calling callbacks twice
We shouldn't call the close-cb twice. Therefore, correctly free the FD on
first error, however, keep the signal-callback to get nice log-messages.
Only when the user calls *_close() we eventually stop everything.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
84b87c3
Commits on Mar 27, 2012
@dvdhrm pty: add kmscon_pty_signal()
Allow to send arbitrary signals to the foreground process group of the
pty. Linux supports the TIOCSIG ioctl so we actually do not need to
implement this on our own, yeah!

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
3bcce95
@dvdhrm terminal: rework API
We now use the new input/video hooks to avoid waking up the UI all the
time. This reduces the code in the generic UI subsystem and makes the
terminal handle all the stuff.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
622f3c7
@dvdhrm Bump version number to 1
We use a single version number. The current state seems to be pretty
stable and has all the important features regarding the DRM/input setup.
Only missing stuff is VTE and console.
This is no stable release but rather a first development release.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
f02d745
@dvdhrm Update README
Fix some small typos and add TODOs.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
1648c91
View
3  Makefile.am
@@ -97,7 +97,8 @@ libkmscon_core_la_LIBADD = \
$(FREETYPE2_LIBS) \
$(XPROTO_LIBS) \
$(XKBCOMMON_LIBS) \
- $(GLIB_LIBS)
+ $(GLIB_LIBS) \
+ -lpthread
kmscon_SOURCES = src/main.c
kmscon_LDADD = libkmscon-core.la
View
18 README
@@ -8,11 +8,11 @@ console.
- libdrm: accessing the kernel graphics layer
- mesa: providing an OpenGL implementation (must be compiled with EGL, gbm
and GL libraries)
- - udev: providing input device hotplug
- - xproto (build time dependency): definition of key symbols
+ - udev: providing input, video, etc. hotplug support
+ - xproto (build time dependency): definition of keysymbols (TODO: remove it)
- libxkbcommon: keyboard handling (optional but strongly recommended)
Without libxkbcommon, basic US-ASCII input is provided.
- - glib: only for Unicode handling
+ - glib: only for Unicode handling (TODO: remove it)
- One of:
- freetype2: drawing generic text
- pango: drawing text with pango (use --enable-pango)
@@ -22,10 +22,18 @@ console.
To compile the kmscon binary, run the standard autotools commands:
$ ./configure [--enable-debug] [--enable-pango]
$ make
- $ make install
+ $ make install (TODO: this is currently not supported)
To compile the test applications, run:
$ make check
+== Running ==
+ To get usage information, run:
+ $ ./kmscon --help
+ You can then run kmscon with:
+ $ ./kmscon [options] --switchvt
+ The --switchvt option will make your machine switch the active VT directly to
+ kmscon after starting it.
+
== License ==
This software is licensed under the terms of the MIT license. Please see
./COPYING for further information.
@@ -45,7 +53,7 @@ console.
== Code Base ==
The kmscon code is split into several independent subsystems:
- - output:
+ - uterm:
This code manages the KMS/DRI output and provides OpenGL framebuffers.
- console:
This draws the text on the screen and provides an API for any terminal
View
2  configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ(2.68)
-AC_INIT([kmscon], [0.0])
+AC_INIT([kmscon], [1])
AC_SUBST(PACKAGE_URL, [https://github.com/dvdhrm/kmscon])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_AUX_DIR([build-aux])
View
246 src/eloop.c
@@ -32,6 +32,7 @@
*/
#include <errno.h>
+#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -40,13 +41,23 @@
#include <sys/signalfd.h>
#include <sys/time.h>
#include <sys/timerfd.h>
+#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include "eloop.h"
#include "log.h"
+#include "misc.h"
#define LOG_SUBSYSTEM "eloop"
+struct ev_signal_shared {
+ struct ev_signal_shared *next;
+
+ struct ev_fd *fd;
+ int signum;
+ struct kmscon_hook *hook;
+};
+
struct ev_eloop {
int efd;
unsigned long ref;
@@ -55,6 +66,8 @@ struct ev_eloop {
struct ev_idle *idle_list;
struct ev_idle *cur_idle;
+ struct ev_signal_shared *sig_list;
+
struct epoll_event *cur_fds;
size_t cur_fds_cnt;
bool exit;
@@ -79,14 +92,6 @@ struct ev_fd {
int fd;
};
-struct ev_signal {
- unsigned long ref;
-
- struct ev_fd *fd;
- ev_signal_cb cb;
- void *data;
-};
-
struct ev_timer {
unsigned long ref;
@@ -138,6 +143,16 @@ int ev_eloop_add_eloop(struct ev_eloop *loop, struct ev_eloop *add)
if (add->fd->loop)
return -EALREADY;
+ /* This adds the epoll-fd into the parent epoll-set. This works
+ * perfectly well with registered FDs, timers, etc. However, we use
+ * shared signals in this event-loop so if the parent and child have
+ * overlapping shared-signals, then the signal will be randomly
+ * delivered to either the parent-hook or child-hook but never both.
+ * TODO:
+ * We may fix this by linking the childs-sig_list into the parent's
+ * siglist but we didn't need this, yet, so ignore it here.
+ */
+
ret = ev_eloop_add_fd(loop, add->fd, add->efd, EV_READABLE,
eloop_cb, add);
if (ret)
@@ -411,140 +426,159 @@ int ev_eloop_update_fd(struct ev_fd *fd, int mask)
return 0;
}
-int ev_signal_new(struct ev_signal **out)
+static void sig_child()
{
- struct ev_signal *sig;
- int ret;
+ pid_t pid;
+ int status;
- if (!out)
- return -EINVAL;
-
- sig = malloc(sizeof(*sig));
- if (!sig)
- return -ENOMEM;
-
- memset(sig, 0, sizeof(*sig));
- sig->ref = 1;
-
- ret = ev_fd_new(&sig->fd);
- if (ret) {
- free(sig);
- return ret;
+ while (1) {
+ pid = waitpid(-1, &status, WNOHANG);
+ if (pid == -1) {
+ if (errno != ECHILD)
+ log_warn("cannot wait on child: %m");
+ break;
+ } else if (pid == 0) {
+ break;
+ } else if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0)
+ log_debug("child %d exited with status %d",
+ pid, WEXITSTATUS(status));
+ else
+ log_debug("child %d exited successfully", pid);
+ } else if (WIFSIGNALED(status)) {
+ log_debug("child %d exited by signal %d", pid,
+ WTERMSIG(status));
+ }
}
-
- *out = sig;
- return 0;
-}
-
-void ev_signal_ref(struct ev_signal *sig)
-{
- if (!sig)
- return;
-
- ++sig->ref;
}
-void ev_signal_unref(struct ev_signal *sig)
+static void shared_signal_cb(struct ev_fd *fd, int mask, void *data)
{
- if (!sig || !sig->ref || --sig->ref)
- return;
-
- ev_fd_unref(sig->fd);
- free(sig);
-}
-
-int ev_eloop_new_signal(struct ev_eloop *loop, struct ev_signal **out,
- int signum, ev_signal_cb cb, void *data)
-{
- struct ev_signal *sig;
- int ret;
-
- if (!out || !loop || !cb || signum < 0)
- return -EINVAL;
-
- ret = ev_signal_new(&sig);
- if (ret)
- return ret;
-
- ret = ev_eloop_add_signal(loop, sig, signum, cb, data);
- if (ret) {
- ev_signal_unref(sig);
- return ret;
- }
-
- ev_signal_unref(sig);
- *out = sig;
- return 0;
-}
-
-static void signal_cb(struct ev_fd *fd, int mask, void *data)
-{
- struct ev_signal *sig = data;
- struct signalfd_siginfo signal_info;
+ struct ev_signal_shared *sig = data;
+ struct signalfd_siginfo info;
int len;
if (mask & EV_READABLE) {
- len = read(fd->fd, &signal_info, sizeof(signal_info));
- if (len != sizeof(signal_info))
+ len = read(fd->fd, &info, sizeof(info));
+ if (len != sizeof(info))
log_warn("cannot read signalfd");
else
- sig->cb(sig, signal_info.ssi_signo, sig->data);
+ kmscon_hook_call(sig->hook, sig->fd->loop, &info);
+
+ if (info.ssi_signo == SIGCHLD)
+ sig_child();
} else if (mask & (EV_HUP | EV_ERR)) {
log_warn("HUP/ERR on signal source");
}
}
-int ev_eloop_add_signal(struct ev_eloop *loop, struct ev_signal *sig,
- int signum, ev_signal_cb cb, void *data)
+static int signal_new(struct ev_signal_shared **out, struct ev_eloop *loop,
+ int signum)
{
sigset_t mask;
int ret, fd;
+ struct ev_signal_shared *sig;
- if (!loop || !sig || signum < 0 || !cb)
+ if (!out || !loop || signum < 0)
return -EINVAL;
- if (sig->fd->loop)
- return -EALREADY;
+ sig = malloc(sizeof(*sig));
+ if (!sig)
+ return -ENOMEM;
+ memset(sig, 0, sizeof(*sig));
+ sig->signum = signum;
+
+ ret = kmscon_hook_new(&sig->hook);
+ if (ret)
+ goto err_free;
sigemptyset(&mask);
sigaddset(&mask, signum);
fd = signalfd(-1, &mask, SFD_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- ret = ev_eloop_add_fd(loop, sig->fd, fd, EV_READABLE, signal_cb, sig);
- if (ret) {
- close(fd);
- return ret;
+ if (fd < 0) {
+ ret = -errno;
+ goto err_hook;
}
- sigprocmask(SIG_BLOCK, &mask, NULL);
- sig->cb = cb;
- sig->data = data;
- ev_signal_ref(sig);
+ ret = ev_eloop_new_fd(loop, &sig->fd, fd, EV_READABLE,
+ shared_signal_cb, sig);
+ if (ret)
+ goto err_sig;
+
+ pthread_sigmask(SIG_BLOCK, &mask, NULL);
+ sig->next = loop->sig_list;
+ loop->sig_list = sig;
+ *out = sig;
return 0;
+
+err_sig:
+ close(fd);
+err_hook:
+ kmscon_hook_free(sig->hook);
+err_free:
+ free(sig);
+ return ret;
}
-void ev_eloop_rm_signal(struct ev_signal *sig)
+static void signal_free(struct ev_signal_shared *sig)
{
int fd;
- if (!sig || !sig->fd->loop)
+ if (!sig)
return;
fd = sig->fd->fd;
ev_eloop_rm_fd(sig->fd);
close(fd);
- ev_signal_unref(sig);
-
- /*
- * We cannot unblock the signal here because we do not know whether some
- * other subsystem also added the signal to the sigprocmask.
+ kmscon_hook_free(sig->hook);
+ free(sig);
+ /* We do not unblock the signal here as there may be other subsystems
+ * which blocked this signal so we do not want to interfere. If you need
+ * a clean sigmask then do it yourself.
*/
}
+int ev_eloop_register_signal_cb(struct ev_eloop *loop, int signum,
+ ev_signal_shared_cb cb, void *data)
+{
+ struct ev_signal_shared *sig;
+ int ret;
+
+ if (!loop || signum < 0 || !cb)
+ return -EINVAL;
+
+ for (sig = loop->sig_list; sig; sig = sig->next) {
+ if (sig->signum == signum)
+ break;
+ }
+
+ if (!sig) {
+ ret = signal_new(&sig, loop, signum);
+ if (ret)
+ return ret;
+ }
+
+ return kmscon_hook_add_cast(sig->hook, cb, data);
+}
+
+void ev_eloop_unregister_signal_cb(struct ev_eloop *loop, int signum,
+ ev_signal_shared_cb cb, void *data)
+{
+ struct ev_signal_shared *sig;
+
+ if (!loop)
+ return;
+
+ for (sig = loop->sig_list; sig; sig = sig->next) {
+ if (sig->signum == signum) {
+ kmscon_hook_rm_cast(sig->hook, cb, data);
+ return;
+ }
+ }
+}
+
int ev_timer_new(struct ev_timer **out)
{
struct ev_timer *timer;
@@ -745,10 +779,18 @@ void ev_eloop_ref(struct ev_eloop *loop)
void ev_eloop_unref(struct ev_eloop *loop)
{
+ struct ev_signal_shared *sig;
+
if (!loop || !loop->ref || --loop->ref)
return;
log_debug("free eloop object %p", loop);
+
+ while ((sig = loop->sig_list)) {
+ loop->sig_list = sig->next;
+ signal_free(sig);
+ }
+
ev_fd_unref(loop->fd);
close(loop->efd);
free(loop);
@@ -774,8 +816,12 @@ int ev_eloop_dispatch(struct ev_eloop *loop, int timeout)
/* dispatch fd events */
count = epoll_wait(loop->efd, ep, 32, timeout);
if (count < 0) {
- log_warn("epoll_wait dispatching failed: %m");
- return -errno;
+ if (errno == EINTR) {
+ count = 0;
+ } else {
+ log_warn("epoll_wait dispatching failed: %m");
+ return -errno;
+ }
}
loop->cur_fds = ep;
View
19 src/eloop.h
@@ -36,18 +36,18 @@
#include <inttypes.h>
#include <stdlib.h>
+#include <sys/signalfd.h>
#include <time.h>
struct ev_eloop;
struct ev_idle;
struct ev_fd;
-struct ev_signal;
struct ev_timer;
typedef void (*ev_idle_cb) (struct ev_idle *idle, void *data);
typedef void (*ev_fd_cb) (struct ev_fd *fd, int mask, void *data);
-typedef void (*ev_signal_cb)
- (struct ev_signal *sig, int signum, void *data);
+typedef void (*ev_signal_shared_cb)
+ (struct ev_eloop *eloop, struct signalfd_siginfo *info, void *data);
typedef void (*ev_timer_cb)
(struct ev_timer *timer, uint64_t num, void *data);
@@ -99,15 +99,10 @@ int ev_eloop_update_fd(struct ev_fd *fd, int mask);
/* signal sources */
-int ev_signal_new(struct ev_signal **out);
-void ev_signal_ref(struct ev_signal *sig);
-void ev_signal_unref(struct ev_signal *sig);
-
-int ev_eloop_new_signal(struct ev_eloop *loop, struct ev_signal **out,
- int signum, ev_signal_cb cb, void *data);
-int ev_eloop_add_signal(struct ev_eloop *loop, struct ev_signal *sig,
- int signum, ev_signal_cb cb, void *data);
-void ev_eloop_rm_signal(struct ev_signal *sig);
+int ev_eloop_register_signal_cb(struct ev_eloop *loop, int signum,
+ ev_signal_shared_cb cb, void *data);
+void ev_eloop_unregister_signal_cb(struct ev_eloop *loop, int signum,
+ ev_signal_shared_cb cb, void *data);
/* timer sources */
View
5 src/input.c
@@ -615,12 +615,13 @@ int kmscon_input_register_cb(struct kmscon_input *input, kmscon_input_cb cb,
return kmscon_hook_add_cast(input->hook, cb, data);
}
-void kmscon_input_unregister_cb(struct kmscon_input *input, kmscon_input_cb cb)
+void kmscon_input_unregister_cb(struct kmscon_input *input, kmscon_input_cb cb,
+ void *data)
{
if (!input || !cb)
return;
- kmscon_hook_rm_cast(input->hook, cb);
+ kmscon_hook_rm_cast(input->hook, cb, data);
}
void kmscon_input_sleep(struct kmscon_input *input)
View
3  src/input.h
@@ -87,7 +87,8 @@ int kmscon_input_connect_eloop(struct kmscon_input *input,
void kmscon_input_disconnect_eloop(struct kmscon_input *input);
int kmscon_input_register_cb(struct kmscon_input *input, kmscon_input_cb cb,
void *data);
-void kmscon_input_unregister_cb(struct kmscon_input *input, kmscon_input_cb cb);
+void kmscon_input_unregister_cb(struct kmscon_input *input, kmscon_input_cb cb,
+ void *data);
void kmscon_input_sleep(struct kmscon_input *input);
void kmscon_input_wake_up(struct kmscon_input *input);
View
54 src/main.c
@@ -28,7 +28,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/wait.h>
+#include <sys/signalfd.h>
#include "conf.h"
#include "eloop.h"
#include "input.h"
@@ -40,9 +40,6 @@
struct kmscon_app {
struct ev_eloop *eloop;
struct ev_eloop *vt_eloop;
- struct ev_signal *sig_term;
- struct ev_signal *sig_int;
- struct ev_signal *sig_child;
struct kmscon_vt *vt;
bool exit;
struct uterm_video *video;
@@ -50,38 +47,13 @@ struct kmscon_app {
struct kmscon_ui *ui;
};
-static void sig_generic(struct ev_signal *sig, int signum, void *data)
+static void sig_generic(struct ev_eloop *eloop, struct signalfd_siginfo *info,
+ void *data)
{
struct kmscon_app *app = data;
ev_eloop_exit(app->eloop);
- log_info("terminating due to caught signal %d", signum);
-}
-
-static void sig_child(struct ev_signal *sig, int signum, void *data)
-{
- pid_t pid;
- int status;
-
- while (1) {
- pid = waitpid(-1, &status, WNOHANG);
- if (pid == -1) {
- if (errno != ECHILD)
- log_warn("cannot wait on child: %m");
- break;
- } else if (pid == 0) {
- break;
- } else if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != 0)
- log_info("child %d exited with status %d",
- pid, WEXITSTATUS(status));
- else
- log_info("child %d exited successfully", pid);
- } else if (WIFSIGNALED(status)) {
- log_info("child %d exited by signal %d", pid,
- WTERMSIG(status));
- }
- }
+ log_info("terminating due to caught signal %d", info->ssi_signo);
}
static bool vt_switch(struct kmscon_vt *vt,
@@ -114,10 +86,9 @@ static void destroy_app(struct kmscon_app *app)
kmscon_input_unref(app->input);
uterm_video_unref(app->video);
kmscon_vt_unref(app->vt);
+ ev_eloop_unregister_signal_cb(app->eloop, SIGINT, sig_generic, app);
+ ev_eloop_unregister_signal_cb(app->eloop, SIGTERM, sig_generic, app);
ev_eloop_rm_eloop(app->vt_eloop);
- ev_eloop_rm_signal(app->sig_child);
- ev_eloop_rm_signal(app->sig_int);
- ev_eloop_rm_signal(app->sig_term);
ev_eloop_unref(app->eloop);
}
@@ -129,18 +100,13 @@ static int setup_app(struct kmscon_app *app)
if (ret)
goto err_app;
- ret = ev_eloop_new_signal(app->eloop, &app->sig_term, SIGTERM,
- sig_generic, app);
- if (ret)
- goto err_app;
-
- ret = ev_eloop_new_signal(app->eloop, &app->sig_int, SIGINT,
- sig_generic, app);
+ ret = ev_eloop_register_signal_cb(app->eloop, SIGTERM,
+ sig_generic, app);
if (ret)
goto err_app;
- ret = ev_eloop_new_signal(app->eloop, &app->sig_child, SIGCHLD,
- sig_child, app);
+ ret = ev_eloop_register_signal_cb(app->eloop, SIGINT,
+ sig_generic, app);
if (ret)
goto err_app;
View
6 src/misc.c
@@ -227,7 +227,7 @@ int kmscon_hook_add(struct kmscon_hook *hook, kmscon_hook_cb cb, void *data)
return 0;
}
-void kmscon_hook_rm(struct kmscon_hook *hook, kmscon_hook_cb cb)
+void kmscon_hook_rm(struct kmscon_hook *hook, kmscon_hook_cb cb, void *data)
{
struct hook_entry *entry, *tmp;
@@ -235,11 +235,11 @@ void kmscon_hook_rm(struct kmscon_hook *hook, kmscon_hook_cb cb)
return;
tmp = NULL;
- if (hook->entries->cb == cb) {
+ if (hook->entries->cb == cb && hook->entries->data == data) {
tmp = hook->entries;
hook->entries = tmp->next;
} else for (entry = hook->entries; entry->next; entry = entry->next) {
- if (entry->next->cb == cb) {
+ if (entry->next->cb == cb && entry->next->data == data) {
tmp = entry->next;
entry->next = tmp->next;
break;
View
6 src/misc.h
@@ -51,11 +51,11 @@ typedef void (*kmscon_hook_cb) (void *parent, void *arg, void *data);
int kmscon_hook_new(struct kmscon_hook **out);
void kmscon_hook_free(struct kmscon_hook *hook);
int kmscon_hook_add(struct kmscon_hook *hook, kmscon_hook_cb cb, void *data);
-void kmscon_hook_rm(struct kmscon_hook *hook, kmscon_hook_cb cb);
+void kmscon_hook_rm(struct kmscon_hook *hook, kmscon_hook_cb cb, void *data);
void kmscon_hook_call(struct kmscon_hook *hook, void *parent, void *arg);
#define kmscon_hook_add_cast(hook, cb, data) \
kmscon_hook_add((hook), (kmscon_hook_cb)(cb), (data))
-#define kmscon_hook_rm_cast(hook, cb) \
- kmscon_hook_rm((hook), (kmscon_hook_cb)(cb))
+#define kmscon_hook_rm_cast(hook, cb, data) \
+ kmscon_hook_rm((hook), (kmscon_hook_cb)(cb), (data))
#endif /* KMSCON_MISC_H */
View
180 src/pty.c
@@ -25,11 +25,14 @@
#include <errno.h>
#include <fcntl.h>
+#include <pthread.h>
#include <pty.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/signalfd.h>
#include <termios.h>
#include <unistd.h>
#include "conf.h"
@@ -48,6 +51,7 @@ struct kmscon_pty {
struct ev_eloop *eloop;
int fd;
+ pid_t child;
struct ev_fd *efd;
struct kmscon_ring *msgbuf;
char io_buf[KMSCON_NREAD];
@@ -110,6 +114,39 @@ void kmscon_pty_unref(struct kmscon_pty *pty)
free(pty);
}
+static bool pty_is_open(struct kmscon_pty *pty)
+{
+ return pty->fd >= 0;
+}
+
+static void sig_child(struct ev_eloop *eloop, struct signalfd_siginfo *info,
+ void *data);
+
+static void pty_close(struct kmscon_pty *pty, bool user)
+{
+ bool called = true;
+
+ if (!pty || !pty_is_open(pty))
+ return;
+
+ if (pty->efd) {
+ called = false;
+ ev_eloop_rm_fd(pty->efd);
+ pty->efd = NULL;
+ }
+
+ if (!user) {
+ if (!called)
+ pty->input_cb(pty, NULL, 0, pty->data);
+
+ return;
+ }
+
+ ev_eloop_unregister_signal_cb(pty->eloop, SIGCHLD, sig_child, pty);
+ close(pty->fd);
+ pty->fd = -1;
+}
+
static void __attribute__((noreturn))
exec_child(int pty_master)
{
@@ -118,10 +155,10 @@ exec_child(int pty_master)
log_err("failed to exec child: %m");
- _exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
-static int setup_child(int master, struct winsize *ws)
+static void setup_child(int master, struct winsize *ws)
{
int ret;
sigset_t sigset;
@@ -131,7 +168,7 @@ static int setup_child(int master, struct winsize *ws)
/* The child should not inherit our signal mask. */
sigemptyset(&sigset);
- ret = sigprocmask(SIG_SETMASK, &sigset, NULL);
+ ret = pthread_sigmask(SIG_SETMASK, &sigset, NULL);
if (ret)
log_warn("cannot reset blocked signals: %m");
@@ -182,14 +219,14 @@ static int setup_child(int master, struct winsize *ws)
close(master);
close(slave);
- return 0;
+ return;
err_out:
ret = -errno;
- if (slave > 0)
+ if (slave >= 0)
close(slave);
close(master);
- return ret;
+ exit(EXIT_FAILURE);
}
/*
@@ -197,50 +234,33 @@ static int setup_child(int master, struct winsize *ws)
* a little bit more control of the process, and as a bonus avoid linking to
* the libutil library in glibc.
*/
-static int pty_spawn(struct kmscon_pty *pty, unsigned short width,
- unsigned short height)
+static int pty_spawn(struct kmscon_pty *pty, int master,
+ unsigned short width, unsigned short height)
{
- int ret;
pid_t pid;
- int master;
struct winsize ws;
- if (pty->fd >= 0)
- return -EALREADY;
-
memset(&ws, 0, sizeof(ws));
ws.ws_col = width;
ws.ws_row = height;
- master = posix_openpt(O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK);
- if (master < 0) {
- log_err("cannot open master: %m");
- return -errno;
- }
-
log_debug("forking child");
pid = fork();
switch (pid) {
case -1:
log_err("cannot fork: %m");
- ret = -errno;
- goto err_master;
+ return -errno;
case 0:
- ret = setup_child(master, &ws);
- if (ret)
- goto err_master;
+ setup_child(master, &ws);
exec_child(pty->fd);
- abort();
+ exit(EXIT_FAILURE);
default:
pty->fd = master;
+ pty->child = pid;
break;
}
return 0;
-
-err_master:
- close(master);
- return ret;
}
static int send_buf(struct kmscon_pty *pty)
@@ -275,15 +295,11 @@ static void pty_input(struct ev_fd *fd, int mask, void *data)
ssize_t len;
struct kmscon_pty *pty = data;
- if (!pty || pty->fd < 0)
- return;
-
- if (mask & (EV_ERR | EV_HUP)) {
- if (mask & EV_ERR)
- log_warn("error on child pty socket");
- else
- log_debug("child closed remote end");
-
+ if (mask & EV_ERR) {
+ log_warn("error on child pty socket");
+ goto err;
+ } else if (mask & EV_HUP) {
+ log_debug("child closed remote end");
goto err;
}
@@ -310,54 +326,80 @@ static void pty_input(struct ev_fd *fd, int mask, void *data)
return;
err:
- ev_eloop_rm_fd(pty->efd);
- pty->efd = NULL;
- if (pty->input_cb)
- pty->input_cb(pty, NULL, 0, pty->data);
+ pty_close(pty, false);
+}
+
+static void sig_child(struct ev_eloop *eloop, struct signalfd_siginfo *info,
+ void *data)
+{
+ struct kmscon_pty *pty = data;
+
+ if (info->ssi_pid != pty->child)
+ return;
+
+ log_info("child exited: pid: %u status: %d utime: %llu stime: %llu",
+ info->ssi_pid, info->ssi_status,
+ info->ssi_utime, info->ssi_stime);
+
+ pty_close(pty, false);
}
int kmscon_pty_open(struct kmscon_pty *pty, unsigned short width,
unsigned short height)
{
int ret;
+ int master;
if (!pty)
return -EINVAL;
- if (pty->fd >= 0)
+ if (pty_is_open(pty))
return -EALREADY;
- ret = pty_spawn(pty, width, height);
- if (ret)
- return ret;
+ master = posix_openpt(O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK);
+ if (master < 0) {
+ log_err("cannot open master: %m");
+ return -errno;
+ }
- ret = ev_eloop_new_fd(pty->eloop, &pty->efd, pty->fd,
+ ret = ev_eloop_new_fd(pty->eloop, &pty->efd, master,
EV_READABLE, pty_input, pty);
- if (ret) {
- close(pty->fd);
- pty->fd = -1;
- return ret;
- }
+ if (ret)
+ goto err_master;
+
+ ret = ev_eloop_register_signal_cb(pty->eloop, SIGCHLD, sig_child, pty);
+ if (ret)
+ goto err_fd;
+
+ ret = pty_spawn(pty, master, width, height);
+ if (ret)
+ goto err_sig;
return 0;
+
+err_sig:
+ ev_eloop_unregister_signal_cb(pty->eloop, SIGCHLD, sig_child, pty);
+err_fd:
+ ev_eloop_rm_fd(pty->efd);
+ pty->efd = NULL;
+err_master:
+ close(master);
+ return ret;
}
void kmscon_pty_close(struct kmscon_pty *pty)
{
- if (!pty || pty->fd < 0)
+ if (!pty || !pty_is_open(pty))
return;
- ev_eloop_rm_fd(pty->efd);
- pty->efd = NULL;
- close(pty->fd);
- pty->fd = -1;
+ pty_close(pty, true);
}
int kmscon_pty_write(struct kmscon_pty *pty, const char *u8, size_t len)
{
int ret;
- if (!pty || pty->fd < 0 || !u8 || !len)
+ if (!pty || !pty_is_open(pty) || !u8 || !len)
return -EINVAL;
if (!kmscon_ring_is_empty(pty->msgbuf))
@@ -369,7 +411,7 @@ int kmscon_pty_write(struct kmscon_pty *pty, const char *u8, size_t len)
log_warn("cannot write to child process");
return ret;
}
- } else if (ret == len) {
+ } else if (ret >= len) {
return 0;
} else if (ret > 0) {
len -= ret;
@@ -381,18 +423,34 @@ int kmscon_pty_write(struct kmscon_pty *pty, const char *u8, size_t len)
buf:
ret = kmscon_ring_write(pty->msgbuf, u8, len);
if (ret)
- log_warn("cannot allocate buffer; dropping input");
+ log_warn("cannot allocate buffer; dropping output");
return 0;
}
+void kmscon_pty_signal(struct kmscon_pty *pty, int signum)
+{
+ int ret;
+
+ if (!pty || !pty_is_open(pty) || signum < 0)
+ return;
+
+ ret = ioctl(pty->fd, TIOCSIG, signum);
+ if (ret) {
+ log_warn("cannot send signal %d to child", signum);
+ return;
+ }
+
+ log_debug("send signal %d to child", signum);
+}
+
void kmscon_pty_resize(struct kmscon_pty *pty,
unsigned short width, unsigned short height)
{
int ret;
struct winsize ws;
- if (!pty || pty->fd < 0)
+ if (!pty || !pty_is_open(pty))
return;
memset(&ws, 0, sizeof(ws));
View
6 src/pty.h
@@ -60,11 +60,7 @@ int kmscon_pty_open(struct kmscon_pty *pty, unsigned short width,
void kmscon_pty_close(struct kmscon_pty *pty);
int kmscon_pty_write(struct kmscon_pty *pty, const char *u8, size_t len);
-
-/*
- * Call this whenever the size of the screen (rows or columns) changes. The
- * kernel and child process need to be notified.
- */
+void kmscon_pty_signal(struct kmscon_pty *pty, int signum);
void kmscon_pty_resize(struct kmscon_pty *pty,
unsigned short width, unsigned short height);
View
271 src/terminal.c
@@ -1,7 +1,7 @@
/*
* kmscon - Terminal
*
- * Copyright (c) 2011 David Herrmann <dh.herrmann@googlemail.com>
+ * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
* Copyright (c) 2011 University of Tuebingen
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -30,10 +30,13 @@
* runs a fully functional terminal emulation on it.
*/
+#define GL_GLEXT_PROTOTYPES
+
#include <errno.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
#include <stdlib.h>
#include <string.h>
-
#include "console.h"
#include "eloop.h"
#include "font.h"
@@ -46,8 +49,12 @@
#include "uterm.h"
#include "vte.h"
-struct term_out {
- struct term_out *next;
+#define LOG_SUBSYSTEM "terminal"
+
+struct screen {
+ struct screen *next;
+ struct screen *prev;
+ struct uterm_display *disp;
struct uterm_screen *screen;
};
@@ -55,9 +62,12 @@ struct kmscon_terminal {
unsigned long ref;
struct ev_eloop *eloop;
struct uterm_video *video;
+ struct kmscon_input *input;
struct gl_shader *shader;
+ bool opened;
- struct term_out *outputs;
+ struct screen *screens;
+ unsigned int max_width;
unsigned int max_height;
struct kmscon_console *console;
@@ -65,20 +75,20 @@ struct kmscon_terminal {
struct kmscon_vte *vte;
struct kmscon_pty *pty;
- kmscon_terminal_closed_cb closed_cb;
- void *closed_data;
+ kmscon_terminal_event_cb cb;
+ void *data;
};
static void draw_all(struct ev_idle *idle, void *data)
{
struct kmscon_terminal *term = data;
- struct term_out *iter;
+ struct screen *iter;
struct uterm_screen *screen;
int ret;
ev_eloop_rm_idle(idle);
- iter = term->outputs;
+ iter = term->screens;
for (; iter; iter = iter->next) {
screen = iter->screen;
@@ -87,6 +97,8 @@ static void draw_all(struct ev_idle *idle, void *data)
continue;
gl_viewport(screen);
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
kmscon_console_map(term->console, term->shader);
uterm_screen_swap(screen);
}
@@ -96,12 +108,96 @@ static void schedule_redraw(struct kmscon_terminal *term)
{
int ret;
- if (!term || !term->eloop)
- return;
-
ret = ev_eloop_add_idle(term->eloop, term->redraw, draw_all, term);
if (ret && ret != -EALREADY)
- log_warn("terminal: cannot schedule redraw\n");
+ log_warn("terminal: cannot schedule redraw");
+}
+
+static int add_display(struct kmscon_terminal *term, struct uterm_display *disp)
+{
+ struct screen *scr;
+ int ret;
+ unsigned int width, height;
+ bool resize;
+
+ scr = malloc(sizeof(*scr));
+ if (!scr)
+ return -ENOMEM;
+ memset(scr, 0, sizeof(*scr));
+ scr->disp = disp;
+
+ ret = uterm_screen_new_single(&scr->screen, disp);
+ if (ret) {
+ free(scr);
+ return ret;
+ }
+
+ scr->next = term->screens;
+ if (scr->next)
+ scr->next->prev = scr;
+ term->screens = scr;
+
+ resize = false;
+ width = uterm_screen_width(scr->screen);
+ height = uterm_screen_height(scr->screen);
+ if (term->max_width < width) {
+ term->max_width = width;
+ resize = true;
+ }
+ if (term->max_height < height) {
+ term->max_height = height;
+ resize = true;
+ }
+
+ if (resize)
+ kmscon_console_resize(term->console, 0, 0, term->max_height);
+
+ log_debug("added display %p to terminal %p", disp, term);
+ schedule_redraw(term);
+ uterm_display_ref(scr->disp);
+ return 0;
+}
+
+static void free_screen(struct screen *scr)
+{
+ uterm_screen_unref(scr->screen);
+ uterm_display_unref(scr->disp);
+ free(scr);
+}
+
+static void rm_display(struct kmscon_terminal *term, struct uterm_display *disp)
+{
+ struct screen *scr;
+
+ for (scr = term->screens; scr; scr = scr->next) {
+ if (scr->disp == disp) {
+ if (scr->prev)
+ scr->prev->next = scr->next;
+ if (scr->next)
+ scr->next->prev = scr->prev;
+ if (term->screens == scr)
+ term->screens = scr->next;
+ break;
+ }
+ }
+
+ if (!scr)
+ return;
+
+ log_debug("removed display %p from terminal %p", disp, term);
+ free_screen(scr);
+ if (!term->screens && term->cb)
+ term->cb(term, KMSCON_TERMINAL_NO_DISPLAY, term->data);
+}
+
+static void rm_all_screens(struct kmscon_terminal *term)
+{
+ struct screen *scr;
+
+ while ((scr = term->screens)) {
+ term->screens = scr->next;
+ free_screen(scr);
+ }
}
static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len,
@@ -110,28 +206,60 @@ static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len,
struct kmscon_terminal *term = data;
if (!len) {
- if (term->closed_cb)
- term->closed_cb(term, term->closed_data);
+ if (term->cb)
+ term->cb(term, KMSCON_TERMINAL_HUP, term->data);
} else {
kmscon_vte_input(term->vte, u8, len);
schedule_redraw(term);
}
}
+static void video_event(struct uterm_video *video,
+ struct uterm_video_hotplug *ev,
+ void *data)
+{
+ struct kmscon_terminal *term = data;
+
+ if (ev->action == UTERM_GONE)
+ rm_display(term, ev->display);
+}
+
+static void input_event(struct kmscon_input *input,
+ struct kmscon_input_event *ev,
+ void *data)
+{
+ struct kmscon_terminal *term = data;
+ int ret;
+ const char *u8;
+ size_t len;
+
+ if (!term->opened)
+ return;
+
+ ret = kmscon_vte_handle_keyboard(term->vte, ev, &u8, &len);
+ switch (ret) {
+ case KMSCON_VTE_SEND:
+ kmscon_pty_write(term->pty, u8, len);
+ break;
+ case KMSCON_VTE_DROP:
+ default:
+ break;
+ }
+}
+
int kmscon_terminal_new(struct kmscon_terminal **out,
struct ev_eloop *loop,
+ struct kmscon_symbol_table *st,
struct kmscon_font_factory *ff,
struct uterm_video *video,
- struct kmscon_symbol_table *st)
+ struct kmscon_input *input)
{
struct kmscon_terminal *term;
int ret;
- if (!out)
+ if (!out || !loop || !st || !ff || !video || !input)
return -EINVAL;
- log_debug("terminal: new terminal object\n");
-
term = malloc(sizeof(*term));
if (!term)
return -ENOMEM;
@@ -140,6 +268,7 @@ int kmscon_terminal_new(struct kmscon_terminal **out,
term->ref = 1;
term->eloop = loop;
term->video = video;
+ term->input = input;
ret = ev_idle_new(&term->redraw);
if (ret)
@@ -162,12 +291,26 @@ int kmscon_terminal_new(struct kmscon_terminal **out,
if (ret)
goto err_pty;
+ ret = uterm_video_register_cb(term->video, video_event, term);
+ if (ret)
+ goto err_shader;
+
+ ret = kmscon_input_register_cb(term->input, input_event, term);
+ if (ret)
+ goto err_video;
+
ev_eloop_ref(term->eloop);
uterm_video_ref(term->video);
+ kmscon_input_ref(term->input);
*out = term;
+ log_debug("new terminal object %p", term);
return 0;
+err_video:
+ uterm_video_unregister_cb(term->video, video_event, term);
+err_shader:
+ gl_shader_unref(term->shader);
err_pty:
kmscon_pty_unref(term->pty);
err_vte:
@@ -197,21 +340,25 @@ void kmscon_terminal_unref(struct kmscon_terminal *term)
if (--term->ref)
return;
+ log_debug("free terminal object %p", term);
kmscon_terminal_close(term);
- kmscon_terminal_rm_all_outputs(term);
+ rm_all_screens(term);
+ kmscon_input_unregister_cb(term->input, input_event, term);
+ uterm_video_unregister_cb(term->video, video_event, term);
gl_shader_unref(term->shader);
kmscon_pty_unref(term->pty);
kmscon_vte_unref(term->vte);
kmscon_console_unref(term->console);
+ ev_eloop_rm_idle(term->redraw);
ev_idle_unref(term->redraw);
+ kmscon_input_unref(term->input);
uterm_video_unref(term->video);
ev_eloop_unref(term->eloop);
free(term);
- log_debug("terminal: destroying terminal object\n");
}
int kmscon_terminal_open(struct kmscon_terminal *term,
- kmscon_terminal_closed_cb closed_cb, void *data)
+ kmscon_terminal_event_cb cb, void *data)
{
int ret;
unsigned short width, height;
@@ -225,8 +372,9 @@ int kmscon_terminal_open(struct kmscon_terminal *term,
if (ret)
return ret;
- term->closed_cb = closed_cb;
- term->closed_data = data;
+ term->opened = true;
+ term->cb = cb;
+ term->data = data;
return 0;
}
@@ -236,81 +384,16 @@ void kmscon_terminal_close(struct kmscon_terminal *term)
return;
kmscon_pty_close(term->pty);
- term->closed_data = NULL;
- term->closed_cb = NULL;
+ term->data = NULL;
+ term->cb = NULL;
+ term->opened = false;
}
-int kmscon_terminal_add_output(struct kmscon_terminal *term,
+int kmscon_terminal_add_display(struct kmscon_terminal *term,
struct uterm_display *disp)
{
- struct term_out *out;
- unsigned int height;
- int ret;
-
if (!term || !disp)
return -EINVAL;
- out = malloc(sizeof(*out));
- if (!out)
- return -ENOMEM;
-
- memset(out, 0, sizeof(*out));
- ret = uterm_screen_new_single(&out->screen, disp);
- if (ret) {
- free(out);
- return ret;
- }
-
- out->next = term->outputs;
- term->outputs = out;
-
- height = uterm_screen_height(out->screen);
- if (term->max_height < height) {
- term->max_height = height;
- kmscon_console_resize(term->console, 0, 0, term->max_height);
- }
-
- schedule_redraw(term);
-
- return 0;
-}
-
-void kmscon_terminal_rm_all_outputs(struct kmscon_terminal *term)
-{
- struct term_out *tmp;
-
- if (!term)
- return;
-
- while (term->outputs) {
- tmp = term->outputs;
- term->outputs = tmp->next;
- uterm_screen_unref(tmp->screen);
- free(tmp);
- }
-}
-
-int kmscon_terminal_input(struct kmscon_terminal *term,
- const struct kmscon_input_event *ev)
-{
- int ret;
- const char *u8;
- size_t len;
-
- if (!term || !ev)
- return -EINVAL;
-
- ret = kmscon_vte_handle_keyboard(term->vte, ev, &u8, &len);
- switch (ret) {
- case KMSCON_VTE_SEND:
- ret = kmscon_pty_write(term->pty, u8, len);
- if (ret)
- return ret;
- break;
- case KMSCON_VTE_DROP:
- default:
- break;
- }
-
- return 0;
+ return add_display(term, disp);
}
View
25 src/terminal.h
@@ -1,7 +1,7 @@
/*
* kmscon - Terminal
*
- * Copyright (c) 2011 David Herrmann <dh.herrmann@googlemail.com>
+ * Copyright (c) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
* Copyright (c) 2011 University of Tuebingen
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -38,31 +38,36 @@
#include "eloop.h"
#include "font.h"
#include "gl.h"
+#include "input.h"
#include "unicode.h"
#include "uterm.h"
struct kmscon_terminal;
-typedef void (*kmscon_terminal_closed_cb) (struct kmscon_terminal *term,
- void *data);
+enum kmscon_terminal_etype {
+ KMSCON_TERMINAL_HUP, /* child closed */
+ KMSCON_TERMINAL_NO_DISPLAY, /* no more display connected */
+};
+
+typedef void (*kmscon_terminal_event_cb)
+ (struct kmscon_terminal *term,
+ enum kmscon_terminal_etype type,
+ void *data);
int kmscon_terminal_new(struct kmscon_terminal **out,
struct ev_eloop *loop,
+ struct kmscon_symbol_table *st,
struct kmscon_font_factory *ff,
struct uterm_video *video,
- struct kmscon_symbol_table *st);
+ struct kmscon_input *input);
void kmscon_terminal_ref(struct kmscon_terminal *term);
void kmscon_terminal_unref(struct kmscon_terminal *term);
int kmscon_terminal_open(struct kmscon_terminal *term,
- kmscon_terminal_closed_cb closed_cb, void *data);
+ kmscon_terminal_event_cb event_cb, void *data);
void kmscon_terminal_close(struct kmscon_terminal *term);
-int kmscon_terminal_add_output(struct kmscon_terminal *term,
+int kmscon_terminal_add_display(struct kmscon_terminal *term,
struct uterm_display *disp);
-void kmscon_terminal_rm_all_outputs(struct kmscon_terminal *term);
-
-int kmscon_terminal_input(struct kmscon_terminal *term,
- const struct kmscon_input_event *ev);
#endif /* KMSCON_TERMINAL_H */
View
36 src/ui.c
@@ -57,19 +57,18 @@ static void video_event(struct uterm_video *video,
void *data)
{
struct kmscon_ui *ui = data;
- struct uterm_display *iter;
int ret;
- kmscon_terminal_rm_all_outputs(ui->term);
- iter = uterm_video_get_displays(ui->video);
- for ( ; iter; iter = uterm_display_next(iter)) {
- if (uterm_display_get_state(iter) == UTERM_DISPLAY_INACTIVE) {
- ret = uterm_display_activate(iter, NULL);
+ if (ev->action == UTERM_NEW) {
+ if (uterm_display_get_state(ev->display) == UTERM_DISPLAY_INACTIVE) {
+ ret = uterm_display_activate(ev->display, NULL);
if (ret)
- continue;
+ return;
+ ret = uterm_display_set_dpms(ev->display, UTERM_DPMS_ON);
+ if (ret)
+ return;
}
-
- kmscon_terminal_add_output(ui->term, iter);
+ kmscon_terminal_add_display(ui->term, ev->display);
}
}
@@ -77,14 +76,6 @@ static void input_event(struct kmscon_input *input,
struct kmscon_input_event *ev,
void *data)
{
- struct kmscon_ui *ui = data;
- int ret;
-
- ret = kmscon_terminal_input(ui->term, ev);
- if (ret) {
- kmscon_terminal_close(ui->term);
- ev_eloop_exit(ui->eloop);
- }
}
int kmscon_ui_new(struct kmscon_ui **out,
@@ -114,7 +105,8 @@ int kmscon_ui_new(struct kmscon_ui **out,
if (ret)
goto err_st;
- ret = kmscon_terminal_new(&ui->term, eloop, ui->ff, ui->video, ui->st);
+ ret = kmscon_terminal_new(&ui->term, eloop, ui->st, ui->ff, ui->video,
+ ui->input);
if (ret)
goto err_ff;
@@ -137,9 +129,9 @@ int kmscon_ui_new(struct kmscon_ui **out,
return 0;
err_input:
- kmscon_input_unregister_cb(ui->input, input_event);
+ kmscon_input_unregister_cb(ui->input, input_event, ui);
err_video:
- uterm_video_unregister_cb(ui->video, video_event);
+ uterm_video_unregister_cb(ui->video, video_event, ui);
err_term:
kmscon_terminal_unref(ui->term);
err_ff:
@@ -156,8 +148,8 @@ void kmscon_ui_free(struct kmscon_ui *ui)
if (!ui)
return;
- kmscon_input_unregister_cb(ui->input, input_event);
- uterm_video_unregister_cb(ui->video, video_event);
+ kmscon_input_unregister_cb(ui->input, input_event, ui);
+ uterm_video_unregister_cb(ui->video, video_event, ui);
kmscon_terminal_unref(ui->term);
kmscon_font_factory_unref(ui->ff);
kmscon_symbol_table_unref(ui->st);
View
3  src/uterm.h
@@ -186,7 +186,8 @@ void uterm_video_segfault(struct uterm_video *video);
struct uterm_display *uterm_video_get_displays(struct uterm_video *video);
int uterm_video_register_cb(struct uterm_video *video, uterm_video_cb cb,
void *data);
-void uterm_video_unregister_cb(struct uterm_video *video, uterm_video_cb cb);
+void uterm_video_unregister_cb(struct uterm_video *video, uterm_video_cb cb,
+ void *data);
void uterm_video_sleep(struct uterm_video *video);
int uterm_video_wake_up(struct uterm_video *video);
View
5 src/uterm_video.c
@@ -535,12 +535,13 @@ int uterm_video_register_cb(struct uterm_video *video, uterm_video_cb cb,
return kmscon_hook_add_cast(video->hook, cb, data);
}
-void uterm_video_unregister_cb(struct uterm_video *video, uterm_video_cb cb)
+void uterm_video_unregister_cb(struct uterm_video *video, uterm_video_cb cb,
+ void *data)
{
if (!video || !cb)
return;
- kmscon_hook_rm_cast(video->hook, cb);
+ kmscon_hook_rm_cast(video->hook, cb, data);
}
void uterm_video_sleep(struct uterm_video *video)
View
30 src/vt.c
@@ -66,6 +66,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/signalfd.h>
#include <termios.h>
#include <unistd.h>
#include "eloop.h"
@@ -84,8 +85,7 @@ struct kmscon_vt {
kmscon_vt_cb cb;
void *data;
- struct ev_signal *sig1;
- struct ev_signal *sig2;
+ struct ev_eloop *eloop;
struct ev_fd *efd;
};
@@ -131,7 +131,8 @@ void kmscon_vt_unref(struct kmscon_vt *vt)
free(vt);
}
-static void vt_enter(struct ev_signal *sig, int signum, void *data)
+static void vt_enter(struct ev_eloop *eloop, struct signalfd_siginfo *info,
+ void *data)
{
struct kmscon_vt *vt = data;
@@ -149,7 +150,8 @@ static void vt_enter(struct ev_signal *sig, int signum, void *data)
vt->cb(vt, KMSCON_VT_ENTER, vt->data);
}
-static void vt_leave(struct ev_signal *sig, int signum, void *data)
+static void vt_leave(struct ev_eloop *eloop, struct signalfd_siginfo *info,
+ void *data)
{
struct kmscon_vt *vt = data;
@@ -185,11 +187,11 @@ static int connect_eloop(struct kmscon_vt *vt, struct ev_eloop *eloop)
if (!vt || !eloop || vt->fd < 0)
return -EINVAL;
- ret = ev_eloop_new_signal(eloop, &vt->sig1, SIGUSR1, vt_leave, vt);
+ ret = ev_eloop_register_signal_cb(eloop, SIGUSR1, vt_leave, vt);
if (ret)
return ret;
- ret = ev_eloop_new_signal(eloop, &vt->sig2, SIGUSR2, vt_enter, vt);
+ ret = ev_eloop_register_signal_cb(eloop, SIGUSR2, vt_enter, vt);
if (ret)
goto err_sig1;
@@ -198,14 +200,14 @@ static int connect_eloop(struct kmscon_vt *vt, struct ev_eloop *eloop)
if (ret)
goto err_sig2;
+ vt->eloop = eloop;
+ ev_eloop_ref(vt->eloop);
return 0;
err_sig2:
- ev_eloop_rm_signal(vt->sig2);
- vt->sig2 = NULL;
+ ev_eloop_unregister_signal_cb(vt->eloop, SIGUSR2, vt_enter, vt);
err_sig1:
- ev_eloop_rm_signal(vt->sig1);
- vt->sig1 = NULL;
+ ev_eloop_unregister_signal_cb(vt->eloop, SIGUSR1, vt_leave, vt);
return ret;
}
@@ -214,12 +216,12 @@ static void disconnect_eloop(struct kmscon_vt *vt)
if (!vt)
return;
- ev_eloop_rm_signal(vt->sig1);
- ev_eloop_rm_signal(vt->sig2);
ev_eloop_rm_fd(vt->efd);
- vt->sig1 = NULL;
- vt->sig2 = NULL;
+ ev_eloop_unregister_signal_cb(vt->eloop, SIGUSR2, vt_enter, vt);
+ ev_eloop_unregister_signal_cb(vt->eloop, SIGUSR1, vt_leave, vt);
+ ev_eloop_unref(vt->eloop);
vt->efd = NULL;
+ vt->eloop = NULL;
}
static int open_tty(int id, int *tty_fd, int *tty_num)

No commit comments for this range

Something went wrong with that request. Please try again.