aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--T.c228
-rw-r--r--T.h43
-rw-r--r--Tc.c100
-rw-r--r--Td.c142
5 files changed, 227 insertions, 306 deletions
diff --git a/Makefile b/Makefile
index 0d438bf..c613482 100644
--- a/Makefile
+++ b/Makefile
@@ -8,37 +8,31 @@ LDFLAGS = -s ${LIBS}
VER = 0.9
CC = cc
-SRC = T.c Tc.c Td.c
+SRC = T.c
OBJ = ${SRC:.c=.o}
-all: Tc Td
+all: T
%.o: %.c
@echo CC $<
@${CC} -c ${CFLAGS} -o $@ $<
-${OBJ}: config.h T.h
+${OBJ}: config.h
-Tc: T.o Tc.o
- @echo CC -o $@
- @${CC} -o $@ $^ ${LDFLAGS}
-
-Td: T.o Td.o
+T: T.o
@echo CC -o $@
@${CC} -o $@ $^ ${LDFLAGS}
clean:
@echo cleaning
- @rm -f Tc Td ${OBJ}
+ @rm -f T ${OBJ}
install: all
@echo installing executable files in ${DESTDIR}${PREFIX}/bin
- @install -D -m755 Tc ${DESTDIR}${PREFIX}/bin/Tc
- @install -D -m755 Td ${DESTDIR}${PREFIX}/bin/Td
+ @install -D -m755 T ${DESTDIR}${PREFIX}/bin/T
uninstall:
@echo removing executable files from ${DESTDIR}${PREFIX}/bin
- @rm -f ${DESTDIR}${PREFIX}/bin/Tc
- @rm -f ${DESTDIR}${PREFIX}/bin/Td
+ @rm -f ${DESTDIR}${PREFIX}/bin/T
.PHONY: all clean install uninstall
diff --git a/T.c b/T.c
index dc62c3d..a531b82 100644
--- a/T.c
+++ b/T.c
@@ -17,28 +17,71 @@
* T. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <glib.h>
#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#include <unistd.h>
#include <vte/vte.h>
+
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#define PROGRAM_NAME "T"
+
+#define SOCKPATH CONFIG_SOCKDIR "/" CONFIG_SOCKNAME
+#define SOCKPATH_MAXLEN sizeof((SOCKPATH))
+
+#define MSGBUF_MAXLEN 64
+
+#define ARG_DAEMON "-d"
+#define ARG_NEWWIN "-n"
+#define ARG_EXIT "-x"
-#include "T.h"
+typedef enum {
+ MSG_NEWWIN,
+ MSG_EXIT,
+ MSG_OK,
+ MSG_ERROR
+} TMessage;
static int window_count = 0;
-/* Event callbacks */
+/* UI event callbacks */
static void window_destroy_callback(GtkWidget *widget, gpointer data);
static gboolean key_press_callback(GtkWidget *widget, GdkEvent *event, gpointer data);
static void terminal_child_exited_callback(VteTerminal *terminal, gpointer data);
static void terminal_window_title_changed_callback(VteTerminal *terminal, gpointer data);
-/* Helper functions */
+/* UI helper functions */
static void change_font_size(VteTerminal *terminal, int delta);
static void set_preferences(VteTerminal *terminal);
static void setup_terminal(GtkWindow *window, VteTerminal *terminal);
+/* (local) Networking & utility functions */
+static int num_open_windows();
+static void new_window();
+static void wrn(const char *message);
+static void err(const char *message, int ecode);
+static int conn_socket();
+static int bind_socket();
+static void cleanup_socket(int sock_fd);
+static TMessage handle_message(TMessage msg);
+static gboolean socket_g_io_watch(GIOChannel *source, GIOCondition condition, gpointer data);
+static int send_message(TMessage msg);
+static int run_daemon();
+static void usage();
+
static void
window_destroy_callback(GtkWidget *widget, gpointer data)
{
@@ -193,13 +236,13 @@ setup_terminal(GtkWindow *window, VteTerminal *terminal)
set_preferences(terminal);
}
-int
+static int
num_open_windows()
{
return window_count;
}
-void
+static void
new_window()
{
GtkWindow *window = (GtkWindow *) gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -227,15 +270,184 @@ new_window()
window_count++;
}
-void
+static void
wrn(const char *message)
{
fprintf(stderr, "%s: %s\n", PROGRAM_NAME, message);
}
-void
+static void
err(const char *message, int ecode)
{
wrn(message);
exit(ecode);
}
+
+static int
+conn_socket()
+{
+ struct sockaddr_un sock_addr;
+
+ int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock_fd < 0)
+ err("Failed to create socket", EXIT_FAILURE);
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.sun_family = AF_UNIX;
+ strncpy(sock_addr.sun_path, SOCKPATH, sizeof(sock_addr.sun_path) - 1);
+
+ if (connect(sock_fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0)
+ err("Failed to connect to daemon", EXIT_FAILURE);
+
+ return sock_fd;
+}
+
+static int
+bind_socket()
+{
+ struct sockaddr_un sock_addr;
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.sun_family = AF_UNIX;
+ strncpy(sock_addr.sun_path, SOCKPATH, sizeof(sock_addr.sun_path) - 1);
+
+ /* Remove old socket */
+ if (!access(sock_addr.sun_path, F_OK) && unlink(sock_addr.sun_path) < 0)
+ err("Failed to remove socket file at " SOCKPATH, EXIT_FAILURE);
+ if (!access(CONFIG_SOCKDIR, F_OK) && rmdir(CONFIG_SOCKDIR) < 0)
+ err("Failed to remove socket directory at " CONFIG_SOCKDIR, EXIT_FAILURE);
+
+ /* Create a new directory */
+ if (mkdir(CONFIG_SOCKDIR, S_IRWXU) < 0)
+ err("Failed to create socket directory at " CONFIG_SOCKDIR, EXIT_FAILURE);
+
+ int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock_fd < 0)
+ err("Failed to create socket", EXIT_FAILURE);
+
+ if (bind(sock_fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0)
+ err("Failed to bind the socket to the file at " SOCKPATH, EXIT_FAILURE);
+
+ return sock_fd;
+}
+
+static void
+cleanup_socket(int sock_fd)
+{
+ if (close(sock_fd) < 0)
+ err("Failed to close socket", EXIT_FAILURE);
+
+ if (unlink(SOCKPATH) < 0)
+ err("Failed to remove socket file at " SOCKPATH, EXIT_FAILURE);
+ if (rmdir(CONFIG_SOCKDIR) < 0)
+ err("Failed to remove socket directory at " CONFIG_SOCKDIR, EXIT_FAILURE);
+}
+
+static TMessage
+handle_message(TMessage msg)
+{
+ switch (msg) {
+ case MSG_NEWWIN:
+ new_window();
+ return MSG_OK;
+
+ case MSG_EXIT:
+ if (num_open_windows() == 0) {
+ gtk_main_quit();
+ return MSG_OK;
+ }
+ return MSG_ERROR;
+
+ default:
+ return MSG_ERROR;
+ }
+}
+
+static gboolean
+socket_g_io_watch(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ int sock_fd = g_io_channel_unix_get_fd(source);
+ int client_fd = accept(sock_fd, NULL, NULL);
+ if (client_fd < 0) {
+ wrn("accept() failed");
+ return TRUE;
+ }
+
+ TMessage msg;
+ int len = recv(client_fd, &msg, sizeof(msg), 0);
+ if (len < 0) {
+ wrn("recv() failed");
+ goto socket_g_io_watch_cleanup;
+ }
+
+ msg = handle_message(msg);
+ write(client_fd, &msg, sizeof(msg));
+
+socket_g_io_watch_cleanup:
+ close(client_fd);
+ return TRUE;
+}
+
+static void
+usage()
+{
+ puts("usage:");
+ puts("\t" PROGRAM_NAME " [ARG]");
+ puts("\nwhere ARG is one of:");
+ puts("\t" ARG_NEWWIN "\tRequests a new window; default if ommited");
+ puts("\t" ARG_EXIT "\tRequests daemon termination; only successful if there are no open windows");
+ puts("\t" ARG_DAEMON "\tRun in daemon mode");
+}
+
+static int
+send_message(TMessage msg)
+{
+ int sock_fd = conn_socket();
+ if (write(sock_fd, &msg, sizeof(msg)) < 0)
+ err("Failed to send data", EXIT_FAILURE);
+ if (recv(sock_fd, &msg, sizeof(msg), 0) < 0)
+ err("Failed to recv data", EXIT_FAILURE);
+ close(sock_fd);
+
+ return msg == MSG_OK ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static int
+run_daemon(int *argc, char ***argv)
+{
+ int sock_fd;
+ gtk_init(argc, argv);
+
+ sock_fd = bind_socket();
+ if (listen(sock_fd, SOMAXCONN) < 0)
+ err("Failed to listen to socket", EXIT_SUCCESS);
+
+ /* poll the socket in the GTK+ main loop */
+ GIOChannel *sock_chan = g_io_channel_unix_new(sock_fd);
+ g_io_add_watch(sock_chan, G_IO_IN, socket_g_io_watch, NULL);
+
+ gtk_main();
+
+ /* clean up */
+ cleanup_socket(sock_fd);
+ g_io_channel_unref(sock_chan);
+
+ return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc > 2) /* More than 1 arg means derp */
+ usage();
+ if (argc == 1 || strcmp(argv[1], ARG_NEWWIN) == 0)
+ return send_message(MSG_NEWWIN);
+ else if (strcmp(argv[1], ARG_EXIT) == 0)
+ return send_message(MSG_EXIT);
+ else if (strcmp(argv[1], ARG_DAEMON) == 0)
+ return run_daemon(&argc, &argv);
+ else /* derp */
+ usage();
+
+ return EXIT_FAILURE;
+}
diff --git a/T.h b/T.h
deleted file mode 100644
index a891982..0000000
--- a/T.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * T.h
- * Common definitions and utilities.
- *
- * This file is part of T.
- *
- * T 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.
- *
- * T 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
- * T. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef T_H
-#define T_H
-
-#include "config.h"
-
-#define PROGRAM_NAME "T"
-
-#define SOCKPATH CONFIG_SOCKDIR "/" CONFIG_SOCKNAME
-#define SOCKPATH_MAXLEN sizeof((SOCKPATH))
-
-typedef enum {
- MSG_NEWWIN,
- MSG_EXIT,
- MSG_OK,
- MSG_ERROR
-} TMessage;
-
-int num_open_windows();
-void new_window();
-
-void wrn(const char *message);
-void err(const char *message, int ecode);
-
-#endif /* T_H */
diff --git a/Tc.c b/Tc.c
deleted file mode 100644
index f54a2a2..0000000
--- a/Tc.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Tc.c
- * T client. Merely issues commands to the T daemon.
- *
- * T is a lean Terminal emulator.
- *
- * This file is part of T.
- *
- * T 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.
- *
- * T 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
- * T. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "T.h"
-
-#define ARG_NEWWIN "-n"
-#define ARG_EXIT "-x"
-
-static int open_conn();
-static TMessage parse_args(int argc, char *argv[]);
-static void usage();
-
-static int
-open_conn()
-{
- struct sockaddr_un sock_addr;
-
- int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock_fd < 0)
- err("Failed to create socket", EXIT_FAILURE);
-
- memset(&sock_addr, 0, sizeof(sock_addr));
- sock_addr.sun_family = AF_UNIX;
- strncpy(sock_addr.sun_path, SOCKPATH, sizeof(sock_addr.sun_path) - 1);
-
- if (connect(sock_fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0)
- err("Failed to connect to daemon", EXIT_FAILURE);
-
- return sock_fd;
-}
-
-static TMessage
-parse_args(int argc, char *argv[])
-{
- if (argc == 1) /* No args means new window */
- return MSG_NEWWIN;
- if (argc > 2) /* More than 1 arg means derp */
- return MSG_ERROR;
- if (strcmp(argv[1], ARG_NEWWIN) == 0)
- return MSG_NEWWIN;
- if (strcmp(argv[1], ARG_EXIT) == 0)
- return MSG_EXIT;
-
- return MSG_ERROR;
-}
-
-static void
-usage()
-{
- puts("usage:");
- puts("\tTc [ARG]");
- puts("\nwhere ARG is one of:");
- puts("\t" ARG_NEWWIN "\tRequests a new window; default if ommited");
- puts("\t" ARG_EXIT "\tRequests daemon termination; only successful if there are no open windows");
-}
-
-int
-main(int argc, char *argv[])
-{
- TMessage msg = parse_args(argc, argv);
- if (msg == MSG_ERROR) {
- usage();
- return EXIT_FAILURE;
- }
-
- int sock_fd = open_conn();
- if (write(sock_fd, &msg, sizeof(msg)) < 0)
- err("Failed to send data", EXIT_FAILURE);
- if (recv(sock_fd, &msg, sizeof(msg), 0) < 0)
- err("Failed to recv data", EXIT_FAILURE);
- close(sock_fd);
-
- return msg == MSG_OK ? EXIT_SUCCESS : EXIT_FAILURE;
-}
diff --git a/Td.c b/Td.c
deleted file mode 100644
index 22a847b..0000000
--- a/Td.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Td.c
- * T daemon. Saves resources by uniting all T windows under the same process.
- *
- * This file is part of T.
- *
- * T 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.
- *
- * T 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
- * T. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-#include <vte/vte.h>
-
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "T.h"
-
-#define MSGBUF_MAXLEN 64
-
-static int bind_socket();
-static TMessage handle_message(TMessage msg);
-static gboolean socket_g_io_watch(GIOChannel *source, GIOCondition condition, gpointer data);
-
-static int
-bind_socket()
-{
- struct sockaddr_un sock_addr;
-
- memset(&sock_addr, 0, sizeof(sock_addr));
- sock_addr.sun_family = AF_UNIX;
- strncpy(sock_addr.sun_path, SOCKPATH, sizeof(sock_addr.sun_path) - 1);
-
- /* Remove old socket */
- if (!access(sock_addr.sun_path, F_OK) && unlink(sock_addr.sun_path) < 0)
- err("Failed to remove socket file at " SOCKPATH, EXIT_FAILURE);
- if (!access(CONFIG_SOCKDIR, F_OK) && rmdir(CONFIG_SOCKDIR) < 0)
- err("Failed to remove socket directory at " CONFIG_SOCKDIR, EXIT_FAILURE);
-
- /* Create a new directory */
- if (mkdir(CONFIG_SOCKDIR, S_IRWXU) < 0)
- err("Failed to create socket directory at " CONFIG_SOCKDIR, EXIT_FAILURE);
-
- int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock_fd < 0)
- err("Failed to create socket", EXIT_FAILURE);
-
- if (bind(sock_fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0)
- err("Failed to bind the socket to the file at " SOCKPATH, EXIT_FAILURE);
-
- return sock_fd;
-}
-
-static TMessage
-handle_message(TMessage msg)
-{
- switch (msg) {
- case MSG_NEWWIN:
- new_window();
- return MSG_OK;
-
- case MSG_EXIT:
- if (num_open_windows() == 0) {
- gtk_main_quit();
- return MSG_OK;
- }
- return MSG_ERROR;
-
- default:
- return MSG_ERROR;
- }
-}
-
-static gboolean
-socket_g_io_watch(GIOChannel *source, GIOCondition condition, gpointer data)
-{
- int sock_fd = g_io_channel_unix_get_fd(source);
- int client_fd = accept(sock_fd, NULL, NULL);
- if (client_fd < 0) {
- wrn("accept() failed");
- return TRUE;
- }
-
- TMessage msg;
- int len = recv(client_fd, &msg, sizeof(msg), 0);
- if (len < 0) {
- wrn("recv() failed");
- goto socket_g_io_watch_cleanup;
- }
-
- msg = handle_message(msg);
- write(client_fd, &msg, sizeof(msg));
-
-socket_g_io_watch_cleanup:
- close(client_fd);
- return TRUE;
-}
-
-int
-main(int argc, char *argv[])
-{
- int sock_fd;
-
- gtk_init(&argc, &argv);
-
- sock_fd = bind_socket();
- if (listen(sock_fd, SOMAXCONN) < 0)
- err("Failed to listen to socket", EXIT_SUCCESS);
-
- /* poll the socket in the main loop */
- GIOChannel *sock_chan = g_io_channel_unix_new(sock_fd);
- g_io_add_watch(sock_chan, G_IO_IN, socket_g_io_watch, NULL);
-
- gtk_main();
-
- /* clean up */
- close(sock_fd);
- unlink(SOCKPATH);
-
- return EXIT_SUCCESS;
-}