From b4772eed539f6768e16f4463b5f6ce6949ef0794 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Tue, 17 Jul 2012 21:31:49 +0000 Subject: [PATCH] neercs: import files from the (unfinished) old neercs code. --- neercs/Makefile.am | 33 +- neercs/neercs.cpp | 9 +- neercs/neercs.h | 2 +- neercs/old/actions.c | 63 ++ neercs/old/ansi.c | 1149 +++++++++++++++++++++++++++++++ neercs/old/attach.c | 424 ++++++++++++ neercs/old/client.c | 298 ++++++++ neercs/old/configuration.c | 568 +++++++++++++++ neercs/old/effects.c | 278 ++++++++ neercs/old/grab.c | 393 +++++++++++ neercs/old/help.c | 76 ++ neercs/old/input.c | 192 ++++++ neercs/old/lock.c | 221 ++++++ neercs/old/main.c | 324 +++++++++ neercs/old/mini-client.c | 94 +++ neercs/old/mini-neercs.c | 52 ++ neercs/old/mini-neercs.h | 22 + neercs/old/mini-server.c | 80 +++ neercs/old/mini-socket.c | 297 ++++++++ neercs/old/mini-socket.h | 24 + neercs/old/mygetopt.c | 125 ++++ neercs/old/mygetopt.h | 30 + neercs/old/mytrace.c | 785 +++++++++++++++++++++ neercs/old/mytrace.h | 33 + neercs/old/neercs.h | 430 ++++++++++++ neercs/old/python/interpreter.c | 197 ++++++ neercs/old/python/py_module.c | 193 ++++++ neercs/old/python/py_module.h | 25 + neercs/old/recurrent.c | 112 +++ neercs/old/screen_list.c | 216 ++++++ neercs/old/screens.c | 334 +++++++++ neercs/old/screensaver.c | 187 +++++ neercs/old/server.c | 680 ++++++++++++++++++ neercs/old/term.c | 133 ++++ neercs/old/widgets.c | 176 +++++ neercs/old/widgets.h | 47 ++ neercs/old/wm.c | 513 ++++++++++++++ 37 files changed, 8811 insertions(+), 4 deletions(-) create mode 100644 neercs/old/actions.c create mode 100644 neercs/old/ansi.c create mode 100644 neercs/old/attach.c create mode 100644 neercs/old/client.c create mode 100644 neercs/old/configuration.c create mode 100644 neercs/old/effects.c create mode 100644 neercs/old/grab.c create mode 100644 neercs/old/help.c create mode 100644 neercs/old/input.c create mode 100644 neercs/old/lock.c create mode 100644 neercs/old/main.c create mode 100644 neercs/old/mini-client.c create mode 100644 neercs/old/mini-neercs.c create mode 100644 neercs/old/mini-neercs.h create mode 100644 neercs/old/mini-server.c create mode 100644 neercs/old/mini-socket.c create mode 100644 neercs/old/mini-socket.h create mode 100644 neercs/old/mygetopt.c create mode 100644 neercs/old/mygetopt.h create mode 100644 neercs/old/mytrace.c create mode 100644 neercs/old/mytrace.h create mode 100644 neercs/old/neercs.h create mode 100644 neercs/old/python/interpreter.c create mode 100644 neercs/old/python/py_module.c create mode 100644 neercs/old/python/py_module.h create mode 100644 neercs/old/recurrent.c create mode 100644 neercs/old/screen_list.c create mode 100644 neercs/old/screens.c create mode 100644 neercs/old/screensaver.c create mode 100644 neercs/old/server.c create mode 100644 neercs/old/term.c create mode 100644 neercs/old/widgets.c create mode 100644 neercs/old/widgets.h create mode 100644 neercs/old/wm.c diff --git a/neercs/Makefile.am b/neercs/Makefile.am index 3e33025..6324453 100644 --- a/neercs/Makefile.am +++ b/neercs/Makefile.am @@ -6,13 +6,15 @@ endif neercs_SOURCES = \ neercs.cpp neercs.h \ \ + $(old_sources) \ + \ video/render.cpp video/render.h \ video/text-render.cpp video/text-render.h \ video/simple.lolfx \ video/blurh.lolfx video/blurv.lolfx \ video/remanency.lolfx video/glow.lolfx video/postfx.lolfx video/radial.lolfx \ video/text.lolfx -neercs_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ @CACA_CFLAGS@ +neercs_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ @CACA_CFLAGS@ -Iold neercs_LDADD = neercs_LDFLAGS = $(top_builddir)/src/liblol.a \ @LOL_LIBS@ @PIPI_LIBS@ @CACA_LIBS@ @UTIL_LIBS@ @PAM_LIBS@ @@ -31,3 +33,32 @@ SUFFIXES = .lolfx .lolfx.o: $(LOLFX_BUILD) +old_sources = \ + old/actions.c \ + old/ansi.c \ + old/attach.c \ + old/client.c \ + old/configuration.c \ + old/effects.c \ + old/grab.c \ + old/help.c \ + old/input.c \ + old/lock.c \ + old/main.c \ + old/mygetopt.c \ + old/mygetopt.h \ + old/mytrace.c \ + old/mytrace.h \ + old/neercs.h \ + old/python/interpreter.c \ + old/python/py_module.c \ + old/python/py_module.h \ + old/recurrent.c \ + old/screen_list.c \ + old/screensaver.c \ + old/screens.c \ + old/server.c \ + old/term.c \ + old/widgets.c \ + old/widgets.h \ + old/wm.c diff --git a/neercs/neercs.cpp b/neercs/neercs.cpp index 415b5ff..70699f0 100644 --- a/neercs/neercs.cpp +++ b/neercs/neercs.cpp @@ -43,7 +43,12 @@ using namespace lol; #include "neercs.h" #include "video/render.h" -Neercs::Neercs() +extern "C" +{ +#include "old/neercs.h" +} + +Neercs::Neercs(int argc, char **argv) : m_ready(false), m_caca(caca_create_canvas(10, 10)), m_render(new Render(m_caca)), @@ -140,7 +145,7 @@ int main(int argc, char **argv) _chdir("../.."); #endif - new Neercs(); + new Neercs(argc, argv); new DebugFps(2, 2); app.ShowPointer(false); diff --git a/neercs/neercs.h b/neercs/neercs.h index cefe7da..caf008e 100644 --- a/neercs/neercs.h +++ b/neercs/neercs.h @@ -14,7 +14,7 @@ class Neercs : public WorldEntity { public: - Neercs(); + Neercs(int argc, char **argv); virtual ~Neercs(); char const *GetName() { return ""; } diff --git a/neercs/old/actions.c b/neercs/old/actions.c new file mode 100644 index 0000000..4a882c3 --- /dev/null +++ b/neercs/old/actions.c @@ -0,0 +1,63 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" +#include +#include +#include +#include +#include "neercs.h" + +void dump_to_file(struct screen_list *screen_list) +{ + char filename[14] = "hardcopy.0"; + int n = 0; + struct stat bufstat; + void * export; + size_t len, wrote; + FILE * out; + + /* FIXME maybe use glob and get next one directly */ + while (n<9999 && !stat(filename, &bufstat)) + { + n++; + sprintf(&filename[9], "%d", n); + } + if (n>=9999) + { + debug("Too many hardcopy files in current directory\n"); + return; + } + + export = caca_export_canvas_to_memory(screen_list->cv, "ansi", &len); + if (!export) + { + debug("Failed to export to ansi\n"); + return; + } + + out = fopen(filename, "w"); + if (!out) + { + debug("Failed to open output file %s: %s\n", filename, strerror(errno)); + return; + } + wrote = fwrite(export, len, 1, out); + if (!wrote) + { + debug("Failed to write to output file: %s\n", strerror(errno)); + return; + } + free(export); +} diff --git a/neercs/old/ansi.c b/neercs/old/ansi.c new file mode 100644 index 0000000..2689e22 --- /dev/null +++ b/neercs/old/ansi.c @@ -0,0 +1,1149 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include "config.h" +#include +#include +#include "neercs.h" + + +/* DEC ACS with common extensions */ +static uint32_t dec_acs(uint32_t uc) +{ + switch (uc) + { + case '+': + return 0x2192; /* RIGHTWARDS ARROW */ + case ',': + return 0x2190; /* LEFTWARDS ARROW */ + case '-': + return 0x2191; /* UPWARDS ARROW */ + case '.': + return 0x2193; /* DOWNWARDS ARROW */ + case '0': + return 0x25AE; /* BLACK VERTICAL RECTANGLE */ + case '_': + return 0x25AE; /* BLACK VERTICAL RECTANGLE */ + case '`': + return 0x25C6; /* BLACK DIAMOND */ + case 'a': + return 0x2592; /* MEDIUM SHADE */ + case 'b': + return 0x2409; /* SYMBOL FOR HORIZONTAL TABULATION */ + case 'c': + return 0x240C; /* SYMBOL FOR FORM FEED */ + case 'd': + return 0x240D; /* SYMBOL FOR CARRIAGE RETURN */ + case 'e': + return 0x240A; /* SYMBOL FOR LINE FEED */ + case 'f': + return 0x00B0; /* DEGREE SIGN */ + case 'g': + return 0x00B1; /* PLUS-MINUS SIGN */ + case 'h': + return 0x2424; /* SYMBOL FOR NEWLINE */ + case 'i': + return 0x240B; /* SYMBOL FOR VERTICAL TABULATION */ + case 'j': + return 0x2518; /* BOX DRAWINGS LIGHT UP AND LEFT */ + case 'k': + return 0x2510; /* BOX DRAWINGS LIGHT DOWN AND LEFT */ + case 'l': + return 0x250C; /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ + case 'm': + return 0x2514; /* BOX DRAWINGS LIGHT UP AND RIGHT */ + case 'n': + return 0x253C; /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + case 'o': + return 0x23BA; /* HORIZONTAL SCAN LINE-1 */ + case 'p': + return 0x23BB; /* HORIZONTAL SCAN LINE-3 */ + case 'q': + return 0x2500; /* BOX DRAWINGS LIGHT HORIZONTAL */ + case 'r': + return 0x23BC; /* HORIZONTAL SCAN LINE-7 */ + case 's': + return 0x23BD; /* HORIZONTAL SCAN LINE-9 */ + case 't': + return 0x251C; /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + case 'u': + return 0x2524; /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + case 'v': + return 0x2534; /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + case 'w': + return 0x252C; /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + case 'x': + return 0x2502; /* BOX DRAWINGS LIGHT VERTICAL */ + case 'y': + return 0x2264; /* LESS-THAN OR EQUAL TO */ + case 'z': + return 0x2265; /* GREATER-THAN OR EQUAL TO */ + case '{': + return 0x03C0; /* GREEK SMALL LETTER PI */ + case '|': + return 0x2260; /* NOT EQUAL TO */ + case '}': + return 0x00A3; /* POUND SIGN */ + case '~': + return 0x00B7; /* MIDDLE DOT */ + default: + return uc; + } +}; + +static void reset_conv_state(struct screen *); + +#define LITERAL2CHAR(i0,i1) (((i0) << 8) | (i1)) + +#define LITERAL3CHAR(i0,i1,i2) LITERAL2CHAR(LITERAL2CHAR(i0, i1), i2) + +static void ansi_parse_grcm(struct screen *, + unsigned int, unsigned int const *); + +inline int handle_single_char(unsigned char c, int *x, int *y, + struct screen_list *screen_list, + struct screen *sc); +inline int handle_duplet(unsigned char const *buffer, struct screen *sc, + unsigned int *skip, int top, int bottom, int width, + int height); + + +inline int handle_single_char(unsigned char c, int *x, int *y, + struct screen_list *screen_list, + struct screen *sc) +{ + if (c == '\r') + { + *x = 0; + } + + else if (c == '\n') + { + *x = 0; + *y = *y + 1; + } + else if (c == '\a') + { + if (!sc->bell) + screen_list->in_bell = 10; + sc->bell = 1; + } + + else if (c == '\t') + { + *x = (*x + 7) & ~7; + } + + else if (c == '\x08') + { + if (*x > 0) + *x = *x - 1; + } + else if (c == '\x0b') + { + /* Vertical tab */ + /* Not sure about the real meaning of it, just y++ for now */ + if (*y < caca_get_canvas_height(sc->cv)) + *y = *y + 1; + } + else if (c == '\x0e') + { + /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: invokes + the G1 character set. */ + sc->conv_state.glr[0] = 1; + } + + else if (c == '\x0f') + { + /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes the + G0 character set. */ + sc->conv_state.glr[0] = 0; + } + else + { + return 1; + } + return 0; +} + +inline int handle_duplet(unsigned char const *buffer, struct screen *sc, + unsigned int *skip, int top, int bottom, int width, + int height) +{ + int i = 0, j, k; + unsigned int dummy = 0; + + /* Single Shift Select of G2 Character Set (SS2: 0x8e): affects next + character only */ + if (buffer[i] == '\033' && buffer[i + 1] == 'N') + { + sc->conv_state.ss = 2; + *skip += 1; + } + /* Reverse Index (RI) go up one line, reverse scroll if necessary */ + else if (buffer[i] == '\033' && buffer[i + 1] == 'M') + { + /* FIXME : not sure about the meaning of 'go up one line' and 'if + necessary' words. Implemented as a scroller only. */ + for (j = bottom - 1; j > top; j--) + { + for (k = 0; k < width; k++) + { + caca_put_char(sc->cv, k, j, caca_get_char(sc->cv, k, j - 1)); + caca_put_attr(sc->cv, k, j, caca_get_attr(sc->cv, k, j - 1)); + } + } + caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' '); + *skip += 1; + } + + /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next + character only */ + else if (buffer[i] == '\033' && buffer[i + 1] == 'O') + { + sc->conv_state.ss = 3; + *skip += 1; + } + + /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */ + else if (buffer[i] == '\033' && buffer[i + 1] == 'n') + { + sc->conv_state.glr[0] = 2; + *skip += 1; + } + + /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */ + else if (buffer[i] == '\033' && buffer[i + 1] == 'o') + { + sc->conv_state.glr[0] = 3; + *skip += 1; + } + + /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */ + else if (buffer[i] == '\033' && buffer[i + 1] == 'c') + { + sc->dfg = CACA_DEFAULT; + sc->dbg = CACA_DEFAULT; + + caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg); + sc->clearattr = caca_get_attr(sc->cv, -1, -1); + ansi_parse_grcm(sc, 1, &dummy); + + reset_conv_state(sc); + *skip += 1; + } + + /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 (ISO + IR 189) */ + else if (buffer[i] == '\033' && buffer[i + 1] == 'd') + { + reset_conv_state(sc); + *skip += 1; + } + else + { + return 1; + } + + return 0; +} + + +long int import_term(struct screen_list *screen_list, struct screen *sc, + void const *data, unsigned int size) +{ + unsigned char const *buffer = (unsigned char const *)data; + unsigned int i, j, k, skip, dummy = 0; + unsigned int width, height, top, bottom; + uint32_t savedattr; + int x = 0, y = 0, save_x = 0, save_y = 0; + char b[100]; + + debug("ansi : import_term\n"); + + width = caca_get_canvas_width(sc->cv); + height = caca_get_canvas_height(sc->cv); + x = caca_get_cursor_x(sc->cv); + y = caca_get_cursor_y(sc->cv); + top = 1; + bottom = height; + + if (!sc->init) + { + sc->dfg = CACA_LIGHTGRAY; + sc->dbg = CACA_BLACK; + + caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg); + sc->clearattr = caca_get_attr(sc->cv, -1, -1); + + ansi_parse_grcm(sc, 1, &dummy); + + reset_conv_state(sc); + + sc->init = 1; + } + + for (i = 0; i < size; i += skip) + { + uint32_t ch = 0; + int wch = 0; + + skip = 1; + + /* Control codes (ASCII < \x20) */ + if (!handle_single_char(buffer[i], &x, &y, screen_list, sc)) + { + } + + /* If there are not enough characters to parse the escape sequence, + wait until the next try. We require 3. */ + + else if (buffer[i] == '\033' && i + 2 >= size) + break; + + + else if (!handle_duplet(&buffer[i], sc, &skip, + top, bottom, width, height)) + { + + } + + + /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form + from ISO 2022:1986] */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C')) + { + sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]); + skip += 2; + } + + /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish + these */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && (i + 3 >= size)) + break; + + /* GZD4 G0-Designator, 94 chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '(') + { + sc->conv_state.gn[0] = buffer[i + 2]; + skip += 2; + } + + /* G1D4 G1-Designator, 94 chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == ')') + { + sc->conv_state.gn[1] = buffer[i + 2]; + skip += 2; + } + + /* G2D4 G2-Designator, 94 chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '*') + { + sc->conv_state.gn[2] = buffer[i + 2]; + skip += 2; + } + + /* G3D4 G3-Designator, 94 chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '+') + { + sc->conv_state.gn[3] = buffer[i + 2]; + skip += 2; + } + + /* G2D6 G2-Designator, 96 chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '.') + { + sc->conv_state.gn[2] = LITERAL2CHAR('.', buffer[i + 2]); + skip += 2; + } + + /* G3D6 G3-Designator, 96 chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '/') + { + sc->conv_state.gn[3] = LITERAL2CHAR('.', buffer[i + 2]); + skip += 2; + } + + /* GZDM4 G0-Designator, 94^n chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && buffer[i + 2] == '(') + { + sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 3]); + skip += 3; + } + + /* G1DM4 G1-Designator, 94^n chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && buffer[i + 2] == ')') + { + sc->conv_state.gn[1] = LITERAL2CHAR('$', buffer[i + 3]); + skip += 3; + } + + /* G2DM4 G2-Designator, 94^n chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && buffer[i + 2] == '*') + { + sc->conv_state.gn[2] = LITERAL2CHAR('$', buffer[i + 3]); + skip += 3; + } + + /* G3DM4 G3-Designator, 94^n chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && buffer[i + 2] == '+') + { + sc->conv_state.gn[3] = LITERAL2CHAR('$', buffer[i + 3]); + skip += 3; + } + + /* G2DM6 G2-Designator, 96^n chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && buffer[i + 2] == '.') + { + sc->conv_state.gn[2] = LITERAL3CHAR('$', '.', buffer[i + 3]); + skip += 3; + } + + /* G3DM6 G3-Designator, 96^n chars */ + else if (buffer[i] == '\033' && buffer[i + 1] == '$' + && buffer[i + 2] == '/') + { + sc->conv_state.gn[3] = LITERAL3CHAR('$', '.', buffer[i + 3]); + skip += 3; + } + else if (buffer[i] == '\033' && buffer[i + 1] == '#') + { + debug("ansi private '#' sequence\n"); + + switch (buffer[i + 2]) + { + case '8': /* DECALN Fills the entire screen area with + uppercase Es for screen focus and + alignment. */ + for (j = 0; j < height; j++) + { + for (k = 0; k < width; k++) + { + caca_put_char(sc->cv, k, j, 'E'); + } + } + x = 0; + y = 0; + skip += 2; + break; + + default: + debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]); + continue; + } + + } + /* Interpret escape commands, as per Standard ECMA-48 "Control + Functions for Coded Character Sets", 5.4. Control sequences. */ + else if (buffer[i] == '\033' && buffer[i + 1] == '[') + { + unsigned int argc = 0, argv[101]; + unsigned int param, inter, junk, final; + + if (buffer[i + 2] == '?') + { + debug("CSI? %c%c%c%c%c\n", + buffer[i + 3], buffer[i + 4], buffer[i + 5], + buffer[i + 6], buffer[i + 7]); + } + + /* Compute offsets to parameter bytes, intermediate bytes and to + the final byte. Only the final byte is mandatory, there can be + zero of the others. 0 param=2 inter final final+1 + +-----+------------------+---------------------+-----------------+ + | CSI | parameter bytes | intermediate bytes | final byte | | | + 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>? + | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ | + +-----+------------------+---------------------+-----------------+ */ + param = 2; + + /* vttest use to interleave control characters (\014 CR or \010 + BS) into CSI sequences, either directly after ESC[ or after + param. Can't find anything related to this in any documentation + nor XTerm sources, thought. */ + + for (junk = param; i + junk < size; junk++) + if (buffer[i + junk] < 0x20) + { + handle_single_char(buffer[i + junk], &x, &y, screen_list, + sc); + } + else + { + break; + } + + /* Intermediate offset */ + for (inter = junk; i + inter < size; inter++) + if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f) + { + break; + } + /* Interleaved character */ + for (junk = inter; i + junk < size; junk++) + if (buffer[i + junk] < 0x20) + { + handle_single_char(buffer[i + junk], &x, &y, screen_list, + sc); + } + else + { + break; + } + + /* Final Byte offset */ + for (final = junk; i + final < size; final++) + if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f) + { + break; + } + if (i + final >= size + || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e) + { + debug("ansi Invalid Final Byte (%d %c)\n", buffer[i + final], + buffer[i + final]); + break; /* Invalid Final Byte */ + } + + skip += final; + + /* Sanity checks */ + if (param < inter && buffer[i + param] >= 0x3c) + { + /* Private sequence, only parse what we know */ + debug("ansi import: private sequence \"^[[%.*s\"", + final - param + 1, buffer + i + param); + /* FIXME better parsing */ + if (buffer[i + 2] == '?') + { + char arg[5]; + int a = 0; + int c, p; + for (p = 0; p < 4; p++) + { + if (buffer[i + 3 + p] >= '0' + && buffer[i + 3 + p] <= '9') + { + arg[a] = buffer[i + 3 + p]; + arg[a + 1] = 0; + a++; + debug("private a now '%s'\n", arg); + } + else + { + break; + } + } + char *end; + int Pm = strtol(arg, &end, 10); + + c = buffer[i + 3 + (end - arg)]; + + debug("ansi private mouse : command %c, arg %d", c, Pm); + if (c == 'h') /* DECSET DEC Private Mode Set */ + { + + switch (Pm) + { + /* FIXME Handle different modes */ + case 9: + debug("mouse : X10 mode\n"); + sc->report_mouse = MOUSE_X10; + break; + case 1000: /* Send Mouse X & Y on button press + and release. */ + debug("mouse : VT200 mode\n"); + sc->report_mouse = MOUSE_VT200; + break; + case 1001: /* Use Hilite Mouse Tracking. */ + debug("mouse : VT200_HIGHLIGHT mode\n"); + sc->report_mouse = MOUSE_VT200_HIGHLIGHT; + break; + case 1002: /* Use Cell Motion Mouse Tracking. */ + debug("mouse : BTN mode\n"); + sc->report_mouse = MOUSE_BTN_EVENT; + break; + case 1003: /* Use All Motion Mouse Tracking. */ + debug("mouse : ANY mode\n"); + sc->report_mouse = MOUSE_ANY_EVENT; + break; + default: + break; + } + } + else if (c == 'l') /* DECRST DEC Private Mode Reset */ + { + Pm = atoi(arg); + switch (Pm) + { + /* FIXME Handle different modes */ + case 9: + case 1000: /* Send Mouse X & Y on button press + and release. */ + case 1001: /* Use Hilite Mouse Tracking. */ + case 1002: /* Use Cell Motion Mouse Tracking. */ + case 1003: /* Use All Motion Mouse Tracking. */ + sc->report_mouse = MOUSE_NONE; + debug("ansi private mouse : NOT reporting mouse"); + break; + default: + break; + } + } + } + continue; /* Private sequence, skip it entirely */ + } + + if (final - param > 100) + continue; /* Suspiciously long sequence, skip it */ + + /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string + format */ + if (param < inter) + { + argv[0] = 0; + for (j = param; j < inter; j++) + { + if (buffer[i + j] == ';') + argv[++argc] = 0; + else if (buffer[i + j] >= '0' && buffer[i + j] <= '9') + argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0'); + } + argc++; + } + + /* Interpret final byte. The code representations are given in + ECMA-48 5.4: Control sequences, and the code definitions are + given in ECMA-48 8.3: Definition of control functions. */ + debug("ansi import: command '%c'", buffer[i + final]); + switch (buffer[i + final]) + { + case 'A': /* CUU (0x41) - Cursor Up */ + y -= argc ? argv[0] : 1; + if (y < 0) + y = 0; + break; + case 'B': /* CUD (0x42) - Cursor Down */ + y += argc ? argv[0] : 1; + break; + case 'C': /* CUF (0x43) - Cursor Right */ + x += argc ? argv[0] : 1; + break; + case 'D': /* CUB (0x44) - Cursor Left */ + x -= argc ? argv[0] : 1; + if (x < 0) + x = 0; + break; + case 'G': /* CHA (0x47) - Cursor Character Absolute */ + x = (argc && argv[0] > 0) ? argv[0] - 1 : 0; + break; + case 'H': /* CUP (0x48) - Cursor Position */ + x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; + y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; + debug("ansi CUP : Cursor at %dx%d\n", x, y); + break; + case 'J': /* ED (0x4a) - Erase In Page */ + savedattr = caca_get_attr(sc->cv, -1, -1); + caca_set_attr(sc->cv, sc->clearattr); + if (!argc || argv[0] == 0) + { + caca_draw_line(sc->cv, x, y, width, y, ' '); + caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' '); + } + else if (argv[0] == 1) + { + caca_fill_box(sc->cv, 0, 0, width, y, ' '); + caca_draw_line(sc->cv, 0, y, x, y, ' '); + } + else if (argv[0] == 2) + { + // x = y = 0; + caca_fill_box(sc->cv, 0, 0, width, height, ' '); + } + caca_set_attr(sc->cv, savedattr); + break; + case 'K': /* EL (0x4b) - Erase In Line */ + debug("ansi EL : cursor at %dx%d\n", x, y); + if (!argc || argv[0] == 0) + { + caca_draw_line(sc->cv, x, y, width, y, ' '); + } + else if (argv[0] == 1) + { + caca_draw_line(sc->cv, 0, y, x, y, ' '); + } + else if (argv[0] == 2) + { + caca_draw_line(sc->cv, 0, y, width, y, ' '); + } + break; + case 'L': /* IL - Insert line */ + { + unsigned int nb_lines = argc ? argv[0] : 1; + for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--) + { + for (k = 0; k < width; k++) + { + caca_put_char(sc->cv, k, j, + caca_get_char(sc->cv, k, + j - nb_lines)); + caca_put_attr(sc->cv, k, j, + caca_get_attr(sc->cv, k, + j - nb_lines)); + } + caca_draw_line(sc->cv, 0, j - nb_lines, width, + j - nb_lines, ' '); + } + } + break; + case 'P': /* DCH (0x50) - Delete Character */ + if (!argc || argv[0] == 0) + argv[0] = 1; /* echo -ne 'foobar\r\e[0P\n' */ + + for (j = x; (unsigned int)(j + argv[0]) < width; j++) + { + caca_put_char(sc->cv, j, y, + caca_get_char(sc->cv, j + argv[0], y)); + caca_put_attr(sc->cv, j, y, + caca_get_attr(sc->cv, j + argv[0], y)); + } + break; +#if 0 + savedattr = caca_get_attr(sc->cv, -1, -1); + caca_set_attr(sc->cv, sc->clearattr); + for (; (unsigned int)j < width; j++) + caca_put_char(sc->cv, j, y, ' '); + caca_set_attr(sc->cv, savedattr); +#endif + case 'X': /* ECH (0x58) - Erase Character */ + if (argc && argv[0]) + { + savedattr = caca_get_attr(sc->cv, -1, -1); + caca_set_attr(sc->cv, sc->clearattr); + caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' '); + caca_set_attr(sc->cv, savedattr); + } + case 'c': /* DA -- Device Attributes */ + /* + 0 Base VT100, no options 1 Processor options (STP) 2 + Advanced video option (AVO) 3 AVO and STP 4 Graphics + processor option (GPO) 5 GPO and STP 6 GPO and AVO 7 GPO, + STP, and AVO */ + /* Warning, argument is Pn */ + debug("ansi Got command c, argc %d, argv[0] (%d)\n", argc, + argv[0], argv[0]); + if (!argc || argv[0] == 0) + { + send_ansi_sequence(screen_list, "\x1b[?1;0c"); + } + else + { + switch (argv[0]) + { + case 1: + send_ansi_sequence(screen_list, "\x1b[?\x1;\x1c"); + break; + case 2: + send_ansi_sequence(screen_list, "\x1b[?\x1;\x2c"); + break; + case 3: + send_ansi_sequence(screen_list, "\x1b[?\x1;\x3c"); + break; + case 4: + send_ansi_sequence(screen_list, "\x1b[?\x1;\x4c"); + break; + case 5: + send_ansi_sequence(screen_list, "\x1b[?\x1;\x5c"); + break; + case 6: + send_ansi_sequence(screen_list, "\x1b[?\x1;\x6c"); + break; + case 7: + send_ansi_sequence(screen_list, "\x1b[?\x1;\x7c"); + break; + default: + debug("Unsupported DA option '%d'\n", argv[0]); + break; + } + } + break; + case 'd': /* VPA (0x64) - Line Position Absolute */ + y = (argc && argv[0] > 0) ? argv[0] - 1 : 0; + break; + case 'f': /* HVP (0x66) - Character And Line Position */ + x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; + y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; + break; + case 'g': /* TBC -- Tabulation Clear */ + break; + case 'r': /* FIXME */ + if (argc == 2) /* DCSTBM - Set top and bottom margin */ + { + debug("DCSTBM %d %d", argv[0], argv[1]); + top = argv[0]; + bottom = argv[1]; + } + else + debug("ansi import: command r with %d params", argc); + break; + case 'h': /* SM (0x68) - FIXME */ + debug("ansi import: set mode %i", argc ? (int)argv[0] : -1); + break; + case 'l': /* RM (0x6c) - FIXME */ + debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1); + break; + case 'm': /* SGR (0x6d) - Select Graphic Rendition */ + if (argc) + ansi_parse_grcm(sc, argc, argv); + else + ansi_parse_grcm(sc, 1, &dummy); + break; + case 'n': + debug("ansi command n, argc %d, argv[0] %d\n", argc, argv[0]); + if (!argc) + break; + + switch (argv[0]) + { + case 5: + /* Term ok */ + send_ansi_sequence(screen_list, "\x1b[0n"); + break; + case 6: + /* Cursor Position */ + sprintf(b, "\x1b[%d;%dR", y + 1, x + 1); + send_ansi_sequence(screen_list, b); + break; + } + + break; + case 's': /* Private (save cursor position) */ + save_x = x; + save_y = y; + break; + case 'u': /* Private (reload cursor position) */ + x = save_x; + y = save_y; + break; + default: + debug("ansi import: unknown command \"^[%.*s\"", + final - param + 1, buffer + i + param); + break; + } + } + + /* Parse OSC stuff. */ + else if (buffer[i] == '\033' && buffer[i + 1] == ']') + { + char *string; + unsigned int command = 0; + unsigned int mode = 2, semicolon, final; + + for (semicolon = mode; i + semicolon < size; semicolon++) + { + if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9') + break; + command = 10 * command + (buffer[i + semicolon] - '0'); + } + + if (i + semicolon >= size || buffer[i + semicolon] != ';') + break; /* Invalid Mode */ + + for (final = semicolon + 1; i + final < size; final++) + if (buffer[i + final] < 0x20) + break; + + if (i + final >= size || buffer[i + final] != '\a') + break; /* Not enough data or no bell found */ + /* FIXME: XTerm also reacts to and */ + /* FIXME: differenciate between not enough data (try again) and + invalid data (print shit) */ + + skip += final; + + string = malloc(final - (semicolon + 1) + 1); + memcpy(string, buffer + i + (semicolon + 1), + final - (semicolon + 1)); + string[final - (semicolon + 1)] = '\0'; + debug("ansi import: got OSC command %i string '%s'", command, + string); + if (command == 0 || command == 2) + { + if (sc->title) + free(sc->title); + sc->title = string; + } + else + free(string); + } + + /* Get the character we’re going to paste */ + else + { + size_t bytes; + + if (i + 6 < size) + { + ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes); + } + else + { + /* Add a trailing zero to what we're going to read */ + char tmp[7]; + memcpy(tmp, buffer + i, size - i); + tmp[size - i] = '\0'; + ch = caca_utf8_to_utf32(tmp, &bytes); + } + + if (!bytes) + { + /* If the Unicode is invalid, assume it was latin1. */ + ch = buffer[i]; + bytes = 1; + } + + /* very incomplete ISO-2022 implementation tailored to DEC ACS */ + if (sc->conv_state.cs == '@') + { + if (((ch > ' ') && (ch <= '~')) + && + (sc->conv_state. + gn[sc->conv_state.ss ? sc->conv_state. + gn[sc->conv_state.ss] : sc->conv_state.glr[0]] == '0')) + { + ch = dec_acs(ch); + } + else if (((ch > 0x80) && (ch < 0xff)) + && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0')) + { + ch = dec_acs(ch + ' ' - 0x80); + } + } + sc->conv_state.ss = 0; /* no single-shift (GL) */ + + wch = caca_utf32_is_fullwidth(ch) ? 2 : 1; + + skip += bytes - 1; + } + + /* Wrap long lines or grow horizontally */ + while ((unsigned int)x + wch > width) + { + x -= width; + y++; + } + + /* Scroll or grow vertically */ + if ((unsigned int)y >= bottom) + { + int lines = (y - bottom) + 1; + + savedattr = caca_get_attr(sc->cv, -1, -1); + + for (j = top - 1; j + lines < bottom; j++) + { + for (k = 0; k < width; k++) + { + caca_put_char(sc->cv, k, j, + caca_get_char(sc->cv, k, j + lines)); + caca_put_attr(sc->cv, k, j, + caca_get_attr(sc->cv, k, j + lines)); + } + } + caca_set_attr(sc->cv, sc->clearattr); + caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' '); + y -= lines; + caca_set_attr(sc->cv, savedattr); + } + + /* Now paste our character, if any */ + if (wch) + { + caca_put_char(sc->cv, x, y, ch); + x += wch; + } + } + + caca_gotoxy(sc->cv, x, y); + + if (i) + sc->changed = 1; + return i; +} + +/* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 (ISO IR + 189) */ + +static void reset_conv_state(struct screen *sc) +{ + sc->conv_state.cs = '@'; /* ISO-2022 coding system */ + sc->conv_state.cn[0] = '@'; /* ISO 646 C0 control charset */ + sc->conv_state.cn[1] = 'C'; /* ISO 6429-1983 C1 control charset */ + sc->conv_state.glr[0] = 0; /* G0 in GL */ + sc->conv_state.glr[1] = 2; /* G2 in GR */ + sc->conv_state.gn[0] = 'B'; /* US-ASCII G0 charset */ + sc->conv_state.gn[1] = '0'; /* DEC ACS G1 charset */ + sc->conv_state.gn[2] = LITERAL2CHAR('.', 'A'); /* ISO 8859-1 G2 + charset */ + sc->conv_state.gn[3] = LITERAL2CHAR('.', 'A'); /* ISO 8859-1 G3 + charset */ + sc->conv_state.ss = 0; /* no single-shift (GL) */ + sc->conv_state.ctrl8bit = 1; +} + +/* XXX : ANSI loader helper */ + +static void ansi_parse_grcm(struct screen *sc, + unsigned int argc, unsigned int const *argv) +{ + static uint8_t const ansi2caca[] = { + CACA_BLACK, CACA_RED, CACA_GREEN, CACA_BROWN, + CACA_BLUE, CACA_MAGENTA, CACA_CYAN, CACA_LIGHTGRAY + }; + + unsigned int j; + uint8_t efg, ebg; /* Effective (libcaca) fg/bg */ + + for (j = 0; j < argc; j++) + { + /* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */ + if (argv[j] >= 30 && argv[j] <= 37) + sc->fg = ansi2caca[argv[j] - 30]; + else if (argv[j] >= 40 && argv[j] <= 47) + sc->bg = ansi2caca[argv[j] - 40]; + else if (argv[j] >= 90 && argv[j] <= 97) + sc->fg = ansi2caca[argv[j] - 90] + 8; + else if (argv[j] >= 100 && argv[j] <= 107) + sc->bg = ansi2caca[argv[j] - 100] + 8; + else + switch (argv[j]) + { + case 0: /* default rendition */ + sc->fg = sc->dfg; + sc->bg = sc->dbg; + sc->bold = sc->blink = sc->italics = sc->negative + = sc->concealed = sc->underline = sc->faint = sc->strike + = sc->proportional = 0; + break; + case 1: /* bold or increased intensity */ + sc->bold = 1; + break; + case 2: /* faint, decreased intensity or second colour + */ + sc->faint = 1; + break; + case 3: /* italicized */ + sc->italics = 1; + break; + case 4: /* singly underlined */ + sc->underline = 1; + break; + case 5: /* slowly blinking (less then 150 per minute) */ + case 6: /* rapidly blinking (150 per minute or more) */ + sc->blink = 1; + break; + case 7: /* negative image */ + sc->negative = 1; + break; + case 8: /* concealed characters */ + sc->concealed = 1; + break; + case 9: /* crossed-out (characters still legible but + marked as to be deleted */ + sc->strike = 1; + break; + case 21: /* doubly underlined */ + sc->underline = 1; + break; + case 22: /* normal colour or normal intensity (neither + bold nor faint) */ + sc->bold = sc->faint = 0; + break; + case 23: /* not italicized, not fraktur */ + sc->italics = 0; + break; + case 24: /* not underlined (neither singly nor doubly) */ + sc->underline = 0; + break; + case 25: /* steady (not blinking) */ + sc->blink = 0; + break; + case 26: /* (reserved for proportional spacing as + specified in CCITT Recommendation T.61) */ + sc->proportional = 1; + break; + case 27: /* positive image */ + sc->negative = 0; + break; + case 28: /* revealed characters */ + sc->concealed = 0; + break; + case 29: /* not crossed out */ + sc->strike = 0; + break; + case 38: /* (reserved for future standardization, + intended for setting character foreground + colour as specified in ISO 8613-6 [CCITT + Recommendation T.416]) */ + break; + case 39: /* default display colour + (implementation-defined) */ + sc->fg = sc->dfg; + break; + case 48: /* (reserved for future standardization, + intended for setting character background + colour as specified in ISO 8613-6 [CCITT + Recommendation T.416]) */ + break; + case 49: /* default background colour + (implementation-defined) */ + sc->bg = sc->dbg; + break; + case 50: /* (reserved for cancelling the effect of the + rendering aspect established by parameter + value 26) */ + sc->proportional = 0; + break; + default: + debug("ansi import: unknown sgr %i", argv[j]); + break; + } + } + + if (sc->concealed) + { + efg = ebg = CACA_TRANSPARENT; + } + else + { + efg = sc->negative ? sc->bg : sc->fg; + ebg = sc->negative ? sc->fg : sc->bg; + + if (sc->bold) + { + if (efg < 8) + efg += 8; + else if (efg == CACA_DEFAULT) + efg = CACA_WHITE; + } + } + + caca_set_color_ansi(sc->cv, efg, ebg); +} diff --git a/neercs/old/attach.c b/neercs/old/attach.c new file mode 100644 index 0000000..8a57d5e --- /dev/null +++ b/neercs/old/attach.c @@ -0,0 +1,424 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "config.h" +#include "neercs.h" + +char *build_socket_path(char *socket_dir, char *session_name, + enum socket_type socktype) +{ + char *path, *dir; + path = (char *)malloc(PATH_MAX + 1); + dir = socket_dir; + if (!dir) + dir = getenv("NEERCSDIR"); + if (!dir) + dir = getenv("TMPDIR"); + if (!dir) + dir = "/tmp"; + if (path) + snprintf(path, PATH_MAX + 1, "%s/neercs.%s%s.sock", dir, session_name, + socktype ? "" : ".srv"); + return path; +} + +static char *socket_to_session(char const *sockpath) +{ + char *p, *s; + p = strrchr(sockpath, '/'); + if (!p) + { + debug("Invalid socket path %s", sockpath); + return NULL; + } + p += 8; /* skip neercs. */ + s = strdup(p); + p = strrchr(s, '.'); + *p = '\0'; /* drop .sock */ + p = strrchr(s, '.'); + *p = '\0'; /* drop .srv */ + p = strdup(s); + free(s); + return p; +} + +int create_socket(struct screen_list *screen_list, enum socket_type socktype) +{ + int sock; + struct sockaddr_un myaddr; + + sock = socket(AF_UNIX, SOCK_DGRAM, 0); + + if (sock < 0) + { + perror("create_socket:socket"); + return errno; + } + + memset(&myaddr, 0, sizeof(struct sockaddr_un)); + + myaddr.sun_family = AF_UNIX; + strncpy(myaddr.sun_path, screen_list->comm.socket_path[socktype], + sizeof(myaddr.sun_path) - 1); + + unlink(screen_list->comm.socket_path[socktype]); + + if (bind(sock, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_un)) < 0) + { + free(screen_list->comm.socket_path[socktype]); + screen_list->comm.socket_path[socktype] = NULL; + close(sock); + perror("create_socket:bind"); + return errno; + } + fcntl(sock, F_SETFL, O_NONBLOCK); + + debug("Listening on %s (%d)", screen_list->comm.socket_path[socktype], sock); + + screen_list->comm.socket[socktype] = sock; + + return 0; +} + +char **list_sockets(char *socket_dir, char *session_name) +{ + char *pattern, *dir; + glob_t globbuf; + + globbuf.gl_pathv = NULL; + + pattern = (char *)malloc(PATH_MAX + 1); + + dir = socket_dir; + if (!dir) + dir = getenv("NEERCSDIR"); + if (!dir) + dir = getenv("TMPDIR"); + if (!dir) + dir = "/tmp"; + + if (!pattern) + return globbuf.gl_pathv; + + if (session_name && strlen(session_name) + strlen(dir) + 13 < PATH_MAX) + sprintf(pattern, "%s/neercs.%s.srv.sock", dir, session_name); + else + snprintf(pattern, PATH_MAX, "%s/neercs.*.srv.sock", dir); + pattern[PATH_MAX] = '\0'; + + debug("Looking for sockets in the form %s", pattern); + + glob(pattern, 0, NULL, &globbuf); + + free(pattern); + + return globbuf.gl_pathv; +} + +char *connect_socket(struct screen_list *screen_list, + enum socket_type socktype) +{ + int sock; + struct sockaddr_un addr; + + debug("Connecting to %s", screen_list->comm.socket_path[socktype]); + + /* Open the socket */ + if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) + { + debug("Failed to create socket\n"); + perror("connect_server:socket"); + return NULL; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, screen_list->comm.socket_path[socktype]); + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + debug("Failed to connect to %s: %s", + screen_list->comm.socket_path[socktype], strerror(errno)); + close(sock); + return NULL; + } + fcntl(sock, F_SETFL, O_NONBLOCK); + + screen_list->comm.socket[socktype] = sock; + + if (socktype == SOCK_SERVER) + { + return socket_to_session(screen_list->comm.socket_path[socktype]); + } + else + return NULL; +} + +int request_attach(struct screen_list *screen_list) +{ + char buf[41]; + int bytes; + + bytes = snprintf(buf, sizeof(buf) - 1, "ATTACH %10d %10d %10d", + caca_get_canvas_width(screen_list->cv), + caca_get_canvas_height(screen_list->cv), + screen_list->delay); + buf[bytes] = '\0'; + debug("Requesting attach: %s", buf); + return write(screen_list->comm.socket[SOCK_SERVER], buf, strlen(buf)) <= 0; +} + +static char *select_socket(struct screen_list *screen_list) +{ + char **sockets = NULL, **usable_sockets = NULL; + int i, sock, nb_usable_sockets = 0; + char *ret = NULL; + + sockets = list_sockets(screen_list->comm.socket_dir, screen_list->comm.session_name); + if (sockets) + { + for (i = 0; sockets[i]; i++); + + /* Return the socket or NULL if there is not more than one match */ + if (i <= 1) + { + if (sockets[0]) + ret = strdup(sockets[0]); + goto end; + } + + /* Else ask the user to chose one */ + usable_sockets = malloc(i * sizeof(char *)); + for (i = 0; sockets[i]; i++) + { + struct sockaddr_un addr; + if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) + { + perror("select_socket:socket"); + goto end; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockets[i]); + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + switch (errno) + { + case EACCES: + debug("Connection refused on %s", sockets[i]); + break; + case ECONNREFUSED: + fprintf(stderr, "%s is dead\n", sockets[i]); + break; + default: + fprintf(stderr, "Unknown error on %s:%s\n", sockets[i], + strerror(errno)); + } + } + else + { + usable_sockets[nb_usable_sockets] = strdup(sockets[i]); + debug("%s is usable", usable_sockets[nb_usable_sockets]); + nb_usable_sockets++; + close(sock); + } + } + if (!nb_usable_sockets) + goto end; + if (nb_usable_sockets == 1) + { + ret = strdup(usable_sockets[0]); + goto end; + } + else + { + caca_event_t ev; + enum caca_event_type t; + int current_line = 1; + int refresh = 1; + screen_list->cv = caca_create_canvas(0, 0); + screen_list->dp = caca_create_display(screen_list->cv); + if (!screen_list->dp) + goto end; + caca_set_cursor(screen_list->dp, 0); + caca_set_display_title(screen_list->dp, PACKAGE_STRING); + while (1) + { + if (refresh) + { + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + caca_fill_box(screen_list->cv, + 0, 0, + caca_get_canvas_width(screen_list->cv), + caca_get_canvas_height(screen_list->cv), + '#'); + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, + CACA_BLUE); + caca_draw_cp437_box(screen_list->cv, 0, 0, + caca_get_canvas_width(screen_list->cv), + caca_get_canvas_height(screen_list-> + cv)); + caca_printf(screen_list->cv, 2, 2, + "Please select a session to reconnect:"); + for (i = 0; i < nb_usable_sockets; i++) + { + if (i == current_line - 1) + { + caca_set_attr(screen_list->cv, CACA_BOLD); + caca_set_color_ansi(screen_list->cv, CACA_GREEN, + CACA_BLUE); + caca_put_char(screen_list->cv, 1, i + 3, '>'); + } + else + { + caca_set_attr(screen_list->cv, 0); + caca_set_color_ansi(screen_list->cv, + CACA_LIGHTGRAY, CACA_BLUE); + caca_put_char(screen_list->cv, 1, i + 3, ' '); + } + caca_printf(screen_list->cv, + 3, i + 3, + "%s", + socket_to_session(usable_sockets[i])); + } + caca_refresh_display(screen_list->dp); + refresh = 0; + } + + if (!caca_get_event(screen_list->dp, + CACA_EVENT_KEY_PRESS + | CACA_EVENT_RESIZE + | CACA_EVENT_QUIT, &ev, 10000)) + continue; + + t = caca_get_event_type(&ev); + + if (t & CACA_EVENT_KEY_PRESS) + { + unsigned int c = caca_get_event_key_ch(&ev); + switch (c) + { + case CACA_KEY_UP: + if (current_line > 1) + current_line--; + break; + case CACA_KEY_DOWN: + if (current_line < nb_usable_sockets) + current_line++; + break; + case CACA_KEY_RETURN: + ret = strdup(usable_sockets[current_line - 1]); + goto end; + break; + case CACA_KEY_ESCAPE: + goto end; + break; + default: + break; + } + refresh = 1; + } + else if (t & CACA_EVENT_RESIZE) + { + refresh = 1; + } + else if (t & CACA_EVENT_QUIT) + goto end; + } + } + } + + end: + if (sockets) + { + for (i = 0; sockets[i]; i++) + free(sockets[i]); + free(sockets); + } + if (usable_sockets) + { + for (i = 0; i < nb_usable_sockets; i++) + free(usable_sockets[i]); + free(usable_sockets); + } + if (screen_list->dp) + { + caca_free_display(screen_list->dp); + screen_list->dp = NULL; + } + if (screen_list->cv) + { + caca_free_canvas(screen_list->cv); + screen_list->cv = NULL; + } + return ret; +} + +void attach(struct screen_list *screen_list) +{ + screen_list->comm.socket_path[SOCK_SERVER] = select_socket(screen_list); + + if (screen_list->comm.socket_path[SOCK_SERVER]) + { + char *session; + session = connect_socket(screen_list, SOCK_SERVER); + if (session) + { + debug("Connected to session %s", session); + /* Create main canvas and associated caca window */ + screen_list->cv = caca_create_canvas(0, 0); + screen_list->dp = caca_create_display(screen_list->cv); + if (!screen_list->dp) + return; + caca_set_display_time(screen_list->dp, screen_list->delay * 1000); + caca_set_cursor(screen_list->dp, 1); + + screen_list->comm.socket_path[SOCK_CLIENT] = + build_socket_path(screen_list->comm.socket_dir, session, + SOCK_CLIENT); + create_socket(screen_list, SOCK_CLIENT); + request_attach(screen_list); + if (screen_list->comm.session_name) + free(screen_list->comm.session_name); + screen_list->comm.session_name = session; + } + else + { + fprintf(stderr, "Failed to attach!\n"); + free(screen_list->comm.socket_path[SOCK_SERVER]); + screen_list->comm.socket_path[SOCK_SERVER] = NULL; + screen_list->sys.attach = 0; + } + } + else + { + fprintf(stderr, "No socket found!\n"); + screen_list->sys.attach = 0; + } +} + diff --git a/neercs/old/client.c b/neercs/old/client.c new file mode 100644 index 0000000..725092c --- /dev/null +++ b/neercs/old/client.c @@ -0,0 +1,298 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2011 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "neercs.h" + +#define NEERCS_RECV_BUFSIZE 128*1024 + + +int start_client(struct screen_list *screen_list) +{ + char *sess = NULL; + create_socket(screen_list, SOCK_CLIENT); + while ((sess = connect_socket(screen_list, SOCK_SERVER)) == NULL) + usleep(100); + free(sess); + + /* Create main canvas and associated caca window */ + screen_list->cv = caca_create_canvas(0, 0); + screen_list->dp = caca_create_display(screen_list->cv); + screen_list->mouse_button = 0; + + if (!screen_list->dp) + return -3; + + caca_set_display_time(screen_list->dp, screen_list->delay * 1000); + caca_set_cursor(screen_list->dp, 1); + + request_attach(screen_list); + + return 0; +} + +int send_event(caca_event_t ev, struct screen_list *screen_list) +{ + enum caca_event_type t; + char buf[64]; + int bytes = 0; + + t = caca_get_event_type(&ev); + + if (t & CACA_EVENT_KEY_PRESS) + { + bytes = snprintf(buf, sizeof(buf) - 1, "KEY %d", + caca_get_event_key_ch(&ev)); + debug("Sending key press to server: %s", buf); + } + else if (t & CACA_EVENT_RESIZE) + { + bytes = snprintf(buf, sizeof(buf) - 1, "RESIZE %10d %10d", + caca_get_event_resize_width(&ev), + caca_get_event_resize_height(&ev)); + } + else if (t & CACA_EVENT_MOUSE_PRESS) + { + screen_list->mouse_button = caca_get_event_mouse_button(&ev); + bytes = snprintf(buf, sizeof(buf) - 1, "MOUSEP %10d %10d %10d", + caca_get_mouse_x(screen_list->dp), + caca_get_mouse_y(screen_list->dp), + screen_list->mouse_button); + } + else if (t & CACA_EVENT_MOUSE_RELEASE) + { + bytes = snprintf(buf, sizeof(buf) - 1, "MOUSER %10d %10d %10d", + caca_get_mouse_x(screen_list->dp), + caca_get_mouse_y(screen_list->dp), + screen_list->mouse_button); + screen_list->mouse_button = 0; + } + else if (t & CACA_EVENT_MOUSE_MOTION) + { + int x = caca_get_mouse_x(screen_list->dp); + int y = caca_get_mouse_y(screen_list->dp); + int b = screen_list->mouse_button; + debug("Mouse motion, button %d", b); + if (x != screen_list->old_x || y != screen_list->old_y) + { + screen_list->old_x = caca_get_mouse_x(screen_list->dp); + screen_list->old_y = caca_get_mouse_y(screen_list->dp); + + bytes = snprintf(buf, sizeof(buf) - 1, "MOUSEM %10d %10d %10d", + caca_get_mouse_x(screen_list->dp), + caca_get_mouse_y(screen_list->dp), + b>=0?b:0); + } + } + else if (t & CACA_EVENT_QUIT) + { + bytes = snprintf(buf, sizeof(buf) - 1, "QUIT"); + } + if (bytes) + { + ssize_t r; + buf[bytes] = '\0'; + debug("Sending '%s', %d bytes", buf, bytes); + r = write(screen_list->comm.socket[SOCK_SERVER], buf, bytes+1); + while (r < 0 && errno == EAGAIN) + { + usleep(20); + r = write(screen_list->comm.socket[SOCK_SERVER], buf, bytes+1); + } + return r < 0; + } + return 0; +} + +int send_delay(struct screen_list *screen_list) +{ + debug("Sending DELAY\n"); + char buf[18]; + int bytes; + bytes = snprintf(buf, sizeof(buf) - 1, "DELAY %10d", screen_list->delay); + buf[bytes] = '\0'; + return write(screen_list->comm.socket[SOCK_SERVER], buf, strlen(buf)) <= 0; +} + +/** \brief Main client loop. + * + * This is the main client loop. + * + * Repeat forever: + * - if data is available on the client socket, read it and interpret it: + * - "DETACH": exit the loop + * - "UPDATE": update screen with the given canvas data + * - "REFRESH": refresh the whole display + * - "CURSOR": set cursor position + * - "TITLE": set window or display title + * - wait for an input event with a 10ms timeout + */ +void mainloop(struct screen_list *screen_list) +{ + char *buf = NULL; + screen_list->last_key_time = get_us(); + + while (mainloop_tick(&buf, screen_list)) + ; + + free(buf); +} + +int mainloop_tick(char **pbuf, struct screen_list *screen_list) +{ + caca_event_t ev; + int ret = 0; + ssize_t n; + if (!screen_list) + return 0; + if (!*pbuf) + *pbuf = malloc(NEERCS_RECV_BUFSIZE); + if (!*pbuf) + { + debug("Failed to allocate memory"); + return 0; + } + if (screen_list->comm.socket[SOCK_CLIENT] + && (n = + read(screen_list->comm.socket[SOCK_CLIENT], *pbuf, + NEERCS_RECV_BUFSIZE - 1)) > 0) + { + *pbuf[n] = 0; + debug("Received from server: '%s' (%d bytes)", *pbuf, n); + if (!strncmp("DETACH", *pbuf, 6)) + { + /* ret = 1; Not used */ + return 1; + } + else if (!strncmp("UPDATE ", *pbuf, 7)) + { + int x, y; + ssize_t l2 = 0, lb = 0; + char *buf2; + size_t l = 0; + /* FIXME check the length before calling atoi */ + x = atoi(*pbuf + 8); + y = atoi(*pbuf + 19); + + /* 0 means we have valid data but incomplete, so read the rest + */ + while (l == 0) + { + buf2 = realloc(*pbuf, l2 + NEERCS_RECV_BUFSIZE); + if (!buf2) + { + debug("Failed to allocate memory"); + return 0; + } + *pbuf = buf2; + fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, 0); + lb = read(screen_list->comm.socket[SOCK_CLIENT], *pbuf + l2, + NEERCS_RECV_BUFSIZE - 1); + if (lb < 0) + { + debug + ("Failed to read the end of the refresh message (%s)", + strerror(errno)); + l = -1; + } + else + { + l2 += lb; + l = caca_import_area_from_memory(screen_list->cv, x, y, + *pbuf, l2, "caca"); + } + } + fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, + O_NONBLOCK); + } + else if (!strncmp("REFRESH ", *pbuf, 8)) + { + int dt, x, y; + /* FIXME check the length before calling atoi */ + x = atoi(*pbuf + 8); + y = atoi(*pbuf + 19); + caca_gotoxy(screen_list->cv, x, y); + caca_refresh_display(screen_list->dp); + dt = caca_get_display_time(screen_list->dp); + + /* Adjust refresh delay so that the server do not compute + useless things */ + if (dt > 2 * 1000 * screen_list->delay + && screen_list->delay <= 100) + { + screen_list->delay *= 2; + send_delay(screen_list); + } + else if (dt < screen_list->delay * 1000 * 1.2 && + screen_list->delay >= + 3 * screen_list->requested_delay / 2) + { + screen_list->delay = 2 * screen_list->delay / 3; + send_delay(screen_list); + } + screen_list->comm.attached = 1; + } + else if (!strncmp("CURSOR ", *pbuf, 7)) + { + caca_set_cursor(screen_list->dp, atoi(*pbuf + 7)); + } + else if (!strncmp("TITLE ", *pbuf, 6)) + { + caca_set_display_title(screen_list->dp, *pbuf + 6); + caca_refresh_display(screen_list->dp); + } + else + { + debug("Unknown message received from server: %s", *pbuf); + } + } + + /* Wait to have finished attaching before handling events */ + if (screen_list->comm.attached) + { + ret = caca_get_event(screen_list->dp, + CACA_EVENT_KEY_PRESS + | CACA_EVENT_MOUSE_PRESS + | CACA_EVENT_MOUSE_RELEASE + | CACA_EVENT_MOUSE_MOTION + | CACA_EVENT_RESIZE + | CACA_EVENT_QUIT, &ev, 10000); + if (ret) + ret = send_event(ev, screen_list); + if (ret) + { + debug("Failed send event, quitting: %s\n", strerror(errno)); + return 1; + } + } + + return 1; +} diff --git a/neercs/old/configuration.c b/neercs/old/configuration.c new file mode 100644 index 0000000..66a544e --- /dev/null +++ b/neercs/old/configuration.c @@ -0,0 +1,568 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "neercs.h" + + +struct config_line *get_config(const char *name); +int set_window_manager(const char *argv, struct screen_list *screen_list); +int set_cube_duration(const char *argv, struct screen_list *screen_list); +int set_thumbnails(const char *argv, struct screen_list *screen_list); +int set_status_bar(const char *argv, struct screen_list *screen_list); +int set_screensaver_timeout(const char *argv, struct screen_list *screen_list); +int set_autolock_timeout(const char *argv, struct screen_list *screen_list); +int set_lock_on_detach(const char *argv, struct screen_list *screen_list); +int set_socket_dir(const char *argv, struct screen_list *screen_list); +int set_delay(const char *argv, struct screen_list *screen_list); +int set_eyecandy(const char *argv, struct screen_list *screen_list); +int set_border(const char *argv, struct screen_list *screen_list); +char *get_window_manager(struct screen_list *screen_list); +char *get_cube_duration(struct screen_list *screen_list); +char *get_thumbnails(struct screen_list *screen_list); +char *get_status_bar(struct screen_list *screen_list); +char *get_screensaver_timeout(struct screen_list *screen_list); +char *get_autolock_timeout(struct screen_list *screen_list); +char *get_lock_on_detach(struct screen_list *screen_list); +char *get_socket_dir(struct screen_list *screen_list); +char *get_delay(struct screen_list *screen_list); +char *get_eyecandy(struct screen_list *screen_list); +char *get_border(struct screen_list *screen_list); + +/* Options definition and associated function pointer */ +struct config_line config_option[] = { + {.name = "window_manager",.set = set_window_manager,.get = + get_window_manager}, + {.name = "eyecandy",.set = set_eyecandy,.get = get_eyecandy}, + {.name = "borders",.set = set_border,.get = get_border}, + {.name = "cube_duration",.set = set_cube_duration,.get = + get_cube_duration}, + {.name = "thumbnails",.set = set_thumbnails,.get = get_thumbnails}, + {.name = "status_bar",.set = set_status_bar,.get = get_status_bar}, + {.name = "screensaver_timeout",.set = set_screensaver_timeout,.get = + get_screensaver_timeout}, + {.name = "autolock_timeout",.set = set_autolock_timeout,.get = + get_autolock_timeout}, + {.name = "lock_on_detach",.set = set_lock_on_detach,.get = + get_lock_on_detach}, + {.name = "socket_dir",.set = set_socket_dir,.get = get_socket_dir}, + {.name = "delay",.set = set_delay,.get = get_delay}, + + {.name = "last",.set = NULL}, +}; + + + +int read_configuration_file(char *filename, struct screen_list *screen_list) +{ + FILE *fp; + struct stat st; + int size = 0, i = 0, total = 0, offset = 0, l = 1; + char *buffer = NULL; + + screen_list->config = NULL; + + /* Check if file exist */ + if (stat(filename, &st) < 0) + { + return -1; + } + /* Get its size */ + size = st.st_size; + if (!size) + { + fprintf(stderr, "File too short\n"); + return -1; + } + + /* Open it */ + fp = fopen(filename, "r"); + if (!fp) + { + return -1; + } + + buffer = malloc(size + 1); + if (!buffer) + { + fclose(fp); + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + return -1; + } + /* Read it */ + while ((i = fread(buffer + total, 1, size, fp)) > 0) + { + total += i; + } + buffer[total] = '\n'; + + fclose(fp); + + /* Parse it */ + while ((i = + parse_conf_line(buffer + offset, total - offset, screen_list)) > 0) + { + offset += i; + l++; + } + + free(buffer); + + /* Fill neercs configuration with it */ + fill_config(screen_list); + + return 1; +} + +struct config_line *get_config_option(void) +{ + return config_option; +} + +int parse_conf_line(char *buf, int size, struct screen_list *screen_list) +{ + int i, s = 0, c = 0; + char *line = NULL; + int l = 0; + int in_quote = 0, end_spaces = 0; + static struct option *prev = NULL; + + if (size <= 0) + return -1; + + /* Find EOL */ + for (i = 0; i < size; i++) + { + if (buf[i] == '\n') + { + s = i + 1; + break; + } + } + + /* Strip comments and trailing spaces */ + for (i = 0; i < s; i++) + { + if (buf[i] == ';' && !in_quote) + { + break; + } + else if (buf[i] == '\n') + { + break; + } + else if (buf[i] == ' ' && !c) + { + } + else + { + if (line == NULL) + { + line = malloc(2); + if (!line) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + } + else + { + line = realloc(line, l + 2); + if (!line) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + } + if (buf[i] == '"') + in_quote = !in_quote; + if (buf[i] == ' ') + end_spaces++; + else + end_spaces = 0; + + line[l] = buf[i]; + line[l + 1] = 0; + l++; + c = 1; + } + } + + if (c == 0) + { + /* This line is empty, do nothing */ + } + else + { + struct option *option = malloc(sizeof(struct option)); + if (!option) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + option->next = NULL; + l -= end_spaces; + line = realloc(line, l + 1); + line[l] = 0; + + get_key_value(line, option); + + if (!screen_list->config) + screen_list->config = option; + + if (prev) + prev->next = option; + + prev = option; + } + free(line); + return s; +} + +int get_key_value(char *line, struct option *option) +{ + unsigned int i, o = 0, b = 0, end_spaces = 0; + char *cur = NULL; + option->value = NULL; + option->key = NULL; + + /* Line is a section delimiter */ + if (line[0] == '[') + { + option->value = malloc(strlen(line) - 1); + if (!option->value) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + memcpy(option->value, line + 1, strlen(line) - 1); + option->value[strlen(line) - 2] = 0; + return 0; + } + + cur = malloc(1); + if (!cur) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + cur[0] = 0; + + for (i = 0; i < strlen(line); i++) + { + if (line[i] == ' ' && !b) + continue; + + + if (line[i] == '=') + { + b = 0; + cur[o - end_spaces] = 0; + cur = realloc(cur, (o - end_spaces) + 1); + if (!cur) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + o = 0; + option->key = cur; + cur = malloc(1); + } + else + { + if (line[i] == ' ') + end_spaces++; + else + end_spaces = 0; + + cur = realloc(cur, o + 2); + if (!cur) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + cur[o] = line[i]; + o++; + b = 1; + + } + } + cur[o] = 0; + option->value = cur; + return 0; +} + + + +struct config_line *get_config(const char *name) +{ + int i = 0; + + debug("Looking for '%s'\n", name); + + while (strncmp(config_option[i].name, "last", strlen("last"))) + { + debug("%d Testing against '%s'\n", i, config_option[i].name); + if (!strncmp(name, config_option[i].name, strlen(name))) + { + debug("Found\n"); + return &config_option[i]; + } + i++; + } + return NULL; +} + + + +int fill_config(struct screen_list *screen_list) +{ + int i = 0; + struct option *option = screen_list->config; + + while (option) + { + if (option->key == NULL) + { + option = option->next; + continue; + } + + struct config_line *c = get_config(option->key); + if (c) + { + c->set((const char *)option->value, screen_list); + } + option = option->next; + } + + return i; +} + + + +/* + * Options setters + */ + +#define IS_OPTION(t) (!strncmp(argv, t, strlen(argv))) +#define IS_OPTION_TRUE (IS_OPTION("true") || IS_OPTION("True") || IS_OPTION("1")) + +int set_window_manager(const char *argv, struct screen_list *screen_list) +{ + if (IS_OPTION("full")) + screen_list->wm_type = WM_FULL; + else if (IS_OPTION("hsplit")) + screen_list->wm_type = WM_HSPLIT; + else if (IS_OPTION("vsplit")) + screen_list->wm_type = WM_VSPLIT; + else if (IS_OPTION("card")) + screen_list->wm_type = WM_CARD; + else + { + fprintf(stderr, "Unknown window manager '%s'\n", argv); + return -1; + } + return 0; +} + +int set_cube_duration(const char *argv, struct screen_list *screen_list) +{ + screen_list->cube.duration = atoi(argv) * 1000000; + return 0; +} + +int set_thumbnails(const char *argv, struct screen_list *screen_list) +{ + if (IS_OPTION_TRUE) + screen_list->modals.mini = 1; + else + screen_list->modals.mini = 0; + return 0; + +} + +int set_status_bar(const char *argv, struct screen_list *screen_list) +{ + if (IS_OPTION_TRUE) + screen_list->modals.status = 1; + else + screen_list->modals.status = 0; + return 0; +} + +int set_screensaver_timeout(const char *argv, struct screen_list *screen_list) +{ + screen_list->screensaver.timeout = atoi(argv) * 1000000; + /* if timeout is 0, set it to 0xFFFFFFFFFFFFFFFF */ + if (!screen_list->screensaver.timeout) + screen_list->screensaver.timeout -= 1; + return 0; +} + +int set_autolock_timeout(const char *argv, struct screen_list *screen_list) +{ + if (screen_list->lock.autolock_timeout == 0 || + screen_list->lock.autolock_timeout == ((long long unsigned int)0) - 1) + { + screen_list->lock.autolock_timeout = atoi(argv) * 1000000; + /* if timeout is 0, set it to 0xFFFFFFFFFFFFFFFF */ + if (!screen_list->lock.autolock_timeout) + screen_list->lock.autolock_timeout -= 1; + } + return 0; +} + +int set_lock_on_detach(const char *argv, struct screen_list *screen_list) +{ + if (IS_OPTION_TRUE) + screen_list->lock.lock_on_detach = 1; + else + screen_list->lock.lock_on_detach = 0; + return 0; +} + +int set_eyecandy(const char *argv, struct screen_list *screen_list) +{ + if (IS_OPTION_TRUE) + screen_list->eyecandy = 1; + else + screen_list->eyecandy = 0; + return 0; +} + +int set_border(const char *argv, struct screen_list *screen_list) +{ + if (IS_OPTION_TRUE) + screen_list->border_size = 1; + else + screen_list->border_size = 0; + return 0; +} + +int set_socket_dir(const char *argv, struct screen_list *screen_list) +{ + screen_list->comm.socket_dir = strdup(argv); + return 0; +} + +int set_delay(const char *argv, struct screen_list *screen_list) +{ + screen_list->requested_delay = atoi(argv); + screen_list->delay = atoi(argv); + return 0; +} + +char *get_window_manager(struct screen_list *screen_list) +{ + debug("Window manager is %d", screen_list->wm_type); + switch (screen_list->wm_type) + { + case WM_FULL: + return "full"; + case WM_CARD: + return "card"; + case WM_VSPLIT: + return "vsplit"; + case WM_HSPLIT: + return "hsplit"; + default: + return "invalid window manager"; + } + return NULL; /* Not reached */ +} + +char *get_cube_duration(struct screen_list *screen_list) +{ + char *r = malloc(100); + sprintf(r, "%f", (float)screen_list->cube.duration / 1000000.0f); + return r; +} + +char *get_thumbnails(struct screen_list *screen_list) +{ + if (screen_list->modals.mini) + return "true"; + return "false"; +} + +char *get_status_bar(struct screen_list *screen_list) +{ + if (screen_list->modals.status) + return "true"; + return "false"; +} + +char *get_eyecandy(struct screen_list *screen_list) +{ + if (screen_list->eyecandy) + return "true"; + return "false"; +} + +char *get_border(struct screen_list *screen_list) +{ + if (screen_list->border_size) + return "true"; + return "false"; +} + +char *get_screensaver_timeout(struct screen_list *screen_list) +{ + char *r = malloc(100); + sprintf(r, "%f", (float)screen_list->screensaver.timeout / 1000000.0f); + return r; +} + +char *get_autolock_timeout(struct screen_list *screen_list) +{ + char *r = malloc(100); + sprintf(r, "%f", (float)screen_list->lock.autolock_timeout / 1000000.0f); + return r; +} + +char *get_lock_on_detach(struct screen_list *screen_list) +{ + if (screen_list->lock.lock_on_detach) + return "true"; + else + return "false"; +} + +char *get_socket_dir(struct screen_list *screen_list) +{ + return screen_list->comm.socket_dir; +} + +char *get_delay(struct screen_list *screen_list) +{ + char *r = malloc(100); + sprintf(r, "%d", screen_list->requested_delay); + return r; +} diff --git a/neercs/old/effects.c b/neercs/old/effects.c new file mode 100644 index 0000000..7999141 --- /dev/null +++ b/neercs/old/effects.c @@ -0,0 +1,278 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "neercs.h" + +void draw_thumbnails(struct screen_list *screen_list) +{ + char const *const *fonts; + caca_dither_t *d; + caca_font_t *f; + uint8_t *buf; + int i, y = + caca_get_canvas_height(screen_list->cv) - 6 - screen_list->modals.status; + int miniw, minih; + + if (screen_list->count) + { + fonts = caca_get_font_list(); + f = caca_load_font(fonts[0], 0); + + miniw = caca_get_canvas_width(screen_list->screen[0]->cv) + * caca_get_font_width(f); + minih = caca_get_canvas_height(screen_list->screen[0]->cv) + * caca_get_font_height(f); + buf = malloc(4 * miniw * minih); + +#if defined(HAVE_ENDIAN_H) + if (__BYTE_ORDER == __BIG_ENDIAN) +#else + /* This is compile-time optimised with at least -O1 or -Os */ + uint32_t const tmp = 0x12345678; + if (*(uint8_t const *)&tmp == 0x12) +#endif + d = caca_create_dither(32, miniw, minih, 4 * miniw, + 0xff0000, 0xff00, 0xff, 0x0); + else + d = caca_create_dither(32, miniw, minih, 4 * miniw, + 0xff00, 0xff0000, 0xff000000, 0x0); + + for (i = 0; i < screen_list->count; i++) + { + if (!screen_list->screen[i]->changed && !screen_list->changed) + continue; + caca_render_canvas(screen_list->screen[i]->cv, f, buf, + miniw, minih, miniw * 4); + caca_dither_bitmap(screen_list->cv, 20 * i, y, 19, 6, d, buf); + caca_set_color_ansi(screen_list->cv, CACA_WHITE, CACA_BLUE); + + if (screen_list->pty == i) + caca_draw_cp437_box(screen_list->cv, 20 * i, y, 19, 6); + caca_printf(screen_list->cv, 20 * i, y, "(%i)", i + 1); + } + + caca_free_dither(d); + caca_free_font(f); + + free(buf); + } + +} + +/* FIXME, make this stuff more configurable */ +void draw_status(struct screen_list *screen_list) +{ + int x = 0, y = caca_get_canvas_height(screen_list->cv) - 1; + + + /* caca_fill_box(screen_list->cv, x, y, + caca_get_canvas_width(screen_list->cv), 1, '#'); */ + + /* Hour */ + { + time_t now = time((time_t *) 0); + struct tm *t = localtime(&now); + char hour[256]; + sprintf(hour, "%02d:%02d", t->tm_hour, t->tm_min); + + caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE); + caca_printf(screen_list->cv, x, y, "["); + + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE); + caca_printf(screen_list->cv, x + 1, y, hour); + caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE); + caca_printf(screen_list->cv, x + strlen(hour) + 1, y, "]"); + x += 7; + + } + + /* Window */ + { + char text[256]; + sprintf(text, "%d/%d", screen_list->pty + 1, screen_list->count); + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + caca_put_char(screen_list->cv, x, y, '#'); + x++; + caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE); + caca_printf(screen_list->cv, x, y, "Window:"); + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + caca_put_char(screen_list->cv, x + 7, y, '#'); + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE); + caca_printf(screen_list->cv, x + 8, y, text); + x += 8 + strlen(text); + } + + /* Window Manager */ + { + char text[256]; + + switch (screen_list->wm_type) + { + case WM_CARD: + strcpy(text, "card"); + break; + case WM_HSPLIT: + strcpy(text, "hsplit"); + break; + case WM_VSPLIT: + strcpy(text, "vsplit"); + break; + case WM_FULL: + default: + strcpy(text, "full"); + break; + + } + + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + caca_put_char(screen_list->cv, x, y, '#'); + x++; + caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE); + caca_printf(screen_list->cv, x, y, "WM:"); + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + caca_put_char(screen_list->cv, x + 3, y, '#'); + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE); + caca_printf(screen_list->cv, x + 4, y, text); + x += 4 + strlen(text); + } + + /* Help (must be the last one ) */ + { + char text[256]; + sprintf(text, "Help: ctrl-a-?"); + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + while (x < + (int)(caca_get_canvas_width(screen_list->cv) - strlen(text))) + { + caca_put_char(screen_list->cv, x, y, '#'); + x++; + } + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE); + caca_printf(screen_list->cv, x, y, text); + } + + +} + + + +int update_window_list(int c, struct screen_list *screen_list) +{ + debug("Got %x\n", c); + + switch (c) + { + case 0x111: + if (screen_list->modals.cur_in_list > 0) + screen_list->modals.cur_in_list--; + break; + case 0x112: + if (screen_list->modals.cur_in_list < screen_list->count - 1) + screen_list->modals.cur_in_list++; + break; + case 0xd: + screen_list->modals.window_list = 0; + screen_list->prevpty = screen_list->pty; + screen_list->pty = screen_list->modals.cur_in_list; + break; + case 0x22: + screen_list->modals.window_list = 0; + break; + default: + break; + } + + return 1; +} + +void draw_list(struct screen_list *screen_list) +{ + int i; + int w = (caca_get_canvas_width(screen_list->cv)); + int h = (caca_get_canvas_height(screen_list->cv)); + + debug("Drawing list\n"); + caca_set_color_ansi(screen_list->cv, CACA_BLACK, CACA_BLACK); + caca_fill_box(screen_list->cv, 0, 0, w, h, '#'); + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_DEFAULT); + caca_draw_cp437_box(screen_list->cv, 0, 0, w, h); + + caca_printf(screen_list->cv, 2, 1, "Num Name"); + for (i = 0; i < screen_list->count; i++) + { + char line[1024]; + if (screen_list->modals.cur_in_list == i) + caca_set_color_ansi(screen_list->cv, CACA_BLACK, CACA_WHITE); + else + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_DEFAULT); + sprintf(line, "%d %s", i + 1, screen_list->screen[i]->title); + + caca_printf(screen_list->cv, 2, i + 3, line); + } +} + +/* Close a window by animating it collapsing */ +/* Total close time */ +#define DELAY 500000.0f +int close_screen_recurrent(struct screen_list *screen_list, + struct recurrent *rec, void *user, + long long unsigned int t) +{ + long long unsigned int delta = t - rec->start_time; + + screen_list->dont_update_coords = 1; + screen_list->delay = 0; + rec->kill_me = 0; + if (delta >= DELAY || (!screen_list->eyecandy)) + { + rec->kill_me = 1; + remove_screen(screen_list, screen_list->pty, 1); + screen_list->pty = screen_list->prevpty>screen_list->count?screen_list->count:screen_list->prevpty; + screen_list->prevpty = 0; + screen_list->dont_update_coords = 0; + } + else + { + float r = 1 - ((DELAY - (DELAY - delta)) / DELAY); + caca_canvas_t *old, *new; + struct screen *s = screen_list->screen[screen_list->pty]; + int w = s->orig_w * r; + int h = s->orig_h * r; + + /* libcaca canvas resize function is bugged, do it by hand */ + old = s->cv; + new = caca_create_canvas(w, h); + caca_blit(new, 0, 0, old, NULL); + s->cv = new; + caca_free_canvas(old); + set_tty_size(s->fd, w, h); + + s->w = w; + s->h = h; + + s->x = (s->orig_x * r) + ((s->orig_w / 2) - s->w / 2); + s->y = (s->orig_y * r) + ((s->orig_h / 2) - s->h / 2); + } + screen_list->changed = 1; + return 1; +} diff --git a/neercs/old/grab.c b/neercs/old/grab.c new file mode 100644 index 0000000..a3f1c31 --- /dev/null +++ b/neercs/old/grab.c @@ -0,0 +1,393 @@ +/* + * neercs console-based window manager + * Copyright (c) 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#define _XOPEN_SOURCE 500 /* getsid() */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined HAVE_LINUX_KDEV_T_H +# include +# include +#endif + +#include "neercs.h" +#include "mytrace.h" + +int grab_process(long pid, char *ptyname, int ptyfd, int *newpid) +{ +#if defined HAVE_LINUX_KDEV_T_H + char fdstr[1024]; + struct mytrace *parent, *child; + int i = 0, fd = 0, ret; + char to_open[128]; + int mode[128]; + int fds[128]; + struct stat stat_buf; + struct termios tos; + int validtos = 0; + DIR *fddir; + struct dirent *fddirent; + + debug("pty is %s", ptyname); + + parent = mytrace_attach(pid); + if (!parent) + { + fprintf(stderr, "Cannot access process %ld\n", pid); + return -1; + } + + child = mytrace_fork(parent); + + snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd", pid); + fddir = opendir(fdstr); + + /* Look for file descriptors that are PTYs */ + while ((fddirent = readdir(fddir)) && i < (int)sizeof(to_open) - 1) + { + fd = atoi(fddirent->d_name); + fds[i] = fd; + to_open[i] = 0; + lstat(fdstr, &stat_buf); + if ((stat_buf.st_mode & S_IRUSR) && (stat_buf.st_mode & S_IWUSR)) + mode[i] = O_RDWR; + else if (stat_buf.st_mode & S_IWUSR) + mode[i] = O_WRONLY; + else + mode[i] = O_RDONLY; + + snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd/%s", pid, + fddirent->d_name); + + if (stat(fdstr, &stat_buf) < 0) + continue; + + if (!S_ISCHR(stat_buf.st_mode) + || MAJOR(stat_buf.st_rdev) != UNIX98_PTY_SLAVE_MAJOR) + continue; + + debug("found pty %d for pid %d", fd, pid); + + if (!validtos) + { + ret = mytrace_tcgets(child, fd, &tos); + if (ret < 0) + { + perror("mytrace_tcgets"); + } + else + { + validtos = 1; + } + } + to_open[i] = 1; + i++; + } + closedir(fddir); + + if (i >= (int)sizeof(to_open) - 1) + { + fprintf(stderr, "too many open pty\n"); + mytrace_detach(child); + return -1; + } + + ret = mytrace_exec(parent, "/usr/bin/reset"); + if (ret < 0) + mytrace_exit(parent, 0); + mytrace_detach(parent); + waitpid(pid, NULL, 0); /* Wait for reset to finish before displaying */ + mytrace_write(child, 2, "\033[H\033[2J", 7); + mytrace_write(child, 2, "\n[Process stolen by neercs]\r\n\n", 30); + + pid = mytrace_getpid(child); + *newpid = pid; + + /* Set the process's session ID */ + debug("Running setsid on process %ld (sid=%d)", pid, getsid(pid)); + + ret = mytrace_setpgid(child, 0, getsid(pid)); + if (ret < 0) + { + fprintf(stderr, "syscall setpgid failed\n"); + mytrace_detach(child); + return -1; + } + + if (ret != 0) + { + fprintf(stderr, "setpgid returned %d\n", ret); + mytrace_detach(child); + return -1; + } + + ret = mytrace_setsid(child); + if (ret < 0) + { + fprintf(stderr, "syscall setsid failed\n"); + mytrace_detach(child); + return -1; + } + + debug("pid %ld has now sid %d", pid, getsid(pid)); + + /* Reopen PTY file descriptors */ + for (; i >= 0; i--) + { + if (!to_open[i]) + continue; + ret = mytrace_close(child, fds[i]); + if (ret < 0) + { + perror("mytrace_close"); + continue; + } + fd = mytrace_open(child, ptyname, mode[i]); + if (fd < 0) + { + perror("mytrace_open"); + continue; + } + + /* FIXME Only needed once */ + mytrace_sctty(child, fd); + + if (validtos) + { + ret = mytrace_tcsets(child, fd, &tos); + if (ret < 0) + { + perror("mytrace_tcsets"); + } + validtos = 0; + } + ret = mytrace_dup2(child, fd, fds[i]); + if (ret < 0) + { + perror("mytrace_dup2"); + } + } + + kill(pid, SIGWINCH); + mytrace_detach(child); + + close(ptyfd); + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} + +struct process +{ + long pid; + char *cmdline; +}; + +static int list_process(struct process **process_list) +{ + glob_t pglob; + unsigned int i, n = 0; + glob("/proc/[0-9]*", GLOB_NOSORT, NULL, &pglob); + *process_list = malloc(pglob.gl_pathc * sizeof(struct process)); + for (i = 0; i < pglob.gl_pathc; i++) + { + glob_t pglob2; + unsigned int j; + char *fds; + (*process_list)[n].pid = atoi(basename(pglob.gl_pathv[i])); + /* Don't allow grabbing ourselves */ + if ((*process_list)[n].pid == getpid()) + continue; + /* FIXME check value of r */ + int r = asprintf(&fds, "%s/fd/*", pglob.gl_pathv[i]); + (void) r; + glob(fds, GLOB_NOSORT, NULL, &pglob2); + free(fds); + for (j = 0; j < pglob2.gl_pathc; j++) + { + char path[4096]; + ssize_t l = readlink(pglob2.gl_pathv[j], path, sizeof(path)); + if (l <= 0) + continue; + path[l] = '\0'; + if (strstr(path, "/dev/pt")) + { + char *cmdfile; + int fd; + /* FIXME check value of r */ + r = asprintf(&cmdfile, "%s/cmdline", pglob.gl_pathv[i]); + (void) r; + fd = open(cmdfile, O_RDONLY); + free(cmdfile); + if (fd) + { + /* FIXME check value of r */ + r = read(fd, path, sizeof(path)); + (void) r; + (*process_list)[n].cmdline = strdup(path); + close(fd); + n++; + break; + } + } + } + globfree(&pglob2); + } + globfree(&pglob); + return n; +} + +long select_process(struct screen_list *screen_list) +{ + caca_event_t ev; + enum caca_event_type t; + int current_line = 1; + int refresh = 1; + int nb_process, i; + int ret = 0; + int start = 0; + struct process *process_list; + + nb_process = list_process(&process_list); + + screen_list->cv = caca_create_canvas(0, 0); + screen_list->dp = caca_create_display(screen_list->cv); + if (!screen_list->dp) + goto end; + caca_set_cursor(screen_list->dp, 0); + caca_set_display_title(screen_list->dp, PACKAGE_STRING); + while (1) + { + if (refresh) + { + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + caca_fill_box(screen_list->cv, + 0, 0, + caca_get_canvas_width(screen_list->cv), + caca_get_canvas_height(screen_list->cv), '#'); + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE); + caca_draw_cp437_box(screen_list->cv, + 0, 0, + caca_get_canvas_width(screen_list->cv), + caca_get_canvas_height(screen_list->cv)); + caca_printf(screen_list->cv, 2, 2, + "Please select a process to grab:"); + for (i = 0; + i < nb_process + && i < caca_get_canvas_height(screen_list->cv) - 4; i++) + { + if (i == current_line - 1) + { + caca_set_attr(screen_list->cv, CACA_BOLD); + caca_set_color_ansi(screen_list->cv, CACA_GREEN, + CACA_BLUE); + caca_put_char(screen_list->cv, 1, i + 3, '>'); + } + else + { + caca_set_attr(screen_list->cv, 0); + caca_set_color_ansi(screen_list->cv, CACA_LIGHTGRAY, + CACA_BLUE); + caca_put_char(screen_list->cv, 1, i + 3, ' '); + } + caca_printf(screen_list->cv, + 3, i + 3, + "%5d %s", + process_list[i + start].pid, + process_list[i + start].cmdline); + } + caca_refresh_display(screen_list->dp); + refresh = 0; + } + + if (!caca_get_event(screen_list->dp, + CACA_EVENT_KEY_PRESS + | CACA_EVENT_RESIZE | CACA_EVENT_QUIT, &ev, 10000)) + continue; + + t = caca_get_event_type(&ev); + + if (t & CACA_EVENT_KEY_PRESS) + { + unsigned int c = caca_get_event_key_ch(&ev); + switch (c) + { + case CACA_KEY_UP: + if (current_line > 1) + current_line--; + if (current_line < start && start > 0) + start--; + break; + case CACA_KEY_DOWN: + if (current_line < nb_process) + current_line++; + if (current_line > + start + caca_get_canvas_height(screen_list->cv) - 3) + start++; + break; + case CACA_KEY_RETURN: + ret = process_list[current_line - 1].pid; + goto end; + break; + case CACA_KEY_ESCAPE: + goto end; + break; + default: + break; + } + refresh = 1; + } + else if (t & CACA_EVENT_RESIZE) + { + refresh = 1; + } + else if (t & CACA_EVENT_QUIT) + goto end; + } + + end: + if (screen_list->dp) + { + caca_free_display(screen_list->dp); + screen_list->dp = NULL; + } + if (screen_list->cv) + { + caca_free_canvas(screen_list->cv); + screen_list->cv = NULL; + } + if (nb_process > 0) + { + for (i = 0; i < nb_process; i++) + { + free(process_list[i].cmdline); + } + free(process_list); + } + return ret; +} diff --git a/neercs/old/help.c b/neercs/old/help.c new file mode 100644 index 0000000..253ff53 --- /dev/null +++ b/neercs/old/help.c @@ -0,0 +1,76 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "neercs.h" + +int help_handle_key(struct screen_list *screen_list, unsigned int c) +{ + if (c == CACA_KEY_ESCAPE || c == '?') + { + screen_list->modals.help = 0; + screen_list->changed = 1; + return 1; + } + else + { + return 0; + } +} + +void draw_help(struct screen_list *screen_list) +{ + int w = 65, h = 20; + int x = (caca_get_canvas_width(screen_list->cv) - w) / 2; + int y = (caca_get_canvas_height(screen_list->cv) - h) / 2; + + + caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE); + caca_fill_box(screen_list->cv, x, y, w, h, '#'); + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE); + caca_draw_cp437_box(screen_list->cv, x, y, w, h); + + x += 2; + y++; + caca_printf(screen_list->cv, + (caca_get_canvas_width(screen_list->cv) - + strlen(PACKAGE_STRING)) / 2, y - 1, PACKAGE_STRING); + caca_printf(screen_list->cv, x, y++, "Copyright (c) 2006-2010"); + caca_printf(screen_list->cv, x, y++, " Sam Hocevar "); + caca_printf(screen_list->cv, x, y++, " Jean-Yves Lamoureux "); + caca_printf(screen_list->cv, x, y++, " Pascal Terjan "); + caca_printf(screen_list->cv, x, y++, ""); + caca_printf(screen_list->cv, x, y++, ""); + caca_printf(screen_list->cv, x, y++, "All shortcuts are in format 'ctrl-a-X' where X is :"); + caca_printf(screen_list->cv, x, y++, "n: Next window"); + caca_printf(screen_list->cv, x, y++, "p: Previous window"); + caca_printf(screen_list->cv, x, y++, "w: Switch window manager"); + caca_printf(screen_list->cv, x, y++, "c: Create new window"); + caca_printf(screen_list->cv, x, y++, "m: Thumbnails"); + caca_printf(screen_list->cv, x, y++, "d: Detach"); + caca_printf(screen_list->cv, x, y++, "k: Close window and kill associated process"); + caca_printf(screen_list->cv, x, y++, "h: Dump screen into a file"); + caca_printf(screen_list->cv, x, y++, "?: This help"); + caca_printf(screen_list->cv, x, y++, ""); + caca_printf(screen_list->cv, x, y++, ""); + caca_printf(screen_list->cv, x, y, "See http://caca.zoy.org/wiki/neercs for more informations"); +} diff --git a/neercs/old/input.c b/neercs/old/input.c new file mode 100644 index 0000000..d36b5e7 --- /dev/null +++ b/neercs/old/input.c @@ -0,0 +1,192 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include "config.h" +#include +#include +#include "neercs.h" + +struct kconv +{ + unsigned int key; + char *val; + int size; +}; + +struct kconv kconv[] = { + {CACA_KEY_UP, "\033OA", 3}, + {CACA_KEY_DOWN, "\033OB", 3}, + {CACA_KEY_RIGHT, "\033OC", 3}, + {CACA_KEY_LEFT, "\033OD", 3}, + {CACA_KEY_PAGEUP, "\033[5~", 4}, + {CACA_KEY_PAGEDOWN, "\033[6~", 4}, + {CACA_KEY_HOME, "\033[1~", 4}, + {CACA_KEY_INSERT, "\033[2~", 4}, + {CACA_KEY_DELETE, "\033[3~", 4}, + {CACA_KEY_END, "\033[4~", 4}, + {CACA_KEY_F1, "\033[11~", 5}, + {CACA_KEY_F2, "\033[12~", 5}, + {CACA_KEY_F3, "\033[13~", 5}, + {CACA_KEY_F4, "\033[14~", 5}, + {CACA_KEY_F5, "\033[15~", 5}, + {CACA_KEY_F6, "\033[17~", 5}, + {CACA_KEY_F7, "\033[18~", 5}, + {CACA_KEY_F8, "\033[19~", 5}, + {CACA_KEY_F9, "\033[20~", 5}, + {CACA_KEY_F10, "\033[21~", 5}, + {CACA_KEY_F11, "\033[23~", 5}, + {CACA_KEY_F12, "\033[24~", 5}, +}; + + + +void *convert_input_ansi(unsigned int *c, int *size) +{ + unsigned int i; + for (i = 0; i < sizeof(kconv) / sizeof(struct kconv); i++) + { + if (*c == kconv[i].key) + { + *size = kconv[i].size; + return kconv[i].val; + } + } + + *size = 1; + return c; +} + + + +int handle_command_input(struct screen_list *screen_list, unsigned int c) +{ + int refresh = 0; + + debug("Key %x\n", c); + screen_list->changed = 1; + + if (c >= '0' && c <= '9') + { + int n = c - 49; + if (n < screen_list->count) + { + screen_list->prevpty = screen_list->pty; + screen_list->pty = n == -1 ? 10 : n; + return 1; + } + else + { + return 0; + } + } + + switch (c) + { + case 0x01: // CACA_KEY_CTRL_A: + screen_list->pty ^= screen_list->prevpty; + screen_list->prevpty ^= screen_list->pty; + screen_list->pty ^= screen_list->prevpty; + refresh = 1; + break; + case 'm': + case 0x0d: // CACA_KEY_CTRL_M: + screen_list->modals.mini = !screen_list->modals.mini; + refresh = 1; + break; + case 'n': + case ' ': + case '\0': + case 0x0e: // CACA_KEY_CTRL_N: + screen_list->prevpty = screen_list->pty; + screen_list->pty = (screen_list->pty + 1) % screen_list->count; + if (screen_list->pty != screen_list->prevpty) + { + screen_list->last_switch = get_us(); + screen_list->cube.in_switch = 1; + screen_list->cube.side = 0; + } + refresh = 1; + break; + case 'p': + case 0x10: // CACA_KEY_CTRL_P: + screen_list->prevpty = screen_list->pty; + screen_list->pty = + (screen_list->pty + screen_list->count - 1) % screen_list->count; + if (screen_list->pty != screen_list->prevpty) + { + screen_list->last_switch = get_us(); + screen_list->cube.in_switch = 1; + screen_list->cube.side = 1; + } + refresh = 1; + break; + case 'c': + case 0x03: // CACA_KEY_CTRL_C: + screen_list->prevpty = screen_list->pty; + screen_list->pty = + add_screen(screen_list, + create_screen(screen_list->width, + screen_list->height, + screen_list->sys.default_shell)); + refresh = 1; + break; + case 'w': + case 0x17: // CACA_KEY_CTRL_W: + screen_list->wm_type = (screen_list->wm_type == (WM_MAX - 1) ? + screen_list->wm_type = 0 : + screen_list->wm_type + 1); + refresh = 1; + break; + case 'k': + case 0x0b: // CACA_KEY_CTRL_K: + add_recurrent(screen_list->recurrent_list, close_screen_recurrent, + screen_list->cv); + refresh = 1; + break; + case 'x': + case 0x18: // CACA_KEY_CTRL_X: + memset(screen_list->lock.lockpass, 0, 1024); + screen_list->lock.locked = 1; + screen_list->lock.lock_offset = 0; + refresh = 1; + break; + case 'h': + case 0x08: // CACA_KEY_CTRL_H: + dump_to_file(screen_list); + break; + case '?': + screen_list->modals.help = !screen_list->modals.help; + refresh = 1; + break; + case '"': + case 0x34: // CTRL+" + screen_list->modals.cur_in_list = screen_list->pty; + screen_list->modals.window_list = !screen_list->modals.window_list; + refresh = 1; + break; + case 'd': + case 0x04: // CACA_KEY_CTRL_D: + detach(screen_list); + break; +#ifdef USE_PYTHON + case 'e': + case 0x05: + debug("py : command is %d, setting to 1 (at %p)\n", screen_list->modals.python_command, &screen_list->modals.python_command); + screen_list->modals.python_command = 1; + refresh = 1; + break; +#endif + } + return refresh; + +} diff --git a/neercs/old/lock.c b/neercs/old/lock.c new file mode 100644 index 0000000..925c297 --- /dev/null +++ b/neercs/old/lock.c @@ -0,0 +1,221 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined USE_LOCK +#if defined HAVE_PAM_PAM_MISC_H +# include +# include +#else +# include +# include +#endif +# include +#endif + +#include "neercs.h" + +#if defined USE_LOCK +static int convpam(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr); +#endif + +int update_lock(int c, struct screen_list *screen_list) +{ + int refresh = 0; + +#if defined USE_LOCK + if (!screen_list->lock.locked) + return 0; + + if (c == 0x08) // BACKSPACE + { + if (screen_list->lock.lock_offset) + { + screen_list->lock.lockpass[screen_list->lock.lock_offset - 1] = 0; + screen_list->lock.lock_offset--; + } + } + else if (c == 0x0d) // RETURN + { + memset(screen_list->lock.lockmsg, 0, 1024); + if (validate_lock(screen_list, getenv("USER"), screen_list->lock.lockpass)) + { + memset(screen_list->lock.lockpass, 0, 1024); + screen_list->lock.locked = 0; + screen_list->lock.lock_offset = 0; + refresh = 1; + } + else + { + memset(screen_list->lock.lockpass, 0, 1024); + screen_list->lock.lock_offset = 0; + refresh = 1; + } + } + else + { + if (screen_list->lock.lock_offset < 1023) + { + screen_list->lock.lockpass[screen_list->lock.lock_offset++] = c; + screen_list->lock.lockpass[screen_list->lock.lock_offset] = 0; + } + } +#endif + + return refresh; +} + +void draw_lock(struct screen_list *screen_list) +{ +#if defined USE_LOCK + unsigned int i; + char buffer[1024]; + caca_canvas_t *cv = screen_list->cv; + + gethostname(buffer, sizeof(buffer) - 1); + + int w = 65, h = 20; + int x = (caca_get_canvas_width(cv) - w) / 2; + int y = (caca_get_canvas_height(cv) - h) / 2; + + + caca_set_color_ansi(cv, CACA_BLUE, CACA_BLUE); + caca_fill_box(cv, x, y, w, h, '#'); + caca_set_color_ansi(cv, CACA_DEFAULT, CACA_BLUE); + caca_draw_cp437_box(cv, x, y, w, h); + + x += 2; + y++; + caca_printf(cv, + (caca_get_canvas_width(cv) - + strlen(PACKAGE_STRING " locked")) / 2, y - 1, + PACKAGE_STRING " locked"); + + caca_printf(cv, x, y++, "Please type in your password for %s@%s :", + getenv("USER"), buffer); + y += 2; + + x = (caca_get_canvas_width(cv) / 2) - + ((strlen(screen_list->lock.lockpass) / 2) + strlen("Password : ")); + caca_printf(cv, x, y, "Password : "); + x += strlen("Password : "); + for (i = 0; i < strlen(screen_list->lock.lockpass); i++) + { + caca_put_str(cv, x, y, "*"); + x++; + } + + + if (strlen(screen_list->lock.lockmsg)) + { + x = ((caca_get_canvas_width(cv) - w) / 2) + + (strlen(screen_list->lock.lockmsg)); + y += 2; + caca_set_color_ansi(cv, CACA_RED, CACA_BLUE); + caca_printf(cv, x, y, "Error : %s", screen_list->lock.lockmsg); + } +#endif +} + + +#if defined USE_LOCK + +/* FIXME, handle this without assuming this is a password auth */ +static int convpam(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + + struct pam_response *aresp; + int i; + aresp = calloc(num_msg, sizeof(*aresp)); + + for (i = 0; i < num_msg; ++i) + { + switch (msg[i]->msg_style) + { + case PAM_PROMPT_ECHO_ON: + case PAM_PROMPT_ECHO_OFF: + aresp[i].resp = strdup(appdata_ptr); + aresp[i].resp_retcode = 0; + break; + case PAM_ERROR_MSG: + break; + default: + printf("Unknow message type from PAM\n"); + break; + } + } + + *resp = aresp; + return (PAM_SUCCESS); +} +#endif + +int validate_lock(struct screen_list *screen_list, char *user, char *pass) +{ +#if USE_LOCK + int ret; + pam_handle_t *pamh = NULL; + char buffer[100]; + const char *service = "neercs"; + struct pam_conv conv = { + convpam, + pass, + }; + + ret = pam_start(service, user, &conv, &pamh); + if (ret != PAM_SUCCESS) + return 0; + pam_set_item(pamh, PAM_RUSER, user); + + ret = gethostname(buffer, sizeof(buffer) - 1); + if (ret) + { + perror("failed to look up hostname"); + ret = pam_end(pamh, PAM_ABORT); + sprintf(screen_list->lock.lockmsg, "Can't get hostname"); + pam_end(pamh, PAM_SUCCESS); + return 0; + } + + ret = pam_set_item(pamh, PAM_RHOST, buffer); + if (ret != PAM_SUCCESS) + { + sprintf(screen_list->lock.lockmsg, "Can't set hostname"); + pam_end(pamh, PAM_SUCCESS); + return 0; + } + + ret = pam_authenticate(pamh, 0); + if (ret != PAM_SUCCESS) + { + sprintf(screen_list->lock.lockmsg, "Can't authenticate"); + pam_end(pamh, PAM_SUCCESS); + return 0; + } + + ret = pam_end(pamh, PAM_SUCCESS); +#endif + + return 1; +} diff --git a/neercs/old/main.c b/neercs/old/main.c new file mode 100644 index 0000000..621fcdf --- /dev/null +++ b/neercs/old/main.c @@ -0,0 +1,324 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#if !defined HAVE_GETOPT_LONG +# include "mygetopt.h" +#elif defined HAVE_GETOPT_H +# include +#endif +#if defined HAVE_GETOPT_LONG +# define mygetopt getopt_long +# define myoptind optind +# define myoptarg optarg +# define myoption option +#endif +#include +#include + +#include "neercs.h" + + +void version(void) +{ + printf("%s\n", PACKAGE_STRING); + printf("Copyright (C) 2006, 2008 Sam Hocevar \n"); + printf + (" Jean-Yves Lamoureux \n\n"); + printf + ("This is free software. You may redistribute copies of it under the\n"); + printf + ("terms of the Do What The Fuck You Want To Public License, Version 2\n"); + printf(".\n"); + printf("There is NO WARRANTY, to the extent permitted by law.\n"); + printf("\n"); + printf + ("For more informations, visit http://libcaca.zoy.org/wiki/neercs\n"); +} + +void usage(int argc, char **argv) +{ + printf("%s\n", PACKAGE_STRING); + printf("Usage : %s [command1] [command2] ... [commandN]\n", argv[0]); + printf("Example : %s zsh top \n\n", argv[0]); + printf("Options :\n"); + printf("\t--config\t-c \t\tuse given config file\n"); + printf("\t--pid\t\t-P [pid]\t\tgrab process\n"); + printf("\t\t\t-r [session]\t\treattach to a detached neercs\n"); + printf + ("\t\t\t-R [session]\t\treattach if possible, otherwise start a new session\n"); + printf("\t\t\t-S \t\tname this session instead of \n"); + printf("\t--lock-after\t-l [n]\t\t\tlock screen after n seconds\n"); + printf("\t--version\t-v \t\t\tdisplay version and exit\n"); + printf("\t--help\t\t-h \t\t\tthis help\n"); +} + +#if 0 +int main(int argc, char **argv) +{ + struct screen_list *screen_list = init_neercs(argc, argv); + if (!screen_list) + return -1; + + mainloop(screen_list); +} +#endif + +struct screen_list *init_neercs(int argc, char **argv) +{ + struct screen_list *screen_list = NULL; + int args; + + int mainret = -1; + + screen_list = create_screen_list(); + screen_list->sys.default_shell = getenv("SHELL"); + + args = argc - 1; + if (screen_list->sys.default_shell == NULL && args <= 0) + { + fprintf(stderr, + "Environment variable SHELL not set and no arguments given. kthxbye.\n"); + free_screen_list(screen_list); + return NULL; + } + + if (handle_command_line(argc, argv, screen_list) < 0) + { + free_screen_list(screen_list); + return NULL; + } + + /* Read global configuration first */ + read_configuration_file("/etc/neercsrc", screen_list); + + /* Then local one */ + if (screen_list->sys.user_path) + { + read_configuration_file(screen_list->sys.user_path, screen_list); + free(screen_list->sys.user_path); + } + + if (screen_list->sys.attach) + { + if (screen_list->sys.nb_to_grab || screen_list->sys.to_start) + { + fprintf(stderr, + "-R can not be associated with commands or pids!\n"); + free_screen_list(screen_list); + return NULL; + } + + attach(screen_list); + + if (screen_list->sys.forceattach && !screen_list->sys.attach) + { + free_screen_list(screen_list); + return NULL; + } + } + + /* Build default session name */ + if (!screen_list->comm.session_name) + { + char mypid[32]; /* FIXME Compute the length of PID_MAX ? */ + snprintf(mypid, 31, "%d", getpid()); + mypid[31] = '\0'; + screen_list->comm.session_name = strdup(mypid); + if (!screen_list->comm.session_name) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + free_screen_list(screen_list); + return NULL; + } + } + if (!screen_list->comm.socket_path[SOCK_CLIENT]) + screen_list->comm.socket_path[SOCK_CLIENT] = + build_socket_path(screen_list->comm.socket_dir, + screen_list->comm.session_name, SOCK_CLIENT); + + if (!screen_list->comm.socket_path[SOCK_SERVER]) + screen_list->comm.socket_path[SOCK_SERVER] = + build_socket_path(screen_list->comm.socket_dir, + screen_list->comm.session_name, SOCK_SERVER); + + /* Fork the server if needed */ + if (!screen_list->sys.attach) + { + debug("Spawning a new server"); + if (start_server(screen_list)) + { + free_screen_list(screen_list); + return NULL; + } + if (start_client(screen_list)) + { + free_screen_list(screen_list); + return NULL; + } + } + + return screen_list; +} + +int handle_command_line(int argc, char *argv[], + struct screen_list *screen_list) +{ + int s = 0, i; + for (;;) + { + int option_index = 0; + int pidopt; + static struct myoption long_options[] = { + {"config", 1, NULL, 'c'}, +#if defined USE_GRAB + {"pid", 0, NULL, 'P'}, +#endif + {"lock-after", 1, NULL, 'l'}, + {"help", 0, NULL, 'h'}, + {"version", 0, NULL, 'v'}, + {NULL, 0, NULL, 0}, + }; +#if defined USE_GRAB + int c = + mygetopt(argc, argv, "c:S:R::l::r::P::hv", long_options, + &option_index); +#else + int c = + mygetopt(argc, argv, "c:S:R::l::r::hv", long_options, + &option_index); +#endif + if (c == -1) + break; + + switch (c) + { + case 'c': /* --config */ + if (screen_list->sys.user_path) + free(screen_list->sys.user_path); + screen_list->sys.user_path = strdup(myoptarg); + s += 2; + break; + case 'S': + if (!screen_list->comm.session_name) + screen_list->comm.session_name = strdup(myoptarg); + s += 2; + break; + case 'P': /* --pid */ + if (myoptarg) + { + pidopt = atoi(myoptarg); + if (pidopt <= 0) + { + fprintf(stderr, "Invalid pid %d\n", pidopt); + if (screen_list->sys.to_grab) + free(screen_list->sys.to_grab); + return -1; + } + } + else + pidopt = select_process(screen_list); + if (pidopt <= 0) + { + s += 1; + break; + } + if (!screen_list->sys.to_grab) + { + /* At most argc-1-s times -P + final 0 */ + screen_list->sys.to_grab = + (int *)malloc(((argc - 1 - s) / 2 + 1) * sizeof(int)); + if (!screen_list->sys.to_grab) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + return -1; + } + } + screen_list->sys.to_grab[screen_list->sys.nb_to_grab++] = pidopt; + screen_list->sys.to_grab[screen_list->sys.nb_to_grab] = 0; + s += 2; + break; + case 'l': + screen_list->lock.autolock_timeout = atoi(myoptarg) * 1000000; + if (screen_list->lock.autolock_timeout == 0) + screen_list->lock.autolock_timeout -= 1; + break; + case 'r': + screen_list->sys.forceattach = 1; + case 'R': + if (screen_list->sys.attach) + { + fprintf(stderr, "Attaching can only be requested once\n"); + return -1; + } + if (myoptarg) + { + if (screen_list->comm.session_name) + free(screen_list->comm.session_name); + screen_list->comm.session_name = strdup(myoptarg); + s += 1; + } + screen_list->sys.attach = 1; + s += 1; + break; + case 'h': /* --help */ + usage(argc, argv); + return -1; + break; + case 'v': /* --version */ + version(); + return -1; + break; + case -2: + return -1; + default: + fprintf(stderr, "Unknown argument #%d\n", myoptind); + return -1; + break; + } + } + if (s >= 0 && s < argc - 1) + { + screen_list->sys.to_start = (char **)malloc((argc - s) * sizeof(char *)); + if (!screen_list->sys.to_start) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + return -1; + } + for (i = 0; i < (argc - 1) - s; i++) + { + screen_list->sys.to_start[i] = strdup(argv[i + s + 1]); + } + screen_list->sys.to_start[argc - 1 - s] = NULL; + } + return s; +} diff --git a/neercs/old/mini-client.c b/neercs/old/mini-client.c new file mode 100644 index 0000000..ed06f8f --- /dev/null +++ b/neercs/old/mini-client.c @@ -0,0 +1,94 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2011 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* BUFSIZ */ +#include /* strncmp() */ + +#include + +#include "mini-neercs.h" +#include "mini-socket.h" + +static caca_display_t *dp; +static caca_canvas_t *cv; +static nrx_socket_t *insock, *outsock; + +void client_init(void) +{ + int i, usec = 10000; + + cv = caca_create_canvas(0, 0); + dp = caca_create_display(cv); + caca_set_display_title(dp, "Press Esc to quit"); + + insock = socket_open("/tmp/neercs.sock.client", 1); + + for (i = 0; i < 10; i++) + { + outsock = socket_open("/tmp/neercs.sock", 0); + if (outsock) + break; + usleep(usec); + usec += usec; + } + + socket_puts(outsock, "CONNECT /tmp/neercs.sock.client"); +} + +int client_step(void) +{ + caca_event_t ev; + int ret; + + /* Handle client sockets */ + ret = socket_select(insock, 1000); + if (ret > 0) + { + char buf[BUFSIZ]; + ssize_t bytes = socket_read(insock, buf, BUFSIZ); + if (bytes <= 0) + return 1; + + /* Parse message */ + if (!strncmp(buf, "OK", strlen("OK"))) + { + fprintf(stderr, "neercs: connection established\n"); +socket_puts(insock, "TEST insock"); + } + } + + /* Handle libcaca events */ + if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 1000) + && caca_get_event_key_ch(&ev) == CACA_KEY_ESCAPE) + return 0; + + return 1; +} + +void client_fini(void) +{ + socket_puts(outsock, "QUIT /tmp/neercs.sock.client"); + + caca_free_display(dp); + caca_free_canvas(cv); + if (insock) + socket_close(insock); + if (outsock) + socket_close(outsock); +} + diff --git a/neercs/old/mini-neercs.c b/neercs/old/mini-neercs.c new file mode 100644 index 0000000..bfb7003 --- /dev/null +++ b/neercs/old/mini-neercs.c @@ -0,0 +1,52 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include /* perror() */ +#include /* fork() */ + +#include "mini-neercs.h" + +int main(void) +{ + pid_t pid; + + pid = fork(); + + if (pid < 0) + { + perror("fork"); + return EXIT_FAILURE; + } + + if (pid > 0) + { + client_init(); + while(client_step()) ; + client_fini(); + } + else + { + server_init(); + while(server_step()) ; + server_fini(); + } + + return EXIT_SUCCESS; +} + diff --git a/neercs/old/mini-neercs.h b/neercs/old/mini-neercs.h new file mode 100644 index 0000000..d898a8b --- /dev/null +++ b/neercs/old/mini-neercs.h @@ -0,0 +1,22 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +void client_init(void); +int client_step(void); +void client_fini(void); + +void server_init(void); +int server_step(void); +void server_fini(void); + diff --git a/neercs/old/mini-server.c b/neercs/old/mini-server.c new file mode 100644 index 0000000..5dd556d --- /dev/null +++ b/neercs/old/mini-server.c @@ -0,0 +1,80 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2011 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* BUFSIZ */ +#include /* strncmp() */ + +#include "mini-neercs.h" +#include "mini-socket.h" + +static nrx_socket_t *insock, *outsock; + +void server_init(void) +{ +while (!insock) + insock = socket_open("/tmp/neercs.sock", 1); +} + +int server_step(void) +{ + char buf[BUFSIZ]; + ssize_t bytes; + int ret; + + if (outsock) + { + ret = socket_select(outsock, 1000); + if (ret <= 0) + goto nothing; + + bytes = socket_read(outsock, buf, BUFSIZ); + if (bytes <= 0) + goto nothing; + } +nothing: + + ret = socket_select(insock, 1000); + if (ret <= 0) + return 1; + + bytes = socket_read(insock, buf, BUFSIZ); + if (bytes <= 0) + return 1; + + /* Parse message */ + if (!strncmp(buf, "CONNECT ", strlen("CONNECT "))) + { + outsock = socket_open(buf + strlen("CONNECT "), 0); + socket_puts(outsock, "OK"); + } + else if (!strncmp(buf, "QUIT ", strlen("QUIT "))) + { + return 0; + } + + return 1; +} + +void server_fini(void) +{ + if (insock) + socket_close(insock); + if (outsock) + socket_close(outsock); +} + diff --git a/neercs/old/mini-socket.c b/neercs/old/mini-socket.c new file mode 100644 index 0000000..3d303a5 --- /dev/null +++ b/neercs/old/mini-socket.c @@ -0,0 +1,297 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2011 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* perror() */ +#include /* malloc(), free() */ +#include /* unlink() */ +#include /* fcntl() */ +#include /* memcpy() */ +#include /* select() */ +#include /* bind(), connect() */ +#include /* bind(), connect() */ +#include /* stat(), struct stat */ +#include /* AF_UNIX */ +#include /* AF_UNIX */ +#include /* time */ + +#include "mini-neercs.h" +#include "mini-socket.h" + +#define SIZEOF_SUN_PATH (sizeof(((struct sockaddr_un *)NULL)->sun_path)) + +#define offsetof(s, f) ((int)(intptr_t)((s *)NULL)->f) + +struct nrx_socket +{ +#if 1 + /* Linux sockets */ + int fd; + int server; + int connected; + char path[SIZEOF_SUN_PATH]; +#else +# error No socket implementation +#endif +}; + +#define QLEN 10 + +int +serv_listen(const char *name) +{ + int fd, len, err, rval; + struct sockaddr_un un; + + /* create a UNIX domain stream socket */ + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return(-1); + unlink(name); /* in case it already exists */ + + /* fill in socket address structure */ + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + strcpy(un.sun_path, name); + len = offsetof(struct sockaddr_un, sun_path) + strlen(name); + + /* bind the name to the descriptor */ + if (bind(fd, (struct sockaddr *)&un, len) < 0) { + rval = -2; + goto errout; + } + if (listen(fd, QLEN) < 0) { /* tell kernel we're a server */ + rval = -3; + goto errout; + } + return(fd); + +errout: + err = errno; + close(fd); + errno = err; + return(rval); +} + +#define STALE 30 /* client's name can't be older than this (sec) */ + +/* + * Wait for a client connection to arrive, and accept it. + * We also obtain the client's user ID from the pathname + * that it must bind before calling us. + * Returns new fd if all OK, <0 on error + */ +int +serv_accept(int listenfd, uid_t *uidptr) +{ + int clifd, len, err, rval; + time_t staletime; + struct sockaddr_un un; + struct stat statbuf; + + len = sizeof(un); + if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0) + return(-1); /* often errno=EINTR, if signal caught */ + + /* obtain the client's uid from its calling address */ + len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */ + un.sun_path[len] = 0; /* null terminate */ + + if (stat(un.sun_path, &statbuf) < 0) { + rval = -2; + goto errout; + } +#ifdef S_ISSOCK /* not defined for SVR4 */ + if (S_ISSOCK(statbuf.st_mode) == 0) { + rval = -3; /* not a socket */ + goto errout; + } +#endif + if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) || + (statbuf.st_mode & S_IRWXU) != S_IRWXU) { + rval = -4; /* is not rwx------ */ + goto errout; + } + + staletime = time(NULL) - STALE; + if (statbuf.st_atime < staletime || + statbuf.st_ctime < staletime || + statbuf.st_mtime < staletime) { + rval = -5; /* i-node is too old */ + goto errout; + } + if (uidptr != NULL) + *uidptr = statbuf.st_uid; /* return uid of caller */ + unlink(un.sun_path); /* we're done with pathname now */ + return(clifd); + +errout: + err = errno; + close(clifd); + errno = err; + return(rval); +} + +#define CLI_PATH "/var/tmp/" /* +5 for pid = 14 chars */ +#define CLI_PERM S_IRWXU /* rwx for user only */ + +/* + * Create a client endpoint and connect to a server. + * Returns fd if all OK, <0 on error. + */ +int +cli_conn(const char *name) +{ + int fd, len, err, rval; + struct sockaddr_un un; + + /* create a UNIX domain stream socket */ + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return(-1); + + /* fill socket address structure with our address */ + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid()); + len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path); + + unlink(un.sun_path); /* in case it already exists */ + if (bind(fd, (struct sockaddr *)&un, len) < 0) { + rval = -2; + goto errout; + } + if (chmod(un.sun_path, CLI_PERM) < 0) { + rval = -3; + goto errout; + } + /* fill socket address structure with server's address */ + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + strcpy(un.sun_path, name); + len = offsetof(struct sockaddr_un, sun_path) + strlen(name); + if (connect(fd, (struct sockaddr *)&un, len) < 0) { + rval = -4; + goto errout; + } + return(fd); + +errout: + err = errno; + close(fd); + errno = err; + return(rval); +} + +nrx_socket_t * socket_open(char const *path, int server) +{ + nrx_socket_t * sock; + struct sockaddr_un addr; + int ret, fd; + +#if 0 + fd = socket(AF_UNIX, SOCK_STREAM, 0); + //fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) + { + perror("socket creation"); + return NULL; + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, SIZEOF_SUN_PATH - 1); + + if (server) + { + unlink(path); + ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + } + else + { + ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + } + + if (ret < 0) + { + perror(server ? "socket binding" : "socket connection"); + close(fd); + return NULL; + } + + fcntl(fd, F_SETFL, O_NONBLOCK); +#endif +if (server) + fd = serv_listen(path); +else + fd = cli_conn(path); +if (fd < 0) return NULL; + + sock = malloc(sizeof(*sock)); + sock->fd = fd; + sock->server = server; + sock->connected = 0; + strncpy(sock->path, path, SIZEOF_SUN_PATH - 1); + + return sock; +} + +int socket_select(nrx_socket_t *sock, int usecs) +{ + fd_set rfds; + struct timeval tv; + int ret; + + FD_ZERO(&rfds); + FD_SET(sock->fd, &rfds); + + tv.tv_sec = usecs / 1000000; + tv.tv_usec = usecs % 1000000; + + ret = select(sock->fd + 1, &rfds, NULL, NULL, &tv); + if (ret < 0) + return -1; + + if (FD_ISSET(sock->fd, &rfds)) + return 1; + + return 0; +} + +int socket_puts(nrx_socket_t *sock, char const *str) +{ + int ret; +fprintf(stderr, "pid %i sending %i bytes on %s: %s\n", getpid(), (int)strlen(str), sock->path, str); + ret = write(sock->fd, str, strlen(str)); + return ret; +} + +ssize_t socket_read(nrx_socket_t *sock, void *buf, size_t count) +{ + int ret; + ret = read(sock->fd, buf, count); +if (ret >= 0) ((char *)buf)[ret] = 0; +if (ret >= 0) fprintf(stderr, "pid %i recving %i bytes on %s: %s\n", getpid(), ret, sock->path, (char *)buf); + return ret; +} + +void socket_close(nrx_socket_t *sock) +{ + close(sock->fd); + if (sock->server) + unlink(sock->path); + free(sock); +} + diff --git a/neercs/old/mini-socket.h b/neercs/old/mini-socket.h new file mode 100644 index 0000000..709e5fa --- /dev/null +++ b/neercs/old/mini-socket.h @@ -0,0 +1,24 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include + +typedef struct nrx_socket nrx_socket_t; + +nrx_socket_t * socket_open(char const *path, int server); +int socket_select(nrx_socket_t *sock, int usecs); +int socket_puts(nrx_socket_t *sock, char const *str); +ssize_t socket_read(nrx_socket_t *sock, void *buf, size_t count); +void socket_close(nrx_socket_t *socket); + diff --git a/neercs/old/mygetopt.c b/neercs/old/mygetopt.c new file mode 100644 index 0000000..44f6863 --- /dev/null +++ b/neercs/old/mygetopt.c @@ -0,0 +1,125 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * mygetopt.c: getopt_long reimplementation + */ + +#include "config.h" + +#include +#include + +#include "caca_types.h" + +#include "mygetopt.h" + +int myoptind = 1; +char *myoptarg = NULL; + +/* XXX: this getopt_long implementation should not be trusted for other + applications without any serious peer reviewing. It “just works” with + zzuf but may fail miserably in other programs. */ +int mygetopt(int argc, char *const _argv[], const char *optstring, + const struct myoption *longopts, int *longindex) +{ + char **argv = (char **)(uintptr_t) _argv; + char *flag; + int i; + + if (myoptind >= argc) + return -1; + + flag = argv[myoptind]; + + if (flag[0] == '-' && flag[1] != '-') + { + char *tmp; + int ret = flag[1]; + + if (ret == '\0') + return -1; + + tmp = strchr(optstring, ret); + if (!tmp || ret == ':') + return '?'; + + myoptind++; + if (tmp[1] == ':') + { + if (flag[2] != '\0') + myoptarg = flag + 2; + else if (myoptind >= argc) + { + if (tmp[2] != ':') + { + fprintf(stderr, "%s: `%s' needs an argument\n", argv[0], + flag); + return -2; + } + } + else + myoptarg = argv[myoptind++]; + return ret; + } + + if (flag[2] != '\0') + { + flag[1] = '-'; + myoptind--; + argv[myoptind]++; + } + + return ret; + } + + if (flag[0] == '-' && flag[1] == '-') + { + if (flag[2] == '\0') + return -1; + + for (i = 0; longopts[i].name; i++) + { + size_t l = strlen(longopts[i].name); + + if (strncmp(flag + 2, longopts[i].name, l)) + continue; + + switch (flag[2 + l]) + { + case '=': + if (!longopts[i].has_arg) + goto bad_opt; + if (longindex) + *longindex = i; + myoptind++; + myoptarg = flag + 2 + l + 1; + return longopts[i].val; + case '\0': + if (longindex) + *longindex = i; + myoptind++; + if (longopts[i].has_arg) + myoptarg = argv[myoptind++]; + return longopts[i].val; + default: + break; + } + } + bad_opt: + fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag); + return '?'; + } + + return -1; +} diff --git a/neercs/old/mygetopt.h b/neercs/old/mygetopt.h new file mode 100644 index 0000000..f5d50a0 --- /dev/null +++ b/neercs/old/mygetopt.h @@ -0,0 +1,30 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * mygetopt.h: getopt_long reimplementation + */ + +struct myoption +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +extern int myoptind; +extern char *myoptarg; + +int mygetopt(int, char * const[], const char *, const struct myoption *, int *); + diff --git a/neercs/old/mytrace.c b/neercs/old/mytrace.c new file mode 100644 index 0000000..7d8a7f0 --- /dev/null +++ b/neercs/old/mytrace.c @@ -0,0 +1,785 @@ +/* + * neercs console-based window manager + * Copyright (c) 2008-2010 Pascal Terjan + * 2008-2010 Sam Hocevar + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#if defined USE_GRAB +# include +# include +# include +# include +# include +# include +#endif + +#include "neercs.h" +#include "mytrace.h" + +#if defined USE_GRAB +static int memcpy_from_target(struct mytrace *t, + char *dest, long src, size_t n); +static int memcpy_into_target(struct mytrace *t, + long dest, char const *src, size_t n); +static long remote_syscall(struct mytrace *t, long call, + long arg1, long arg2, long arg3); +# if defined DEBUG +static void print_registers(pid_t pid); +# else +# define print_registers(x) do {} while(0) +# endif + +#define X(x) #x +#define STRINGIFY(x) X(x) + +#define SYSCALL_X86 0x80cd /* CD 80 = int $0x80 */ +#define SYSCALL_X86_NEW 0xf3eb /* EB F3 = jmp <__kernel_vsyscall+0x3> */ +#define SYSENTER 0x340f /* 0F 34 = sysenter */ +#define SYSCALL_AMD64 0x050fL /* 0F 05 = syscall */ + +#if defined __x86_64__ +# define RAX rax +# define RBX rbx +# define RCX rcx +# define RDX rdx +# define RSP rsp +# define RBP rbp +# define RIP rip +# define RDI rdi +# define RSI rsi +# define FMT "%016lx" +#else +# define RAX eax +# define RBX ebx +# define RCX ecx +# define RDX edx +# define RSP esp +# define RBP ebp +# define RIP eip +# define RDI edi +# define RSI esi +# define FMT "%08lx" +#endif + +#define MYCALL_OPEN 0 +#define MYCALL_CLOSE 1 +#define MYCALL_WRITE 2 +#define MYCALL_DUP2 3 +#define MYCALL_SETPGID 4 +#define MYCALL_SETSID 5 +#define MYCALL_KILL 6 +#define MYCALL_FORK 7 +#define MYCALL_EXIT 8 +#define MYCALL_EXECVE 9 +#define MYCALL_IOCTL 10 + +#if defined __x86_64__ +/* from unistd_32.h on an amd64 system */ +int syscalls32[] = { 5, 6, 4, 63, 57, 66, 37, 2, 1, 11, 54 }; + +int syscalls64[] = +#else +int syscalls32[] = +#endif +{ SYS_open, SYS_close, SYS_write, SYS_dup2, SYS_setpgid, SYS_setsid, + SYS_kill, SYS_fork, SYS_exit, SYS_execve, SYS_ioctl +}; + +char const *syscallnames[] = + { "open", "close", "write", "dup2", "setpgid", "setsid", "kill", "fork", + "exit", "execve", "ioctl" +}; + +#endif /* USE_GRAB */ + +struct mytrace +{ + pid_t pid, child; +}; + +struct mytrace *mytrace_attach(long int pid) +{ +#if defined USE_GRAB + struct mytrace *t; + int status; + + if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) + { + perror("PTRACE_ATTACH (attach)"); + return NULL; + } + if (waitpid(pid, &status, 0) < 0) + { + perror("waitpid"); + return NULL; + } + if (!WIFSTOPPED(status)) + { + fprintf(stderr, "traced process was not stopped\n"); + ptrace(PTRACE_DETACH, pid, 0, 0); + return NULL; + } + + t = malloc(sizeof(struct mytrace)); + t->pid = pid; + t->child = 0; + + return t; +#else + errno = ENOSYS; + return NULL; +#endif +} + +struct mytrace *mytrace_fork(struct mytrace *t) +{ +#if defined USE_GRAB + struct mytrace *child; + + ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEFORK); + remote_syscall(t, MYCALL_FORK, 0, 0, 0); + waitpid(t->child, NULL, 0); + + child = malloc(sizeof(struct mytrace)); + child->pid = t->child; + child->child = 0; + + return child; +#else + errno = ENOSYS; + return NULL; +#endif +} + +int mytrace_detach(struct mytrace *t) +{ +#if defined USE_GRAB + ptrace(PTRACE_DETACH, t->pid, 0, 0); + free(t); + + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} + +long mytrace_getpid(struct mytrace *t) +{ +#if defined USE_GRAB + return t->pid; +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_open(struct mytrace *t, char const *path, int mode) +{ +#if defined USE_GRAB + char backup_data[4096]; + struct user_regs_struct regs; + size_t size = strlen(path) + 1; + int ret, err; + + if (ptrace(PTRACE_GETREGS, t->pid, NULL, ®s) < 0) + { + perror("PTRACE_GETREGS (open)\n"); + return -1; + } + + /* Backup the data that we will use */ + if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0) + return -1; + + memcpy_into_target(t, regs.RSP, path, size); + + ret = remote_syscall(t, MYCALL_OPEN, regs.RSP, O_RDWR, 0755); + err = errno; + + /* Restore the data */ + memcpy_into_target(t, regs.RSP, backup_data, size); + + errno = err; + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_close(struct mytrace *t, int fd) +{ +#if defined USE_GRAB + return remote_syscall(t, MYCALL_CLOSE, fd, 0, 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_write(struct mytrace *t, int fd, char const *data, size_t len) +{ +#if defined USE_GRAB + struct user_regs_struct regs; + char *backup_data; + int ret, err; + + if (ptrace(PTRACE_GETREGS, t->pid, NULL, ®s) < 0) + { + perror("PTRACE_GETREGS (write)\n"); + return -1; + } + + backup_data = malloc(len); + + /* Backup the data that we will use */ + if (memcpy_from_target(t, backup_data, regs.RSP, len) < 0) + return -1; + + memcpy_into_target(t, regs.RSP, data, len); + + ret = remote_syscall(t, MYCALL_WRITE, fd, regs.RSP, len); + err = errno; + + /* Restore the data */ + memcpy_into_target(t, regs.RSP, backup_data, len); + + errno = err; + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_dup2(struct mytrace *t, int oldfd, int newfd) +{ +#if defined USE_GRAB + return remote_syscall(t, MYCALL_DUP2, oldfd, newfd, 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_setpgid(struct mytrace *t, long pid, long pgid) +{ +#if defined USE_GRAB + return remote_syscall(t, MYCALL_SETPGID, pid, pgid, 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_setsid(struct mytrace *t) +{ +#if defined USE_GRAB + return remote_syscall(t, MYCALL_SETSID, 0, 0, 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_kill(struct mytrace *t, long pid, int sig) +{ +#if defined USE_GRAB + return remote_syscall(t, MYCALL_KILL, pid, sig, 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_exit(struct mytrace *t, int status) +{ +#if defined USE_GRAB + ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXIT); + return remote_syscall(t, MYCALL_EXIT, status, 0, 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_exec(struct mytrace *t, char const *command) +{ +#if defined USE_GRAB + struct user_regs_struct regs; + char *env, *p; + long p2, envaddr, argvaddr, envptraddr; + char envpath[PATH_MAX + 1]; + ssize_t envsize = 16 * 1024; + int ret, fd, l, l2; + char *nullp = NULL; + ssize_t r; + + ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXEC); + + if (ptrace(PTRACE_GETREGS, t->pid, NULL, ®s) < 0) + { + perror("PTRACE_GETREGS (exec)\n"); + return -1; + } + + debug("PTRACE_GETREGS done"); + env = malloc(envsize); + if (!env) + return -1; + + snprintf(envpath, PATH_MAX, "/proc/%d/environ", t->pid); + + fd = open(envpath, O_RDONLY); + if (fd == -1) + return -1; + r = read(fd, env, envsize); + close(fd); + if (r == -1) + return -1; + while (r == envsize) + { + free(env); + env = malloc(envsize); + if (!env) + return -1; + fd = open(envpath, O_RDONLY); + r = read(fd, env, envsize); + close(fd); + if (r == -1) + return -1; + } + envsize = r; + l2 = sizeof(char *); /* Size of a pointer */ + p2 = regs.RSP; + + /* First argument is the command string */ + l = strlen(command) + 1; + memcpy_into_target(t, p2, command, l); + p2 += l; + + /* Second argument is argv */ + argvaddr = p2; + /* argv[0] is a pointer to the command string */ + memcpy_into_target(t, p2, (char *)®s.RSP, l2); + p2 += l2; + /* Then follows a NULL pointer */ + memcpy_into_target(t, p2, (char *)&nullp, l2); + p2 += l2; + + /* Third argument is the environment */ + /* First, copy all the strings */ + memcpy_into_target(t, p2, env, envsize); + envaddr = p2; + p2 += envsize; + /* Then write an array of pointers to the strings */ + envptraddr = p2; + p = env; + while (p < env + envsize) + { + long diffp = p - env + envaddr; + memcpy_into_target(t, p2, (char *)&diffp, l2); + p2 += l2; + p += strlen(p) + 1; + } + /* And have a NULL pointer at the end of the array */ + memcpy_into_target(t, p2, (char *)&nullp, l2); + free(env); + + ret = remote_syscall(t, MYCALL_EXECVE, regs.RSP, argvaddr, envptraddr); + + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_tcgets(struct mytrace *t, int fd, struct termios *tos) +{ +#if defined USE_GRAB + char backup_data[4096]; + struct user_regs_struct regs; + size_t size = sizeof(struct termios); + int ret, err; + + if (ptrace(PTRACE_GETREGS, t->pid, NULL, ®s) < 0) + { + perror("PTRACE_GETREGS (tcgets)\n"); + return -1; + } + + /* Backup the data that we will use */ + if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0) + return -1; + + ret = remote_syscall(t, MYCALL_IOCTL, fd, TCGETS, regs.RSP); + err = errno; + + memcpy_from_target(t, (char *)tos, regs.RSP, size); + + /* Restore the data */ + memcpy_into_target(t, regs.RSP, backup_data, size); + + errno = err; + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_tcsets(struct mytrace *t, int fd, struct termios *tos) +{ +#if defined USE_GRAB + char backup_data[4096]; + struct user_regs_struct regs; + size_t size = sizeof(struct termios); + int ret, err; + + if (ptrace(PTRACE_GETREGS, t->pid, NULL, ®s) < 0) + { + perror("PTRACE_GETREGS (tcsets)\n"); + return -1; + } + + /* Backup the data that we will use */ + if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0) + return -1; + + memcpy_into_target(t, regs.RSP, (char *)tos, size); + + ret = remote_syscall(t, MYCALL_IOCTL, fd, TCSETS, regs.RSP); + err = errno; + + /* Restore the data */ + memcpy_into_target(t, regs.RSP, backup_data, size); + + errno = err; + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int mytrace_sctty(struct mytrace *t, int fd) +{ +#if defined USE_GRAB + ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXIT); + return remote_syscall(t, MYCALL_IOCTL, fd, TIOCSCTTY, 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +/* + * XXX: the following functions are local + */ + +#if defined USE_GRAB +static int memcpy_from_target(struct mytrace *t, + char *dest, long src, size_t n) +{ + static int const align = sizeof(long) - 1; + + while (n) + { + long data; + size_t todo = sizeof(long) - (src & align); + + if (n < todo) + todo = n; + + data = ptrace(PTRACE_PEEKTEXT, t->pid, src - (src & align), 0); + if (errno) + { + perror("ptrace_peektext (memcpy_from_target)"); + return -1; + } + memcpy(dest, (char *)&data + (src & align), todo); + + dest += todo; + src += todo; + n -= todo; + } + + return 0; +} + +static int memcpy_into_target(struct mytrace *t, + long dest, char const *src, size_t n) +{ + static int const align = sizeof(long) - 1; + + while (n) + { + long data; + size_t todo = sizeof(long) - (dest & align); + + if (n < todo) + todo = n; + if (todo != sizeof(long)) + { + data = ptrace(PTRACE_PEEKTEXT, t->pid, dest - (dest & align), 0); + if (errno) + { + perror("ptrace_peektext (memcpy_into_target)"); + return -1; + } + } + + memcpy((char *)&data + (dest & align), src, todo); + if (ptrace(PTRACE_POKETEXT, t->pid, dest - (dest & align), data) < 0) + { + perror("ptrace_poketext (memcpy_into_target)"); + return -1; + } + + src += todo; + dest += todo; + n -= todo; + } + + return 0; +} + +static long remote_syscall(struct mytrace *t, long call, + long arg1, long arg2, long arg3) +{ + /* Method for remote syscall: - wait until the traced application exits + from a syscall - save registers - rewind eip/rip to point on the + syscall instruction - single step: execute syscall instruction - + retrieve resulting registers - restore registers */ + struct user_regs_struct regs, oldregs; + long oinst; + int bits; + int offset = 2; + + if (call < 0 + || call >= (long)(sizeof(syscallnames) / sizeof(*syscallnames))) + { + fprintf(stderr, "unknown remote syscall %li\n", call); + return -1; + } + + debug("remote syscall %s(0x%lx, 0x%lx, 0x%lx)", + syscallnames[call], arg1, arg2, arg3); + +#if defined __x86_64__ + bits = 64; +#else + bits = 32; +#endif + + for (;;) + { + if (ptrace(PTRACE_GETREGS, t->pid, NULL, &oldregs) < 0) + { + perror("PTRACE_GETREGS (syscall 1)\n"); + return -1; + } + + oinst = ptrace(PTRACE_PEEKTEXT, t->pid, oldregs.RIP - 2, 0) & 0xffff; + +#if defined __x86_64__ + if (oinst == SYSCALL_AMD64) + break; +#endif + if (oinst == SYSCALL_X86 || oinst == SYSCALL_X86_NEW) + { + bits = 32; + break; + } + + if (ptrace(PTRACE_SYSCALL, t->pid, NULL, 0) < 0) + { + perror("ptrace_syscall (1)"); + return -1; + } + waitpid(t->pid, NULL, 0); + if (ptrace(PTRACE_SYSCALL, t->pid, NULL, 0) < 0) + { + perror("ptrace_syscall (2)"); + return -1; + } + waitpid(t->pid, NULL, 0); + } + + print_registers(t->pid); + + if (oinst == SYSCALL_X86_NEW) + { + /* Get back to sysenter */ + while ((ptrace(PTRACE_PEEKTEXT, t->pid, oldregs.RIP - offset, 0) & + 0xffff) != 0x340f) + offset++; + oldregs.RBP = oldregs.RSP; + } + + regs = oldregs; + regs.RIP = regs.RIP - offset; +#if defined __x86_64__ + if (bits == 64) + { + regs.RAX = syscalls64[call]; + regs.RDI = arg1; + regs.RSI = arg2; + regs.RDX = arg3; + } + else +#endif + { + regs.RAX = syscalls32[call]; + regs.RBX = arg1; + regs.RCX = arg2; + regs.RDX = arg3; + } + + if (ptrace(PTRACE_SETREGS, t->pid, NULL, ®s) < 0) + { + perror("PTRACE_SETREGS (syscall 1)\n"); + return -1; + } + + for (;;) + { + int status; + + print_registers(t->pid); + + if (ptrace(PTRACE_SINGLESTEP, t->pid, NULL, NULL) < 0) + { + perror("PTRACE_SINGLESTEP (syscall)\n"); + return -1; + } + waitpid(t->pid, &status, 0); + + if (WIFEXITED(status)) + return 0; + + if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) + continue; + + /* Fuck Linux: there is no macro for this */ + switch ((status >> 16) & 0xffff) + { + case PTRACE_EVENT_FORK: + if (ptrace(PTRACE_GETEVENTMSG, t->pid, 0, &t->child) < 0) + { + perror("PTRACE_GETEVENTMSG (syscall)\n"); + return -1; + } + debug("PTRACE_GETEVENTMSG %d", t->child); + continue; + case PTRACE_EVENT_EXIT: + debug("PTRACE_EVENT_EXIT"); + /* The process is about to exit, don't do anything else */ + return 0; + case PTRACE_EVENT_EXEC: + debug("PTRACE_EVENT_EXEC"); + return 0; + } + + break; + } + + print_registers(t->pid); + + if (ptrace(PTRACE_GETREGS, t->pid, NULL, ®s) < 0) + { + perror("PTRACE_GETREGS (syscall 2)\n"); + return -1; + } + + if (ptrace(PTRACE_SETREGS, t->pid, NULL, &oldregs) < 0) + { + perror("PTRACE_SETREGS (syscall 2)\n"); + return -1; + } + print_registers(t->pid); + + debug("syscall %s returned %ld", syscallnames[call], regs.RAX); + + if ((long)regs.RAX < 0) + { + errno = -(long)regs.RAX; + perror("syscall"); + return -1; + } + + return regs.RAX; +} + +/* For debugging purposes only. Prints register and stack information. */ +#if defined DEBUG +static void print_registers(pid_t pid) +{ + union + { + long int l; + unsigned char data[sizeof(long int)]; + } inst; + struct user_regs_struct regs; + int i; + + if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) < 0) + { + perror("PTRACE_GETREGS (syscall 2)"); + exit(errno); + } + + fprintf(stderr, " / %s: " FMT " ", STRINGIFY(RAX), regs.RAX); + fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RBX), regs.RBX); + fprintf(stderr, " | %s: " FMT " ", STRINGIFY(RCX), regs.RCX); + fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RDX), regs.RDX); + fprintf(stderr, " | %s: " FMT " ", STRINGIFY(RDI), regs.RDI); + fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RSI), regs.RSI); + fprintf(stderr, " | %s: " FMT " ", STRINGIFY(RSP), regs.RSP); + fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RIP), regs.RIP); + + inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP - 4, 0); + fprintf(stderr, " | code: ... %02x %02x %02x %02x <---> ", + inst.data[0], inst.data[1], inst.data[2], inst.data[3]); + inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP, 0); + fprintf(stderr, "%02x %02x %02x %02x ...\n", + inst.data[0], inst.data[1], inst.data[2], inst.data[3]); + + fprintf(stderr, " \\ stack: ... "); + for (i = -16; i < 24; i += sizeof(long)) + { + inst.l = ptrace(PTRACE_PEEKDATA, pid, regs.RSP + i, 0); +#if defined __x86_64__ + fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ", + inst.data[0], inst.data[1], inst.data[2], inst.data[3], + inst.data[4], inst.data[5], inst.data[6], inst.data[7]); +#else + fprintf(stderr, "%02x %02x %02x %02x ", + inst.data[0], inst.data[1], inst.data[2], inst.data[3]); +#endif + if (i == 0) + fprintf(stderr, "[%s] ", STRINGIFY(RSP)); + } + fprintf(stderr, "...\n"); +} +#endif /* DEBUG */ + +#endif /* USE_GRAB */ diff --git a/neercs/old/mytrace.h b/neercs/old/mytrace.h new file mode 100644 index 0000000..d0f9d61 --- /dev/null +++ b/neercs/old/mytrace.h @@ -0,0 +1,33 @@ +/* + * neercs console-based window manager + * Copyright (c) 2008-2010 Sam Hocevar + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include + +struct mytrace; + +struct mytrace* mytrace_attach(long int pid); +struct mytrace* mytrace_fork(struct mytrace *t); +int mytrace_detach(struct mytrace *t); +long mytrace_getpid(struct mytrace *t); + +int mytrace_open(struct mytrace *t, char const *path, int mode); +int mytrace_write(struct mytrace *t, int fd, char const *data, size_t len); +int mytrace_close(struct mytrace *t, int fd); +int mytrace_dup2(struct mytrace *t, int oldfd, int newfd); +int mytrace_setpgid(struct mytrace *t, long pid, long pgid); +int mytrace_setsid(struct mytrace *t); +int mytrace_kill(struct mytrace *t, long pid, int sig); +int mytrace_exit(struct mytrace *t, int status); +int mytrace_exec(struct mytrace *t, char const *command); +int mytrace_tcgets(struct mytrace *t, int fd, struct termios *tos); +int mytrace_tcsets(struct mytrace *t, int fd, struct termios *tos); +int mytrace_sctty(struct mytrace *t, int fd); diff --git a/neercs/old/neercs.h b/neercs/old/neercs.h new file mode 100644 index 0000000..9536547 --- /dev/null +++ b/neercs/old/neercs.h @@ -0,0 +1,430 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#ifndef _NEERCS_H_ +#define _NEERCS_H_ + +#include +#include + +#include "widgets.h" + +enum wm_types +{ + WM_FULL, + WM_CARD, + WM_HSPLIT, + WM_VSPLIT, + + WM_MAX, +}; + +enum mouse_report +{ + MOUSE_NONE, + MOUSE_X10, + MOUSE_VT200, + MOUSE_VT200_HIGHLIGHT, + MOUSE_BTN_EVENT, + MOUSE_ANY_EVENT, +}; + + +/* ISO-2022 Conversion State */ +struct iso2022_conv_state +{ + /* cs = coding system/coding method: */ + /* (with standard return) */ + /* '@' = ISO-2022, */ + /* 'G' = UTF-8 without implementation level, */ + /* '8' = UTF-8 (Linux console and imitators), */ + /* and many others that are rarely used; */ + /* (without standard return) */ + /* '/G' = UTF-8 Level 1, */ + /* '/H' = UTF-8 Level 2, */ + /* '/I' = UTF-8 Level 3, */ + /* and many others that are rarely used */ + uint32_t cs; + /* ctrl8bit = allow 8-bit controls */ + uint8_t ctrl8bit; + /* cn[0] = C0 control charset (0x00 ... 0x1f): + * '@' = ISO 646, + * '~' = empty, + * and many others that are rarely used */ + /* cn[1] = C1 control charset (0x80 ... 0x9f): + * 'C' = ISO 6429-1983, + * '~' = empty, + * and many others that are rarely used */ + uint32_t cn[2]; + /* glr[0] = GL graphic charset (94-char. 0x21 ... 0x7e, + * 94x94-char. 0x21/0x21 ... 0x7e/0x7e), + * and + * glr[1] = GR graphic charset (94-char. 0xa1 ... 0xfe, + * 96-char. 0xa0 ... 0xff, + * 94x94-char. 0xa1/0xa1 ... 0xfe/0xfe, + * 96x96-char. 0xa0/0xa0 ... 0xff/0xff): + * 0 = G0, 1 = G1, 2 = G2, 3 = G3 */ + uint8_t glr[2]; + /* gn[i] = G0/G1/G2/G3 graphic charset state: + * (94-char. sets) + * '0' = DEC ACS (VT100 and imitators), + * 'B' = US-ASCII, + * and many others that are rarely used for e.g. various national ASCII variations; + * (96-char. sets) + * '.A' = ISO 8859-1 "Latin 1" GR, + * '.~' = empty 96-char. set, + * and many others that are rarely used for e.g. ISO 8859-n GR; + * (double-byte 94x94-charsets) + * '$@' = Japanese Character Set ("old JIS") (JIS C 6226:1978), + * '$A' = Chinese Character Set (GB 2312), + * '$B' = Japanese Character Set (JIS X0208/JIS C 6226:1983), + * '$C' = Korean Graphic Character Set (KSC 5601:1987), + * '$D' = Supplementary Japanese Graphic Character Set (JIS X0212), + * '$E' = CCITT Chinese Set (GB 2312 + GB 8565), + * '$G' = CNS 11643 plane 1, + * '$H' = CNS 11643 plane 2, + * '$I' = CNS 11643 plane 3, + * '$J' = CNS 11643 plane 4, + * '$K' = CNS 11643 plane 5, + * '$L' = CNS 11643 plane 6, + * '$M' = CNS 11643 plane 7, + * '$O' = JIS X 0213 plane 1, + * '$P' = JIS X 0213 plane 2, + * '$Q' = JIS X 0213-2004 Plane 1, + * and many others that are rarely used for e.g. traditional + * ideographic Vietnamese and BlissSymbolics; + * (double-byte 96x96-charsets) + * none standardized or in use on terminals AFAIK (Mule does use + * some internally) + */ + uint32_t gn[4]; + /* ss = single-shift state: 0 = GL, 2 = G2, 3 = G3 */ + uint8_t ss; +}; + +struct screen +{ + /* Graphics stuff */ + int init; + caca_canvas_t *cv; + uint32_t clearattr; + uint8_t fg, bg; /* ANSI-context fg/bg */ + uint8_t dfg, dbg; /* Default fg/bg */ + uint8_t bold, blink, italics, negative, concealed, underline; + uint8_t faint, strike, proportional; /* unsupported */ + struct iso2022_conv_state conv_state; /* charset mess */ + + /* Other stuff */ + int visible; /* Draw canvas and border flag */ + int fd; /* pty fd */ + unsigned char *buf; /* text buffer */ + long int total; /* buffer length */ + char *title; /* tty title */ + int bell; /* bell occuring */ + unsigned int scroll, s1, s2; /* FIXME, ANSI scroll properties */ + int pid; /* running program pid */ + int changed; /* content was updated */ + + int x, y; /* Canvas position */ + int w, h; /* Canvas size */ + + int orig_x, orig_y; /* Used by recurrents */ + int orig_w, orig_h; /* Used by recurrents */ + + int report_mouse; /* ANSI */ +}; + +enum socket_type +{ + SOCK_SERVER=0, + SOCK_CLIENT=1 +}; + +struct cube_props +{ + int in_switch; + int side; + long long unsigned int duration; +}; + +struct interpreter_props +{ + /* Input box */ + struct input_box *box; +}; + +struct screensaver +{ + /* ScreenSaver stuff */ + long long unsigned int timeout; /* Screensaver timeout in us */ + int in_screensaver; + void *data; +}; + +struct comm +{ + /* Detaching */ + int attached; /* Are we attached to a terminal or a server */ + int socket[2]; /* Sockets to write to the server / to the client */ + char *socket_path[2]; /* Sockets to write to the server / to the client */ + char *socket_dir; /* Where to create the socket */ + char *session_name; /* Name of the session */ +}; + +struct lock +{ + int locked; + int lock_offset; + int lock_on_detach; + long long unsigned int autolock_timeout; + char lockpass[1024]; + char lockmsg[1024]; +}; + +struct modals +{ + /* Add-ons*/ + int mini; /* Thumbnails */ + int status; /* Status bar */ + int help; /* Help */ + int python_command; /* Python command */ + int window_list; /* Window list */ + int cur_in_list; /* Window list */ +}; + +struct sys +{ + char *default_shell; + char *user_path; + int *to_grab; + char **to_start; + int nb_to_grab; + int attach, forceattach; +}; + +struct screen_list +{ + int outfd; /* Debug */ + int in_bell; /* Bell occuring in a window */ + int was_in_bell; + int dont_update_coords; /* Used by recurrents */ + int changed; /* Global redraw (e.g. adding a screen) */ + int delay; /* Minimal time between two refresh (ms) */ + int requested_delay; + int force_refresh; + int need_refresh; /* If we skipped a refresh, do it next time */ + int command; + int eyecandy; /* Eye Candy */ + + long long unsigned int last_key_time; + long long unsigned int last_refresh_time; + + struct comm comm; /* Client/Server communications */ + struct lock lock; /* Lock */ + struct modals modals; /* Modal windows */ + struct interpreter_props interpreter_props; /* Python interpreter */ + struct screensaver screensaver;/* Screensaver stuff */ + + int pty, prevpty; /* Current and previous window */ + int count; /* Window count */ + int wm_type; /* Window manager type */ + int border_size; /* Borders */ + struct cube_props cube; /* Cube */ + long long unsigned int last_switch; /* Cube */ + + struct screen **screen; /* Windows */ + struct option *config; /* Option parsing and configuration */ + struct sys sys; /* System stuff */ + + struct recurrent_list *recurrent_list; /* Recurrents functions */ + + char *title; /* Window title */ + int width, height; /* caca window size */ + int old_x, old_y; /* Mouse */ + int mouse_button; + caca_canvas_t *cv; + caca_display_t *dp; +}; + +/* Configuration */ +struct option +{ + char *key; + char *value; + + struct option *next; +}; +struct config_line +{ + const char name[32]; + int (*set) (const char *argv, struct screen_list * screen_list); + char* (*get) (struct screen_list * screen_list); +}; + +/* Recurrents */ +struct recurrent +{ + int (*function)(struct screen_list*, struct recurrent* rec, void *user, long long unsigned int t); + void *user; + long long unsigned int start_time; + int kill_me; +}; + +struct recurrent_list +{ + int count; + struct recurrent **recurrent; +}; + + + +void version(void); +void usage(int argc, char **argv); +struct screen_list *init_neercs(int argc, char **argv); + +int handle_command_line(int argc, char *argv[], struct screen_list *screen_list); + +struct screen_list *create_screen_list(void); +void free_screen_list(struct screen_list *screen_list); + +int start_client(struct screen_list * screen_list); +/** \defgroup client neercs client + * @{ */ +void mainloop(struct screen_list *screen_list); +int mainloop_tick(char **pbuf, struct screen_list *screen_list); +/** }@ */ + + +int create_pty(char *cmd, unsigned int w, unsigned int h, int *cpid); +int create_pty_grab(long pid, unsigned int w, unsigned int h, int *cpid); +int grab_process(long pid, char *ptyname, int ptyfd, int *newpid); +long select_process(struct screen_list* screen_list); + +long int import_term(struct screen_list *screen_list, struct screen *sc, void const *data, unsigned int size); +int set_tty_size(int fd, unsigned int w, unsigned int h); +int update_terms(struct screen_list* screen_list); +void refresh_screens(struct screen_list *screen_list); +int update_screens_contents(struct screen_list* screen_list); +int install_fds(struct screen_list *screen_list); +long long get_us(void); + +void attach(struct screen_list* screen_list); +int detach(struct screen_list* screen_list); +int request_attach(struct screen_list* screen_list); +char * build_socket_path(char *socket_dir, char *session_name, enum socket_type socktype); +int create_socket(struct screen_list* screen_list, enum socket_type socktype); +char * connect_socket(struct screen_list* screen_list, enum socket_type socktype); +char ** list_sockets(char *socket_dir, char *session_name); +int start_server(struct screen_list *screen_list); +int send_event(caca_event_t ev, struct screen_list* screen_list); +int send_delay(struct screen_list* screen_list); +int send_ansi_sequence(struct screen_list *screen_list, char *str); + +/* Screens management */ +struct screen* create_screen(int w, int h, char *command); +struct screen* create_screen_grab(int w, int h, int pid); +int destroy_screen(struct screen *s); +int add_screen(struct screen_list *list, struct screen *s); +int remove_screen(struct screen_list *list, int n, int please_kill); +void resize_screen(struct screen *s, int z, int h); + +/* Window managers */ +void update_windows_props(struct screen_list *screen_list); +void update_windows_props_cards(struct screen_list *screen_list); +void update_windows_props_hsplit(struct screen_list *screen_list); +void update_windows_props_full(struct screen_list *screen_list); +void update_windows_props_vsplit(struct screen_list *screen_list); +void update_windows_props_cube(struct screen_list *screen_list); + +void wm_refresh(struct screen_list *screen_list); +void wm_refresh_card(struct screen_list *screen_list); +void wm_refresh_cube(struct screen_list *screen_list); +void wm_refresh_full(struct screen_list *screen_list); +void wm_refresh_hsplit(struct screen_list *screen_list); +void wm_refresh_vsplit(struct screen_list *screen_list); +int switch_screen_recurrent(struct screen_list* screen_list, struct recurrent* rec, void *user, long long unsigned int t); + + +/* Effects and addons */ +void draw_thumbnails(struct screen_list *screen_list); +void draw_status(struct screen_list *screen_list); +void draw_help(struct screen_list *screen_list); +int help_handle_key(struct screen_list *screen_list, unsigned int c); +int update_window_list(int c, struct screen_list *screen_list); +void draw_list(struct screen_list *screen_list); +void draw_lock(struct screen_list *screen_list); +int update_lock(int c, struct screen_list *screen_list); +int validate_lock(struct screen_list *screen_list, char *user, char *pass); + +int close_screen_recurrent(struct screen_list*, struct recurrent* rec, void *user, long long unsigned int t); + +/* Input to ANSI */ +void *convert_input_ansi(unsigned int *c, int *size); +int handle_command_input(struct screen_list*screen_list, unsigned int c); + + +/* Screensavers */ +void screensaver_init(struct screen_list *screen_list); +void screensaver_kill(struct screen_list *screen_list); + +void draw_screensaver(struct screen_list *screen_list); +void screensaver_flying_toasters(struct screen_list *screen_list); + +void screensaver_flying_toasters_init(struct screen_list *screen_list); + +void screensaver_flying_toasters_kill(struct screen_list *screen_list); + +/* Actions */ +void dump_to_file(struct screen_list *screen_list); + +/* Recurrents */ +int handle_recurrents(struct screen_list* screen_list); +int add_recurrent(struct recurrent_list *list, + int (*function)(struct screen_list*, struct recurrent* rec, void *user, long long unsigned int t), + void *user); +int remove_recurrent(struct recurrent_list *list, int n); + + + +/* Configuration file */ +int read_configuration_file(char *filename, struct screen_list *screen_list); +int parse_conf_line(char *buf, int size, struct screen_list *screen_list); +int get_key_value(char *line, struct option *option); +int fill_config(struct screen_list *screen_list); +struct config_line *get_config(const char *name); +struct config_line *get_config_option(void); + +/* Python interpreter */ +#ifdef USE_PYTHON +int python_init(struct screen_list *sl); +int python_close(struct screen_list *sl); +int python_command_handle_key(struct screen_list *screen_list, unsigned int c); +void draw_python_command(struct screen_list *screen_list); +#endif + +#if defined DEBUG +# include +# include +static inline void debug(const char *format, ...) +{ + va_list args; + va_start(args, format); + fprintf(stderr, "** neercs debug ** "); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + va_end(args); +} +#else +# define debug(format, ...) do {} while(0) +#endif +#endif /* _NEERCS_H_ */ diff --git a/neercs/old/python/interpreter.c b/neercs/old/python/interpreter.c new file mode 100644 index 0000000..267d860 --- /dev/null +++ b/neercs/old/python/interpreter.c @@ -0,0 +1,197 @@ +/* + * neercs console-based window manager + * Copyright (c) 2009-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#ifdef USE_PYTHON + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "neercs.h" +#include "py_module.h" + +static int python_execute(struct screen_list *sl); +char *getStringFromPyObject(PyObject * p); +static char *getPythonError(void); + +#if ! defined HAVE_PYTHON26 +static PyObject *PyUnicode_FromString(char const *str) +{ + PyObject *tmp, *ret; + tmp = PyString_FromString(str); + if (!tmp) + return NULL; + ret = PyString_AsDecodedObject(tmp, "utf-8", "replace"); + Py_DECREF(tmp); + return ret; +} +#endif + +int python_command_handle_key(struct screen_list *screen_list, unsigned int c) +{ + int ret = widget_ibox_handle_key(screen_list->interpreter_props.box, c); + + if (ret == INPUT_BOX_ESC) + { + widget_ibox_destroy(screen_list->interpreter_props.box); + screen_list->interpreter_props.box = NULL; + screen_list->modals.python_command = 0; + } + else if (ret == INPUT_BOX_RET) + { + python_execute(screen_list); + } + screen_list->changed = 1; + + return 1; +} + +void draw_python_command(struct screen_list *screen_list) +{ + if (!screen_list->interpreter_props.box) + { + screen_list->interpreter_props.box = + widget_ibox_init(screen_list->cv, 65, 6); + debug("py Init %p\n", screen_list->interpreter_props.box); + } + widget_ibox_draw(screen_list->interpreter_props.box); +} + +/* Actual Python interpreter stuff */ +int python_init(struct screen_list *sl) +{ + initNeercsModule(sl); + + return 0; +} + +int python_close(struct screen_list *sl) +{ + widget_ibox_destroy(sl->interpreter_props.box); + sl->interpreter_props.box = NULL; + + Py_Finalize(); + return 0; +} + + +static int python_execute(struct screen_list *sl) +{ + char *command = widget_ibox_get_text(sl->interpreter_props.box); + if (!command || strlen(command) < 1) + return -1; + int err = 0; + + debug("py Executing '%s'\n", command); + + + PyObject *pModule, *pName; + + /* Module from which to call the function */ + pName = PyUnicode_FromString("neercs"); + if (!pName) + { + widget_ibox_set_error(sl->interpreter_props.box, getPythonError()); + err = 1; + debug("py Error 1\n"); + goto end; + } + + pModule = PyImport_Import(pName); + Py_DECREF(pName); + + if (pModule != NULL) + { + PyObject *dictionary = PyModule_GetDict(pModule); + + getExportedValues(dictionary); + + PyObject *o = + PyRun_String(command, Py_single_input, + dictionary, NULL); + if (!o) + { + widget_ibox_set_error(sl->interpreter_props.box, getPythonError()); + err = 1; + } + else + { + setExportedValues(dictionary); + + widget_ibox_set_msg(sl->interpreter_props.box, getStringFromPyObject(o)); + err = 1; + } + + Py_DECREF(pModule); + } + else + { + widget_ibox_set_error(sl->interpreter_props.box, getPythonError()); + err = 1; + } + + end: + + if (!err) + { + widget_ibox_destroy(sl->interpreter_props.box); + sl->interpreter_props.box = NULL; + sl->modals.python_command = 0; + } + sl->changed = 1; + + return 0; +} + +static char *getPythonError(void) +{ + char *err; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + + char *evalue = getStringFromPyObject(value); + + int r = asprintf(&err, "%s", evalue); + (void)r; + return err; +} + +char *getStringFromPyObject(PyObject * p) +{ + PyObject *str = PyObject_Repr(p); + char *tmp; +#if defined HAVE_PYTHON26 + tmp = PyBytes_AS_STRING(PyUnicode_AsEncodedString(str, "utf-8", "Error ~")); +#else + tmp = PyString_AsString(str); +#endif + return strdup(tmp); +} + + +#endif diff --git a/neercs/old/python/py_module.c b/neercs/old/python/py_module.c new file mode 100644 index 0000000..17ce2b6 --- /dev/null +++ b/neercs/old/python/py_module.c @@ -0,0 +1,193 @@ +/* + * neercs console-based window manager + * Copyright (c) 2009-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#ifdef USE_PYTHON + +#include +#include "py_module.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "neercs.h" + +/* FIXME : Find a way to pass a user pointer to PyModuleDef or something */ +static struct screen_list *screen_list; + +#if defined HAVE_PYTHON3 +static PyObject *PyInit_neercs(void); +#else +static void PyInit_neercs(void); +#endif +static void removeTrailingStuff(char *b); + + +static void addVariableFromConfig(PyObject * dictionary, + const char *varname, const char *configname) +{ + char *v = get_config(configname)->get(screen_list); + if (v != NULL) + { + PyObject *value = Py_BuildValue("s", v); + PyDict_SetItemString(dictionary, varname, value); + } + + debug("py get '%s' to '%s'\n", varname, + get_config(configname)->get(screen_list)); +} + +static void removeTrailingStuff(char *b) +{ + if(!b) + return; + if(b[0]=='\'') + { + memmove(b, &b[1], strlen(b)-1); + b[strlen(b)-2] = 0; + } +} + +void setExportedValues(PyObject * dictionary) +{ + struct config_line *config_option = get_config_option(); + int i = 0; + + while (strncmp(config_option[i].name, "last", strlen("last"))) + { + /* Get variable */ + PyObject *res = + PyDict_GetItemString(dictionary, config_option[i].name); + + /* Got it */ + if (res) + { + /* Get object representation + * FIXME : find a way to check object's type */ + PyObject *str = PyObject_Repr(res); + + /* Make sure it's a string */ + char *err = +#if defined HAVE_PYTHON3 + PyBytes_AS_STRING(PyUnicode_AsEncodedString + (str, "utf-8", "Error ~")); +#elif defined HAVE_PYTHON2 + PyString_AsString(str); +#endif + /* FIXME leak leak leak */ + char *s = strdup(err); + + if (s != NULL) + { + /* Representation can include '' around strings */ + removeTrailingStuff(s); + get_config(config_option[i].name)->set(s, screen_list); + } + } + i++; + } +} + +void getExportedValues(PyObject * dictionary) +{ + struct config_line *config_option = get_config_option(); + int i = 0; + while (strncmp(config_option[i].name, "last", strlen("last"))) + { + addVariableFromConfig(dictionary, config_option[i].name, + config_option[i].name); + i++; + } +} + +static PyObject *neercs_get(PyObject * self, PyObject * args) +{ + char *s = NULL; + + debug("Get using list at %p", screen_list); + + if (!PyArg_ParseTuple(args, "s", &s)) + { + PyErr_SetString(PyExc_ValueError, "Can't parse argument"); + debug("py Can't parse"); + return NULL; + } + debug("py Argument : '%s'", s); + struct config_line *c = get_config(s); + + if (c) + return Py_BuildValue("s", c->get(screen_list)); + + + PyErr_SetString(PyExc_ValueError, + "Can't get value for specified variable"); + return NULL; +} + +static PyObject *neercs_version(PyObject * self, PyObject * args) +{ + return Py_BuildValue("s", PACKAGE_VERSION); +} + +static PyMethodDef NeercsMethods[] = +{ + { "version", neercs_version, METH_NOARGS, "Return the neercs version." }, + { "get", neercs_get, METH_VARARGS, + "Return the specified variable's value." }, + { NULL, NULL, 0, NULL } +}; + +#if defined HAVE_PYTHON3 +static PyObject *PyInit_neercs(void) +{ + static PyModuleDef NeercsModule = + { + PyModuleDef_HEAD_INIT, "neercs", NULL, -1, NeercsMethods, + NULL, NULL, NULL, NULL + }; + + return PyModule_Create(&NeercsModule); +} + +#elif defined HAVE_PYTHON2 +static void PyInit_neercs(void) +{ + PyMethodDef *m = NeercsMethods; + PyObject *mod = PyModule_New("neercs"); + PyModule_AddStringConstant(mod, "__file__", ""); + + for (m = NeercsMethods; m->ml_name; m++) + PyModule_AddObject(mod, m->ml_name, PyCFunction_New(m, NULL)); +} +#endif + +void initNeercsModule(struct screen_list *sl) +{ + screen_list = sl; + PyImport_AppendInittab("neercs", &PyInit_neercs); + Py_Initialize(); +} + +#endif diff --git a/neercs/old/python/py_module.h b/neercs/old/python/py_module.h new file mode 100644 index 0000000..bae9e32 --- /dev/null +++ b/neercs/old/python/py_module.h @@ -0,0 +1,25 @@ +/* + * neercs console-based window manager + * Copyright (c) 2009-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#ifdef USE_PYTHON + +#include +#include "neercs.h" + +void initNeercsModule(struct screen_list *sl); +void getExportedValues(PyObject * dictionary); +void setExportedValues(PyObject * dictionary); + + +#endif diff --git a/neercs/old/recurrent.c b/neercs/old/recurrent.c new file mode 100644 index 0000000..7c8de1b --- /dev/null +++ b/neercs/old/recurrent.c @@ -0,0 +1,112 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "neercs.h" + + +int handle_recurrents(struct screen_list *screen_list) +{ + int refresh = 0, i; + /* Recurrent functions */ + for (i = 0; i < screen_list->recurrent_list->count; i++) + { + if (screen_list->recurrent_list->recurrent[i]->function) + { + refresh |= + screen_list->recurrent_list->recurrent[i]-> + function(screen_list, + screen_list->recurrent_list->recurrent[i], + screen_list->recurrent_list->recurrent[i]->user, + get_us()); + } + } + /* Delete recurrent functions */ + for (i = 0; i < screen_list->recurrent_list->count; i++) + { + if (screen_list->recurrent_list->recurrent[i]->kill_me) + { + remove_recurrent(screen_list->recurrent_list, i); + refresh = 1; + i = 0; + } + } + return refresh; +} + + +/* Add recurrent function. It will be called at each main loop iteration, + unless it is removed */ +int add_recurrent(struct recurrent_list *list, + int (*func) (struct screen_list *, struct recurrent * rec, + void *user, long long unsigned int t), + void *user) +{ + if (list == NULL || func == NULL) + return -1; + + list->recurrent = (struct recurrent **)realloc(list->recurrent, + sizeof(struct recurrent *) + * (list->count + 1)); + + if (!list->recurrent) + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + + list->recurrent[list->count] = malloc(sizeof(struct recurrent)); + + list->recurrent[list->count]->kill_me = 0; + list->recurrent[list->count]->function = func; + list->recurrent[list->count]->user = user; + list->recurrent[list->count]->start_time = get_us(); + list->count++; + + return list->count - 1; +} + + +/* Remove recurrent. Do *NOT* call this from a recurrent function. */ +int remove_recurrent(struct recurrent_list *list, int n) +{ + + if (n >= list->count) + return -1; + + memmove(&list->recurrent[n], + &list->recurrent[n + 1], + sizeof(struct recurrent *) * (list->count - (n + 1))); + + free(list->recurrent[n]); + list->recurrent = (struct recurrent **)realloc(list->recurrent, + sizeof(sizeof + (struct recurrent *)) + * (list->count)); + if (!list->recurrent) + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + + + + list->count--; + return 0; +} diff --git a/neercs/old/screen_list.c b/neercs/old/screen_list.c new file mode 100644 index 0000000..a9871c1 --- /dev/null +++ b/neercs/old/screen_list.c @@ -0,0 +1,216 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "neercs.h" + +struct screen_list *create_screen_list(void) +{ + + struct screen_list *screen_list = NULL; + struct passwd *user_info; + char *user_dir = NULL; + + /* Create screen list */ + screen_list = (struct screen_list *)malloc(sizeof(struct screen_list)); + if (!screen_list) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + return NULL; + } + screen_list->screen = + (struct screen **)malloc(sizeof(sizeof(struct screen *))); + if (!screen_list->screen) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + free(screen_list); + return NULL; + } + + screen_list->count = 0; + screen_list->modals.mini = 1; + screen_list->modals.help = 0; + screen_list->modals.status = 1; + screen_list->modals.window_list = 0; + screen_list->modals.python_command = 0; + screen_list->eyecandy = 1; + screen_list->border_size = 1; + screen_list->title = NULL; + screen_list->wm_type = WM_VSPLIT; + screen_list->in_bell = 0; + screen_list->changed = 0; + screen_list->requested_delay = 0; + screen_list->delay = 1000 / 60; /* Don't refresh more than 60 times + per second */ + screen_list->pty = screen_list->prevpty = 0; + screen_list->dont_update_coords = 0; + screen_list->screensaver.timeout = (60*5) * 1000000; + screen_list->screensaver.data = NULL; + screen_list->screensaver.in_screensaver = 0; + screen_list->lock.autolock_timeout = -1; + screen_list->lock.locked = 0; + screen_list->lock.lock_offset = 0; + screen_list->lock.lock_on_detach = 0; + screen_list->comm.attached = 0; + screen_list->comm.socket[SOCK_SERVER] = 0; + screen_list->comm.socket[SOCK_CLIENT] = 0; + screen_list->comm.socket_dir = NULL; + screen_list->comm.socket_path[SOCK_SERVER] = NULL; + screen_list->comm.socket_path[SOCK_CLIENT] = NULL; + screen_list->comm.session_name = NULL; + screen_list->sys.default_shell = NULL; + screen_list->sys.user_path = NULL; + screen_list->sys.to_grab = NULL; + screen_list->sys.to_start = NULL; + screen_list->sys.nb_to_grab = 0; + screen_list->sys.attach = 0; + screen_list->sys.forceattach = 0; + screen_list->need_refresh = 0; + + screen_list->force_refresh = 0; + screen_list->cube.in_switch = 0; + screen_list->cube.duration = 1000000; + + screen_list->interpreter_props.box = NULL; + + screen_list->recurrent_list = NULL; + screen_list->cv = NULL; + screen_list->dp = NULL; + + memset(screen_list->lock.lockmsg, 0, 1024); + memset(screen_list->lock.lockpass, 0, 1024); + + /* Build local config file path */ + user_dir = getenv("HOME"); + if (!user_dir) + { + user_info = getpwuid(getuid()); + if (user_info) + { + user_dir = user_info->pw_dir; + } + } + if (user_dir) + { + screen_list->sys.user_path = + malloc(strlen(user_dir) + strlen("/.neercsrc") + 1); + sprintf(screen_list->sys.user_path, "%s/%s", user_dir, ".neercsrc"); + } + + + screen_list->recurrent_list = + (struct recurrent_list *)malloc(sizeof(struct recurrent_list)); + screen_list->recurrent_list->recurrent = + (struct recurrent **)malloc(sizeof(struct recurrent *)); + if (!screen_list->recurrent_list->recurrent) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + free(screen_list); + free(screen_list->screen); + return NULL; + } + screen_list->recurrent_list->count = 0; + + return screen_list; +} + +void free_screen_list(struct screen_list *screen_list) +{ + int i; + struct option *option; + + if (screen_list->dp) + caca_free_display(screen_list->dp); + + if (screen_list->cv) + caca_free_canvas(screen_list->cv); + + for (i = 0; i < screen_list->count; i++) + { + destroy_screen(screen_list->screen[i]); + } + + if (screen_list->comm.socket_path[SOCK_SERVER]) + { + /* FIXME test that we are the server */ + if (!screen_list->dp) + unlink(screen_list->comm.socket_path[SOCK_SERVER]); + free(screen_list->comm.socket_path[SOCK_SERVER]); + } + + if (screen_list->comm.socket_path[SOCK_CLIENT]) + { + /* FIXME test that we are the client */ + if (screen_list->dp) + + unlink(screen_list->comm.socket_path[SOCK_CLIENT]); + free(screen_list->comm.socket_path[SOCK_CLIENT]); + } + + if (screen_list->comm.socket[SOCK_CLIENT]) + close(screen_list->comm.socket[SOCK_CLIENT]); + + if (screen_list->comm.socket[SOCK_SERVER]) + close(screen_list->comm.socket[SOCK_SERVER]); + + if (screen_list->screen) + free(screen_list->screen); + + option = screen_list->config; + + while (option) + { + struct option *kromeugnon = option; + option = option->next; + if (kromeugnon->key) + free(kromeugnon->key); + if (kromeugnon->value) + free(kromeugnon->value); + free(kromeugnon); + } + + for (i = 0; i < screen_list->recurrent_list->count; i++) + { + remove_recurrent(screen_list->recurrent_list, i); + i = 0; + } + + if (screen_list->recurrent_list->recurrent) + free(screen_list->recurrent_list->recurrent); + if (screen_list->recurrent_list) + free(screen_list->recurrent_list); + + if (screen_list->comm.session_name) + free(screen_list->comm.session_name); + + if (screen_list->title) + free(screen_list->title); + + free(screen_list); +} diff --git a/neercs/old/screens.c b/neercs/old/screens.c new file mode 100644 index 0000000..94e2954 --- /dev/null +++ b/neercs/old/screens.c @@ -0,0 +1,334 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "neercs.h" + +struct screen *create_screen_grab(int w, int h, int pid) +{ + struct screen *s = (struct screen *)malloc(sizeof(struct screen)); + + s->cv = caca_create_canvas(w, h); + caca_set_color_ansi(s->cv, CACA_BLACK, CACA_BLACK); + caca_clear_canvas(s->cv); + s->init = 0; + + s->buf = NULL; + s->title = NULL; + s->total = 0; + s->w = w; + s->h = h; + s->bell = 0; + s->report_mouse = MOUSE_NONE; + + s->fd = create_pty_grab(pid, w, h, &s->pid); + + if (s->fd < 0) + { + caca_free_canvas(s->cv); + free(s); + return NULL; + } + return s; +} + +struct screen *create_screen(int w, int h, char *command) +{ + struct screen *s = (struct screen *)malloc(sizeof(struct screen)); + + s->cv = caca_create_canvas(w, h); + caca_set_color_ansi(s->cv, CACA_BLACK, CACA_BLACK); + caca_clear_canvas(s->cv); + s->init = 0; + + s->buf = NULL; + s->title = NULL; + s->total = 0; + s->w = w + 1; + s->h = h + 1; + s->bell = 0; + s->visible = 1; + s->scroll = 0; + s->report_mouse = MOUSE_NONE; + s->fd = create_pty(command, w, h, &s->pid); + + s->orig_w = s->w; + s->orig_h = s->h; + s->orig_x = s->x; + s->orig_y = s->y; + + + if (s->fd < 0) + { + caca_free_canvas(s->cv); + free(s); + return NULL; + } + return s; +} + +int destroy_screen(struct screen *s) +{ + if (s->fd >= 0) + close(s->fd); + if (s->buf) + free(s->buf); + if (s->title) + free(s->title); + s->buf = NULL; + if (s->cv) + caca_free_canvas(s->cv); + s->cv = NULL; + free(s); + return 1; +} + +int add_screen(struct screen_list *list, struct screen *s) +{ + if (list == NULL || s == NULL) + return -1; + + else + { + list->screen = (struct screen **)realloc(list->screen, + sizeof(sizeof + (struct screen *)) * + (list->count + 1)); + if (!list->screen) + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + list->screen[list->count] = s; + list->count++; + } + + list->changed = 1; + + return list->count - 1; +} + +int remove_screen(struct screen_list *list, int n, int please_kill) +{ + + if (n >= list->count) + return -1; + + if (please_kill) + { + int status = 0; + int ret = 0; + /* FIXME */ + close(list->screen[n]->fd); + list->screen[n]->fd = -1; + kill(list->screen[n]->pid, SIGINT); + ret = waitpid(list->screen[n]->pid, &status, + WNOHANG | WUNTRACED | WCONTINUED); + if (!ret) + kill(list->screen[n]->pid, SIGQUIT); + ret = waitpid(list->screen[n]->pid, &status, + WNOHANG | WUNTRACED | WCONTINUED); + if (!ret) + kill(list->screen[n]->pid, SIGABRT); + ret = waitpid(list->screen[n]->pid, &status, + WNOHANG | WUNTRACED | WCONTINUED); + if (!ret) + kill(list->screen[n]->pid, SIGKILL); + + } + destroy_screen(list->screen[n]); + + memmove(&list->screen[n], + &list->screen[n + 1], + sizeof(struct screen *) * (list->count - (n + 1))); + + list->screen = (struct screen **)realloc(list->screen, + sizeof(sizeof(struct screen *)) + * (list->count)); + if (!list->screen) + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + + + + list->count--; + list->changed = 1; + return 1; +} + + + +void refresh_screens(struct screen_list *screen_list) +{ + int i; + + if (!screen_list->count) + return; + + + screen_list->width = caca_get_canvas_width(screen_list->cv); + screen_list->height = + caca_get_canvas_height(screen_list->cv) - (screen_list->modals.mini * 6) - + screen_list->modals.status; + + if (!screen_list->dont_update_coords) + { + update_windows_props(screen_list); + } + + if (screen_list->changed) + { + caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_DEFAULT); + caca_clear_canvas(screen_list->cv); + } + + wm_refresh(screen_list); + + caca_gotoxy(screen_list->cv, + screen_list->screen[screen_list->pty]->x + + caca_get_cursor_x(screen_list->screen[screen_list->pty]->cv), + screen_list->screen[screen_list->pty]->y + + caca_get_cursor_y(screen_list->screen[screen_list->pty]->cv)); + + + if (screen_list->modals.mini) + { + draw_thumbnails(screen_list); + } + if (screen_list->modals.status) + { + draw_status(screen_list); + } + if (screen_list->modals.help) + { + draw_help(screen_list); + } + if (screen_list->modals.window_list) + { + draw_list(screen_list); + } +#ifdef USE_PYTHON + debug("py : command is %d (at %p)\n", screen_list->modals.python_command, &screen_list->modals.python_command); + if(screen_list->modals.python_command) + { + draw_python_command(screen_list); + } +#endif + screen_list->changed = 0; + for (i = screen_list->count - 1; i >= 0; i--) + screen_list->screen[i]->changed = 0; +} + + +int update_screens_contents(struct screen_list *screen_list) +{ + int i, refresh = 0; + int maxfd = 0; + struct timeval tv; + fd_set fdset; + int ret; + + /* Read data, if any */ + FD_ZERO(&fdset); + for (i = 0; i < screen_list->count; i++) + { + if (screen_list->screen[i]->fd >= 0) + FD_SET(screen_list->screen[i]->fd, &fdset); + if (screen_list->screen[i]->fd > maxfd) + maxfd = screen_list->screen[i]->fd; + } + tv.tv_sec = 0; + tv.tv_usec = 50000; + ret = select(maxfd + 1, &fdset, NULL, NULL, &tv); + + if (ret < 0) + { + if (errno == EINTR) + ; /* We probably got a SIGWINCH, ignore it */ + else + { + /* FIXME: Useless since break will mean that we return 0 But I + don't know what was the purpose of this code */ + for (i = 0; i < screen_list->count; i++) + if (screen_list->screen[i]->total) + break; + if (i == screen_list->count) + return 0; + } + } + else if (ret) + { + + for (i = 0; i < screen_list->count; i++) + { + /* FIXME: try a new strategy: read all filedescriptors until each + of them starved at least once. */ + + if (screen_list->screen[i]->fd < 0 || + !FD_ISSET(screen_list->screen[i]->fd, &fdset)) + continue; + + for (;;) + { + ssize_t nr; + + screen_list->screen[i]->buf = + realloc(screen_list->screen[i]->buf, + screen_list->screen[i]->total + 1024); + if (!screen_list->screen[i]->buf) + fprintf(stderr, "Can't allocate memory at %s:%d\n", + __FUNCTION__, __LINE__); + + nr = read(screen_list->screen[i]->fd, + screen_list->screen[i]->buf + + screen_list->screen[i]->total, 1024); + + if (nr > 0) + { + screen_list->screen[i]->total += nr; + continue; + } + + if (nr == 0 || errno != EWOULDBLOCK) + { + remove_screen(screen_list, i, 0); + if (i < screen_list->prevpty) + screen_list->prevpty--; + if (i == screen_list->pty) + { + screen_list->pty = screen_list->prevpty; + screen_list->prevpty = 0; + } + if (i < (screen_list->pty)) + (screen_list->pty)--; + /* Don't skip the element which is now at position i */ + i--; + refresh = 1; + } + + break; + } + } + } + return refresh; +} diff --git a/neercs/old/screensaver.c b/neercs/old/screensaver.c new file mode 100644 index 0000000..9e9ab89 --- /dev/null +++ b/neercs/old/screensaver.c @@ -0,0 +1,187 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "neercs.h" + + +void screensaver_init(struct screen_list *screen_list) +{ + screensaver_flying_toasters_init(screen_list); +} + +void screensaver_kill(struct screen_list *screen_list) +{ + screensaver_flying_toasters_kill(screen_list); +} + +void draw_screensaver(struct screen_list *screen_list) +{ + screensaver_flying_toasters(screen_list); +} + + + + +/* Flying Toasters */ + +#define COUNT 15 +#define PRECISION 100 + +char toaster_text[3][99] = { { + " __._ \n" + " .-'== _',\n" + " <|_= .-' |\n" + " | --| \\'.-_ \n" + " | | \\ \" _.\n" + " `-_|.-\\_.-\n"}, +{ + " __._ \n" + " .-'== _',\n" + " \\|_= .-' |\n" + " | --| __'-.\n" + " | | ___.-\n" + " `-_|.-\n"}, +{ + " _- __._\n" + " /.-'== _',_.-.\n" + " \\|_= .-'/ _.'\n" + " | --| / .-\n" + " | | _.|\n" + " `-_|.-\n"} +}; + +char toaster_mask[3][99] = { { + + " __._ \n" + " .-'== _',\n" + " <|_=X.-'XX|\n" + " |X--|XXX\\'.-_ \n" + " |XXX|X\\XX\"X_.\n" + " `-_|.-\\_.-\n"}, + { + + " __._ \n" + " .-'== _',\n" + " \\|_= .-'XX|\n" + " |X--|XX__'-.\n" + " |XXX|X___.-\n" + " `-_|.-\n"}, +{ + " _- __._\n" + " /.-'== _',_.-.\n" + " \\|_= .-'/XX_.'\n" + " |X--|X/X.-\n" + " |XXX|XX_.|\n" + " `-_|.-\n"} +}; + +struct flying_toaster +{ + int x[COUNT], y[COUNT], s[COUNT]; + caca_canvas_t **toaster; + caca_canvas_t **mask; +}; + +void screensaver_flying_toasters_init(struct screen_list *screen_list) +{ + struct flying_toaster *flying_toaster; + int w = caca_get_canvas_width(screen_list->cv); + int h = caca_get_canvas_height(screen_list->cv); + int i; + + flying_toaster = malloc(sizeof(struct flying_toaster)); + flying_toaster->toaster = + (caca_canvas_t **) malloc(sizeof(caca_canvas_t *) * 3); + flying_toaster->mask = + (caca_canvas_t **) malloc(sizeof(caca_canvas_t *) * 3); + + for (i = 0; i < 3; i++) + { + flying_toaster->toaster[i] = caca_create_canvas(0, 0); + flying_toaster->mask[i] = caca_create_canvas(0, 0); + caca_import_canvas_from_memory(flying_toaster->toaster[i], + toaster_text[i], + strlen(toaster_text[i]), "utf8"); + caca_import_canvas_from_memory(flying_toaster->mask[i], + toaster_mask[i], + strlen(toaster_mask[i]), "utf8"); + } + + for (i = 0; i < COUNT; i++) + { + flying_toaster->x[i] = (rand() % w) * PRECISION; + flying_toaster->y[i] = (rand() % h) * PRECISION; + flying_toaster->s[i] = (rand() % 3) * PRECISION; + } + + + screen_list->screensaver.data = flying_toaster; +} + +void screensaver_flying_toasters_kill(struct screen_list *screen_list) +{ + struct flying_toaster *flying_toaster = screen_list->screensaver.data; + + caca_free_canvas(flying_toaster->toaster[0]); + caca_free_canvas(flying_toaster->toaster[1]); + caca_free_canvas(flying_toaster->toaster[2]); + free(flying_toaster->toaster); + free(flying_toaster); + screen_list->screensaver.data = NULL; +} + +void screensaver_flying_toasters(struct screen_list *screen_list) +{ + struct flying_toaster *d = screen_list->screensaver.data; + int i, w, h, x, y, s; + if (!d) + return; + + w = caca_get_canvas_width(screen_list->cv); + h = caca_get_canvas_height(screen_list->cv); + + caca_set_color_ansi(screen_list->cv, CACA_WHITE, CACA_BLACK); + caca_clear_canvas(screen_list->cv); + + for (i = 0; i < COUNT; i++) + { + x = d->x[i] / PRECISION; + y = d->y[i] / PRECISION; + s = d->s[i] / PRECISION; + + caca_blit(screen_list->cv, x, y, d->toaster[s], d->mask[s]); + + d->x[i] -= 40; + d->y[i] += 10; + + if (d->x[i] / PRECISION + caca_get_canvas_width(d->toaster[s]) <= 0) + d->x[i] = ((rand() % w) / 3 + w) * PRECISION; + if (d->y[i] / PRECISION >= h) + d->y[i] = ((rand() % h) / 2 - h) * PRECISION; + + d->s[i] = ((d->s[i] + 24) % (3 * PRECISION)); + } +} diff --git a/neercs/old/server.c b/neercs/old/server.c new file mode 100644 index 0000000..3c450e2 --- /dev/null +++ b/neercs/old/server.c @@ -0,0 +1,680 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * 2008-2010 Pascal Terjan + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "neercs.h" + +static void server_init(struct screen_list *screen_list); +static void refresh_screen(struct screen_list *screen_list, int refresh); +static int handle_key(struct screen_list *screen_list, unsigned int c, + int refresh); +static int handle_attach(struct screen_list *screen_list, char *buf); + +static int send_to_client(const char *msg, int size, + struct screen_list *screen_list) +{ + int ret; + if (!screen_list->comm.socket[SOCK_CLIENT]) + connect_socket(screen_list, SOCK_CLIENT); + if (!screen_list->comm.socket[SOCK_CLIENT]) + ret = -1; + else + ret = write(screen_list->comm.socket[SOCK_CLIENT], msg, size); + if (ret < 0 && errno != EAGAIN) + { + fprintf(stderr, "Failed to send message to client: %s\n", + strerror(errno)); + if (screen_list->comm.attached) + detach(screen_list); + } + return ret; +} + +static int set_title(struct screen_list *screen_list) +{ + char buf[1024]; + int bytes; + char *title = NULL; + + if (screen_list->comm.attached) + { + if (screen_list->pty < screen_list->count && + screen_list->screen[screen_list->pty]->title) + title = screen_list->screen[screen_list->pty]->title; + else + title = PACKAGE_STRING; + } + + if (screen_list->title) + { + if (!strcmp(screen_list->title, title)) + return 0; + free(screen_list->title); + } + + screen_list->title = strdup(title); + + bytes = snprintf(buf, sizeof(buf) - 1, "TITLE %s", title); + buf[bytes] = '\0'; + return send_to_client(buf, strlen(buf), screen_list); +} + +static int set_cursor(int state, struct screen_list *screen_list) +{ + char buf[16]; + int bytes; + + bytes = snprintf(buf, sizeof(buf) - 1, "CURSOR %d", state); + buf[bytes] = '\0'; + + return send_to_client(buf, strlen(buf), screen_list); +} + +static int request_refresh(struct screen_list *screen_list) +{ + int ndirty = caca_get_dirty_rect_count(screen_list->cv); + if (!ndirty) + return 0; + if (!screen_list->comm.socket[SOCK_CLIENT]) + connect_socket(screen_list, SOCK_CLIENT); + if (screen_list->comm.socket[SOCK_CLIENT]) + { + size_t bufsize, towrite; + ssize_t written, ret; + socklen_t optlen = sizeof(bufsize); + size_t bytes; + void *buf; + char buf2[32]; + int x, y, i; + + getsockopt(screen_list->comm.socket[SOCK_CLIENT], SOL_SOCKET, + SO_SNDBUF, &bufsize, &optlen); + bufsize /= 2; + debug("bufsize=%d", bufsize); + + for (i = 0; i < ndirty; i++) + { + int w, h; + caca_get_dirty_rect(screen_list->cv, i, &x, &y, &w, &h); + debug("dirty @%d,%d %dx%d [%dx%d]", x, y, w, h, + caca_get_canvas_width(screen_list->cv), + caca_get_canvas_height(screen_list->cv)); + buf = + caca_export_area_to_memory(screen_list->cv, x, y, w, h, "caca", + &bytes); + debug("Requesting refresh for %d", bytes); + towrite = bytes; + written = 0; + sprintf(buf2, "UPDATE %10d %10d", x, y); + ret = send_to_client(buf2, strlen(buf2) + 1, screen_list); + if (ret < 29) + { + free(buf); + return -1; + } + /* Block to write the end of the message */ + fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, 0); + while (towrite > 0) + { + ssize_t n; + debug("Wrote %d, %d remaining", written, towrite); + n = send_to_client((char *)buf + written, + towrite > bufsize ? bufsize : towrite, + screen_list); + if (n < 0) + { + debug("Can't refresh (%s), with %d bytes (out of %d)", + strerror(errno), + towrite > bufsize ? bufsize : towrite, towrite); + return -1; + } + written += n; + towrite -= n; + } + fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, O_NONBLOCK); + free(buf); + } + sprintf(buf2, "REFRESH %10d %10d", caca_get_cursor_x(screen_list->cv), + caca_get_cursor_y(screen_list->cv)); + /* FIXME check value of r */ + int r = send_to_client(buf2, strlen(buf2) + 1, screen_list); + (void)r; + caca_clear_dirty_rect_list(screen_list->cv); + } + return 0; +} + +int detach(struct screen_list *screen_list) +{ + screen_list->comm.attached = 0; + if (screen_list->lock.lock_on_detach) + screen_list->lock.locked = 1; + if (screen_list->comm.socket[SOCK_CLIENT]) + { + send_to_client("DETACH", 6, screen_list); + close(screen_list->comm.socket[SOCK_CLIENT]); + screen_list->comm.socket[SOCK_CLIENT] = 0; + } + return 0; +} + +static int server_iteration(struct screen_list *screen_list) +{ + int i; + int eof = 0, refresh; + + int quit = 0; + ssize_t n; + char buf[128]; + + /* Read program output */ + refresh = update_screens_contents(screen_list); + + /* Check if we got something from the client */ + while (screen_list->comm.socket[SOCK_SERVER] + && (n = + read(screen_list->comm.socket[SOCK_SERVER], buf, + sizeof(buf) - 1)) > 0) + { + buf[n] = 0; + debug("Received command %s", buf); + if (!strncmp("ATTACH ", buf, 7)) + { + refresh |= handle_attach(screen_list, buf); + } + else if (!strncmp("QUIT", buf, 4)) + { + quit = 1; + } + else if (!strncmp("DELAY ", buf, 6)) + { + /* FIXME check the length before calling atoi */ + screen_list->delay = atoi(buf + 6); + } + else if (!strncmp("RESIZE ", buf, 7)) + { + caca_free_canvas(screen_list->cv); + /* FIXME check the length before calling atoi */ + screen_list->cv = + caca_create_canvas(atoi(buf + 7), atoi(buf + 18)); + screen_list->changed = 1; + refresh = 1; + } + else if (!strncmp("KEY ", buf, 4)) + { + unsigned int c = atoi(buf + 4); + refresh |= handle_key(screen_list, c, refresh); + } + else if (!strncmp("MOUSEP ", buf, 6)) + { + debug("Got mouse press '%s'\n", buf); + int x, y, b; + x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x; + y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y; + b = atoi(buf + 28); + + switch (screen_list->screen[screen_list->pty]->report_mouse) + { + case MOUSE_VT200: + case MOUSE_VT200_HIGHLIGHT: + case MOUSE_BTN_EVENT: + case MOUSE_ANY_EVENT: + sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32); + debug("mousea send ESC[M %d %d %d", (b - 1), x + 32, y + 32); + send_ansi_sequence(screen_list, buf); + break; + case MOUSE_X10: + sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), 32 + x, 32 + y); + debug("mousex send ESC[M %d %d %d", 32 + (b - 1), 32 + x, + 32 + y); + send_ansi_sequence(screen_list, buf); + break; + case MOUSE_NONE: + break; + + } + } + else if (!strncmp("MOUSER ", buf, 6)) + { + debug("Got mouse release '%s'\n", buf); + int x, y, b; + x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x; + y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y; + b = atoi(buf + 28); + + switch (screen_list->screen[screen_list->pty]->report_mouse) + { + case MOUSE_VT200: + case MOUSE_VT200_HIGHLIGHT: + case MOUSE_BTN_EVENT: + case MOUSE_ANY_EVENT: + sprintf(buf, "\x1b[M%c%c%c", 32 + 3, x + 32, y + 32); + send_ansi_sequence(screen_list, buf); + break; + case MOUSE_X10: + sprintf(buf, "\x1b[M%c%c%c", 32 + 3, 32 + x, 32 + y); + send_ansi_sequence(screen_list, buf); + break; + case MOUSE_NONE: + break; + } + } + + else if (!strncmp("MOUSEM ", buf, 6)) + { + debug("Got mouse motion '%s'\n", buf); + int x, y, b; + x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x; + y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y; + b = atoi(buf + 28); + + switch (screen_list->screen[screen_list->pty]->report_mouse) + { + case MOUSE_X10: // X10 reports mouse clicks only + if (b) + { + sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32); + send_ansi_sequence(screen_list, buf); + } + break; + case MOUSE_VT200: + case MOUSE_VT200_HIGHLIGHT: + case MOUSE_BTN_EVENT: + if (b) + { + sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32); + send_ansi_sequence(screen_list, buf); + } + case MOUSE_ANY_EVENT: + sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32); + send_ansi_sequence(screen_list, buf); + break; + case MOUSE_NONE: + break; + } + } + else + { + fprintf(stderr, "Unknown command received: %s\n", buf); + } + } + + /* No more screens, exit */ + if (!screen_list->count) + return -1; + + /* User requested to exit */ + if (quit) + return -2; + + /* Update each screen canvas */ + refresh |= update_terms(screen_list); + + /* Launch recurrents if any */ + refresh |= handle_recurrents(screen_list); + + /* Refresh screen */ + refresh_screen(screen_list, refresh); + + eof = 1; + for (i = 0; i < screen_list->count; i++) + if (screen_list->screen[i]->fd >= 0) + eof = 0; + if (eof) + return -3; + + return 0; +} + +static void server_main(struct screen_list *screen_list) +{ + screen_list->last_key_time = 0; + screen_list->comm.attached = 0; + screen_list->command = 0; + screen_list->was_in_bell = 0; + screen_list->last_refresh_time = 0; + + server_init(screen_list); +#ifdef USE_PYTHON + python_init(screen_list); +#endif + + for (;;) + { + if (server_iteration(screen_list)) + break; + } + + detach(screen_list); + + free_screen_list(screen_list); + +#ifdef USE_PYTHON + python_close(screen_list); +#endif + + exit(0); +} + +static void refresh_screen(struct screen_list *screen_list, int refresh) +{ + if (!screen_list->comm.attached) + { + /* No need to refresh Don't use the CPU too much Would be better to + select on terms + socket */ + sleep(1); + } + else + { + long long unsigned int current_time = get_us(); + long long int tdiff = + (current_time - screen_list->last_refresh_time) / 1000; + + refresh |= screen_list->need_refresh; + + if (screen_list->force_refresh) + { + wm_refresh(screen_list); + refresh = 1; + } + + /* Draw lock window */ + if (screen_list->lock.locked) + { + /* FIXME don't redraw it each iteration */ + draw_lock(screen_list); + refresh = 1; + } +#ifdef USE_LOCK + else if ((current_time - screen_list->last_key_time >= + screen_list->lock.autolock_timeout)) + { + screen_list->lock.locked = 1; + refresh = 1; + } +#endif + else if ((current_time - screen_list->last_key_time >= + screen_list->screensaver.timeout)) + { + if (!screen_list->screensaver.in_screensaver) + { + screensaver_init(screen_list); + screen_list->screensaver.in_screensaver = 1; + set_cursor(0, screen_list); + } + draw_screensaver(screen_list); + refresh = 1; + } + else if (refresh || screen_list->was_in_bell) + { + if (tdiff >= screen_list->delay) + { + refresh_screens(screen_list); + set_title(screen_list); + refresh = 1; + } + } + if (refresh) + { + if (tdiff >= screen_list->delay) + { + request_refresh(screen_list); + screen_list->last_refresh_time = current_time; + screen_list->need_refresh = 0; + } + else + { + debug("Skipping refresh (%lld < %d)", tdiff, + screen_list->delay); + screen_list->need_refresh = 1; + } + } + } +} + +static void server_init(struct screen_list *screen_list) +{ + int i; + debug("Screen list at %p\n", screen_list); + + /* Create socket and bind it */ + create_socket(screen_list, SOCK_SERVER); + + /* Connect to the client */ + connect_socket(screen_list, SOCK_CLIENT); + + screen_list->width = screen_list->height = 80; + + /* Create main canvas */ + screen_list->cv = caca_create_canvas(screen_list->width, + screen_list->height + + screen_list->modals.mini * 6 + + screen_list->modals.status); + + if (!screen_list->sys.to_grab && !screen_list->sys.to_start) + { + add_screen(screen_list, + create_screen(screen_list->width, + screen_list->height, + screen_list->sys.default_shell)); + } + + /* Attach processes */ + if (screen_list->sys.to_grab) + { + for (i = 0; screen_list->sys.to_grab[i]; i++) + { + add_screen(screen_list, + create_screen_grab(screen_list->width, + screen_list->height, + screen_list->sys.to_grab[i])); + } + free(screen_list->sys.to_grab); + screen_list->sys.to_grab = NULL; + } + + /* Launch command line processes */ + if (screen_list->sys.to_start) + { + for (i = 0; screen_list->sys.to_start[i]; i++) + { + add_screen(screen_list, + create_screen(screen_list->width, + screen_list->height, + screen_list->sys.to_start[i])); + free(screen_list->sys.to_start[i]); + } + free(screen_list->sys.to_start); + screen_list->sys.to_start = NULL; + } + + screen_list->last_key_time = get_us(); +} + +static int handle_attach(struct screen_list *screen_list, char *buf) +{ + /* If we were attached to someone else, detach first */ + if (screen_list->comm.attached) + detach(screen_list); + screen_list->comm.attached = 1; + caca_free_canvas(screen_list->cv); + screen_list->cv = caca_create_canvas(atoi(buf + 7), atoi(buf + 18)); + screen_list->delay = atoi(buf + 29); + screen_list->changed = 1; + return 1; +} + +static int handle_key(struct screen_list *screen_list, unsigned int c, + int refresh) +{ + char *str = NULL; + int size = 0; + + if (screen_list->modals.help) + { + return help_handle_key(screen_list, c); + } +#ifdef USE_PYTHON + if (screen_list->modals.python_command) + { + return python_command_handle_key(screen_list, c); + } +#endif + + /* CTRL-A has been pressed before, handle this as a command, except that + CTRL-A a sends literal CTRL-A */ + if (screen_list->command && (c != 'a')) + { + screen_list->command = 0; + refresh |= handle_command_input(screen_list, c); + } + else + { + /* Not in command mode */ + screen_list->last_key_time = get_us(); + set_cursor(1, screen_list); + + /* Kill screensaver */ + if (screen_list->screensaver.in_screensaver) + { + screensaver_kill(screen_list); + screen_list->screensaver.in_screensaver = 0; + screen_list->changed = 1; + refresh = 1; + return refresh; + } + /* Handle lock window */ + if (screen_list->lock.locked) + { + refresh |= update_lock(c, screen_list); + screen_list->changed = 1; + } + else if (screen_list->modals.window_list) + { + refresh |= update_window_list(c, screen_list); + screen_list->changed = 1; + } + else + { + switch (c) + { + case 0x01: // CACA_KEY_CTRL_A: + screen_list->command = 1; + break; + default: + /* CTRL-A a sends literal CTRL-A */ + if (screen_list->command && (c == 'a')) + { + c = 0x01; + } + /* Normal key, convert it if needed */ + str = convert_input_ansi(&c, &size); + /* FIXME check value of r */ + int r = write(screen_list->screen[screen_list->pty]->fd, str, + size); + (void)r; + break; + } + } + } + return refresh; +} + +int send_ansi_sequence(struct screen_list *screen_list, char *str) +{ + debug("Sending ansi '%s'\n", str); + return write(screen_list->screen[screen_list->pty]->fd, str, strlen(str)); +} + + +int install_fds(struct screen_list *screen_list) +{ + int fd; + close(0); + close(1); + close(2); + fd = open("/dev/null", O_RDWR, 0); + if (fd < 0) + { + perror("Failed to open /dev/null"); + return -2; + } + dup2(fd, 0); +#ifndef DEBUG + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) + close(fd); +#else + if (fd != 0) + close(fd); + screen_list->outfd = + open("/tmp/neercs-debug.txt", O_TRUNC | O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR); + dup2(screen_list->outfd, 1); + dup2(screen_list->outfd, 2); + if (screen_list->outfd > 2) + close(screen_list->outfd); +#endif + return 0; +} + +int start_server(struct screen_list *screen_list) +{ + pid_t pid; + + pid = fork(); + if (pid < 0) + { + perror("Failed to create child process"); + return -1; + } + if (pid == 0) + { + int r = install_fds(screen_list); + if (r) + return r; + setsid(); + + server_main(screen_list); + /* Never returns */ + } + + return 0; +} + +long long get_us(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * (1000000) + tv.tv_usec); +} diff --git a/neercs/old/term.c b/neercs/old/term.c new file mode 100644 index 0000000..032f9b5 --- /dev/null +++ b/neercs/old/term.c @@ -0,0 +1,133 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include +#include +#if defined HAVE_PTY_H +# include /* for openpty and forkpty */ +#elif defined HAVE_UTIL_H +# include /* for OS X, OpenBSD and NetBSD */ +#elif defined HAVE_LIBUTIL_H +# include /* for FreeBSD */ +#endif +#include +#include + +#include + +#include "neercs.h" + + +int create_pty(char *cmd, unsigned int w, unsigned int h, int *cpid) +{ + char **argv; + int fd; + pid_t pid; + + pid = forkpty(&fd, NULL, NULL, NULL); + if (pid < 0) + { + fprintf(stderr, "forkpty() error\n"); + return -1; + } + else if (pid == 0) + { + set_tty_size(0, w, h); + putenv("CACA_DRIVER=slang"); + putenv("TERM=xterm"); + argv = malloc(2 * sizeof(char *)); + if (!argv) + { + fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, + __LINE__); + return -1; + } + argv[0] = cmd; + argv[1] = NULL; + execvp(cmd, argv); + fprintf(stderr, "execvp() error\n"); + return -1; + } + + *cpid = pid; + + fcntl(fd, F_SETFL, O_NDELAY); + return fd; +} + +int create_pty_grab(long pid, unsigned int w, unsigned int h, int *newpid) +{ + int fdm, fds; + + int ret = openpty(&fdm, &fds, NULL, NULL, NULL); + + if (ret < 0) + { + fprintf(stderr, "open() error\n"); + return -1; + } + + set_tty_size(0, w, h); + grab_process(pid, ptsname(fdm), fds, newpid); + + fcntl(fdm, F_SETFL, O_NDELAY); + return fdm; +} + +int set_tty_size(int fd, unsigned int w, unsigned int h) +{ + struct winsize ws; + + memset(&ws, 0, sizeof(ws)); + ws.ws_row = h; + ws.ws_col = w; + ioctl(fd, TIOCSWINSZ, (char *)&ws); + + return 0; +} + + + +int update_terms(struct screen_list *screen_list) +{ + int i, refresh = 0; + for (i = 0; i < screen_list->count; i++) + { + if (screen_list->screen[i]->total && !screen_list->dont_update_coords) + { + unsigned long int bytes; + + bytes = import_term(screen_list, + screen_list->screen[i], + screen_list->screen[i]->buf, + screen_list->screen[i]->total); + + if (bytes > 0) + { + screen_list->screen[i]->total -= bytes; + memmove(screen_list->screen[i]->buf, + screen_list->screen[i]->buf + bytes, + screen_list->screen[i]->total); + if (screen_list->screen[i]->visible || screen_list->modals.mini) + refresh = 1; + } + } + } + return refresh; +} diff --git a/neercs/old/widgets.c b/neercs/old/widgets.c new file mode 100644 index 0000000..a181660 --- /dev/null +++ b/neercs/old/widgets.c @@ -0,0 +1,176 @@ +/* + * neercs console-based window manager + * Copyright (c) 2009-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + + +#include "widgets.h" + +static void widget_ibox_add_char(struct input_box *box, unsigned int c); +static void widget_ibox_del_char(struct input_box *box); + +struct input_box *widget_ibox_init(caca_canvas_t *cv, int w, int h) +{ + struct input_box *box = malloc(sizeof(struct input_box)); + if (!box) + return NULL; + box->cv = cv; + box->w = w; + box->h = h; + box->command = NULL; + box->output_err = NULL; + box->output_res = NULL; + + return box; +} + + +int widget_ibox_draw(struct input_box *box) +{ + int x = (caca_get_canvas_width(box->cv) - box->w) / 2; + int y = (caca_get_canvas_height(box->cv) - box->h) / 2; + + caca_set_color_ansi(box->cv, CACA_BLUE, CACA_BLUE); + caca_fill_box(box->cv, x, y, box->w, box->h, '#'); + caca_set_color_ansi(box->cv, CACA_DEFAULT, CACA_BLUE); + caca_draw_cp437_box(box->cv, x, y, box->w, box->h); + caca_printf(box->cv, x, y, "Mini-command"); + + caca_printf(box->cv, x + 2, y + 2, + "[___________________________________________________________]"); + + if (box->command) + { + caca_printf(box->cv, x + 3, y + 2, "%s", box->command); + caca_gotoxy(box->cv, x + 3 + box->x, y + 2); + } + else + { + caca_gotoxy(box->cv, x + 3, y + 2); + } + + if (box->output_err) + { + caca_set_color_ansi(box->cv, CACA_RED, CACA_BLUE); + caca_printf(box->cv, x + 2, y + 4, box->output_err); + } + if (box->output_res) + { + caca_set_color_ansi(box->cv, CACA_LIGHTGREEN, CACA_BLUE); + caca_printf(box->cv, x + 2, y + 4, box->output_res); + } + + return 0; +} + +char *widget_ibox_get_text(struct input_box *box) +{ + return box->command; +} + +void widget_ibox_destroy(struct input_box *box) +{ + if(!box) return; + if (box->command) + free(box->command); + if (box->output_err) + free(box->output_err); + if (box->output_res) + free(box->output_res); +} + +void widget_ibox_set_error(struct input_box *box, char *err) +{ + box->output_err = err; +} + +void widget_ibox_set_msg(struct input_box *box, char *msg) +{ + box->output_res = msg; +} + +int widget_ibox_handle_key(struct input_box *box, unsigned int c) +{ + if (c == CACA_KEY_ESCAPE) + { + if (box->command) + { + free(box->command); + box->command = NULL; + } + return INPUT_BOX_ESC; + } + else if (c == CACA_KEY_LEFT) + { + if (box->x) + box->x--; + } + else if (c == CACA_KEY_RIGHT) + { + if (box->x < box->size - 1) + box->x++; + } + else if (c == CACA_KEY_RETURN) + { + return INPUT_BOX_RET; + } + else + { + if (c >= ' ' && c < 127) + widget_ibox_add_char(box, c); + else if (c == 8) + { + widget_ibox_del_char(box); + } + } + return INPUT_BOX_NOTHING; +} + + + +static void widget_ibox_add_char(struct input_box *box, unsigned int c) +{ + /* FIXME handle return values */ + if (!box->command) + { + box->size = 1; + box->x = 0; + box->command = (char *)malloc(2); + box->command[0] = 0; + } + else + { + box->command = (char *)realloc(box->command, box->size + 1); + } + memmove(&box->command[box->x + 1], + &box->command[box->x], (box->size - box->x)); + + box->command[box->x] = c; + box->x++; + box->size++; +} + +static void widget_ibox_del_char(struct input_box *box) +{ + if (box->x < 1) + return; + if (box->size > 1) + box->size--; + else + return; + + memcpy(&box->command[box->x - 1], &box->command[box->x], box->size - box->x); + + box->command = (char *)realloc(box->command, box->size); + + if (box->x) + box->x--; + box->command[box->size - 1] = 0; +} diff --git a/neercs/old/widgets.h b/neercs/old/widgets.h new file mode 100644 index 0000000..b8e045d --- /dev/null +++ b/neercs/old/widgets.h @@ -0,0 +1,47 @@ +/* + * neercs console-based window manager + * Copyright (c) 2009-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + + +enum input_box_code +{ + INPUT_BOX_ESC, + INPUT_BOX_RET, + INPUT_BOX_NOTHING, +}; + +struct input_box +{ + caca_canvas_t *cv; + int x, y; + int w, h; + int size; + char *command; + char *output_err; + char *output_res; +}; + +struct input_box *widget_ibox_init(caca_canvas_t * cv, int w, int h); +int widget_ibox_draw(struct input_box *box); +int widget_ibox_handle_key(struct input_box *box, unsigned int c); +char* widget_ibox_get_text(struct input_box *box); +void widget_ibox_destroy(struct input_box *box); +void widget_ibox_set_error(struct input_box *box, char *err); +void widget_ibox_set_msg(struct input_box *box, char *msg); diff --git a/neercs/old/wm.c b/neercs/old/wm.c new file mode 100644 index 0000000..006192a --- /dev/null +++ b/neercs/old/wm.c @@ -0,0 +1,513 @@ +/* + * neercs console-based window manager + * Copyright (c) 2006-2010 Sam Hocevar + * 2008-2010 Jean-Yves Lamoureux + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "neercs.h" + + +void resize_screen(struct screen *s, int w, int h) +{ + caca_canvas_t *old, *new; + + if (w == s->w && h == s->h) + return; + if (w <= 0 || h <= 0) + return; + + s->changed = 1; + + s->w = w; + s->h = h; + + /* + * caca_set_canvas_boundaries() is bugged as hell, so let's resize it by + * hands + */ + old = s->cv; + new = caca_create_canvas(w, h); + caca_blit(new, 0, 0, old, NULL); + s->cv = new; + caca_gotoxy(new, caca_get_cursor_x(old), caca_get_cursor_y(old)); + caca_free_canvas(old); + set_tty_size(s->fd, w, h); + + s->orig_w = s->w; + s->orig_h = s->h; + s->orig_x = s->x; + s->orig_y = s->y; +} + +void update_windows_props(struct screen_list *screen_list) +{ + debug("%s, %d screens, type %d\n", __FUNCTION__, screen_list->count, + screen_list->wm_type); + + if (!screen_list->count) + return; + + switch (screen_list->wm_type) + { + case WM_CARD: + update_windows_props_cards(screen_list); + break; + case WM_HSPLIT: + update_windows_props_hsplit(screen_list); + break; + case WM_VSPLIT: + update_windows_props_vsplit(screen_list); + break; + case WM_FULL: + default: + update_windows_props_full(screen_list); + break; + } +} + +void update_windows_props_hsplit(struct screen_list *screen_list) +{ + int i; + int w = + (screen_list->width / screen_list->count) - + (screen_list->border_size * 2); + int h = screen_list->height - (screen_list->border_size * 2); + + for (i = 0; i < screen_list->count; i++) + { + screen_list->screen[i]->x = (i * w) + screen_list->border_size; + screen_list->screen[i]->y = screen_list->border_size; + screen_list->screen[i]->visible = 1; + if (i != screen_list->count - 1) + { + resize_screen(screen_list->screen[i], w - 1, h); + } + else + { + resize_screen(screen_list->screen[i], + screen_list->width - i * w - 2, h); + } + } +} + +void update_windows_props_vsplit(struct screen_list *screen_list) +{ + int i; + int w = screen_list->width - (screen_list->border_size * 2); + int h = (screen_list->height) / screen_list->count; + + for (i = 0; i < screen_list->count; i++) + { + screen_list->screen[i]->x = screen_list->border_size; + screen_list->screen[i]->y = (i * h) + (screen_list->border_size); + screen_list->screen[i]->visible = 1; + if (i != screen_list->count - 1) + { + resize_screen(screen_list->screen[i], w, + h - (screen_list->border_size * 2)); + } + else + { + resize_screen(screen_list->screen[i], + w, + screen_list->height - i * h - + (screen_list->border_size * 2)); + } + } +} + + +void update_windows_props_full(struct screen_list *screen_list) +{ + int i; + int w = screen_list->width - (screen_list->border_size * 2); + int h = screen_list->height - (screen_list->border_size * 2); + + for (i = 0; i < screen_list->count; i++) + { + screen_list->screen[i]->visible = 0; + screen_list->screen[i]->x = screen_list->border_size; + screen_list->screen[i]->y = screen_list->border_size; + + resize_screen(screen_list->screen[i], w, h); + } + screen_list->screen[screen_list->pty]->visible = 1; +} + + +void update_windows_props_cards(struct screen_list *screen_list) +{ + int i; + int w = (screen_list->width - screen_list->count * 3) + 1; + int h = (screen_list->height - screen_list->count) - 1; + int x = 1; + int y = screen_list->count; + + for (i = 0; i < screen_list->count; i++) + { + screen_list->screen[i]->visible = 1; + screen_list->screen[i]->x = x; + screen_list->screen[i]->y = y; + + resize_screen(screen_list->screen[i], w, h); + x += 3; + y--; + } +} + +/* Window managers refresh */ + +void wm_refresh(struct screen_list *screen_list) +{ + /* FIXME : move set_color to a relevant place */ + caca_set_color_ansi(screen_list->cv, CACA_LIGHTRED, CACA_BLACK); + + switch (screen_list->wm_type) + { + case WM_CARD: + wm_refresh_card(screen_list); + break; + case WM_HSPLIT: + wm_refresh_hsplit(screen_list); + break; + case WM_VSPLIT: + wm_refresh_hsplit(screen_list); + break; + case WM_FULL: + default: + wm_refresh_cube(screen_list); + break; + } +} + +static void wm_bell(struct screen_list *screen_list) +{ + if (screen_list->screen[screen_list->pty]->bell) + { + caca_set_color_ansi(screen_list->cv, CACA_RED, CACA_BLACK); + screen_list->in_bell--; + screen_list->force_refresh = 1; + if (!screen_list->in_bell) + { + screen_list->was_in_bell = 1; + screen_list->screen[screen_list->pty]->bell = 0; + } + } + else + { + if (screen_list->was_in_bell) + { + screen_list->screen[screen_list->pty]->bell = 0; + screen_list->force_refresh = 1; + screen_list->was_in_bell = 0; + screen_list->changed = 1; + } + caca_set_color_ansi(screen_list->cv, CACA_LIGHTGREEN, CACA_BLACK); + } +} + +static void wm_box(struct screen_list *screen_list, int pty) +{ + if (!screen_list->screen[pty]->changed && !screen_list->changed) + return; + + if (!screen_list->border_size) + return; + + /* Color determined by wm_bell() */ + caca_draw_cp437_box(screen_list->cv, + screen_list->screen[pty]->x - 1, + screen_list->screen[pty]->y - 1, + screen_list->screen[pty]->w + 2, + screen_list->screen[pty]->h + 2); + + if (screen_list->screen[pty]->title) + { + caca_printf(screen_list->cv, + screen_list->screen[pty]->x, + screen_list->screen[pty]->y - 1, + " %.*s ", + screen_list->screen[pty]->w - 3, + screen_list->screen[pty]->title); + } +} + +static void wm_blit_current_screen(struct screen_list *screen_list) +{ + if (screen_list->screen[screen_list->pty]->changed || screen_list->changed) + caca_blit(screen_list->cv, + screen_list->screen[screen_list->pty]->x, + screen_list->screen[screen_list->pty]->y, + screen_list->screen[screen_list->pty]->cv, NULL); +} + +void wm_refresh_card(struct screen_list *screen_list) +{ + int i; + + for (i = screen_list->count - 1; i >= 0; i--) + { + if (i != screen_list->pty && screen_list->screen[i]->visible && + (screen_list->screen[i]->changed || screen_list->changed)) + { + caca_blit(screen_list->cv, + screen_list->screen[i]->x, + screen_list->screen[i]->y, + screen_list->screen[i]->cv, NULL); + + wm_box(screen_list, i); + } + } + + /* Force 'changed' to force redraw */ + screen_list->screen[screen_list->pty]->changed = 1; + wm_blit_current_screen(screen_list); + wm_bell(screen_list); + wm_box(screen_list, screen_list->pty); +} + +void wm_refresh_full(struct screen_list *screen_list) +{ + wm_blit_current_screen(screen_list); + wm_bell(screen_list); + wm_box(screen_list, screen_list->pty); +} + +void wm_refresh_vsplit(struct screen_list *screen_list) +{ + int i; + + for (i = screen_list->count - 1; i >= 0; i--) + { + if (i != screen_list->pty && screen_list->screen[i]->visible && + (screen_list->screen[i]->changed || screen_list->changed)) + { + caca_blit(screen_list->cv, + screen_list->screen[i]->x, + screen_list->screen[i]->y, + screen_list->screen[i]->cv, NULL); + + wm_box(screen_list, i); + } + } + + wm_blit_current_screen(screen_list); + wm_bell(screen_list); + wm_box(screen_list, screen_list->pty); +} + +void wm_refresh_hsplit(struct screen_list *screen_list) +{ + int i; + + for (i = screen_list->count - 1; i >= 0; i--) + { + if (i != screen_list->pty && screen_list->screen[i]->visible && + (screen_list->screen[i]->changed || screen_list->changed)) + { + caca_blit(screen_list->cv, + screen_list->screen[i]->x, + screen_list->screen[i]->y, + screen_list->screen[i]->cv, NULL); + + wm_box(screen_list, i); + } + } + + wm_blit_current_screen(screen_list); + wm_bell(screen_list); + wm_box(screen_list, screen_list->pty); +} + + +static float +get_direction(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) +{ + float d1x, d1y, d2x, d2y; + + d1x = p3x - p1x; + d1y = p3y - p1y; + d2x = p3x - p2x; + d2y = p3y - p2y; + return (d1x * d2y) - (d1y * d2x); +} + + +/* 3D Cube. Yeah I know, it's a mess. Just look anywhere else. */ +static void draw_face(caca_canvas_t * cv, + int p1x, int p1y, + int p2x, int p2y, + int p3x, int p3y, + int p4x, int p4y, caca_canvas_t * tex, + int color, int borders) +{ + if (get_direction(p1x, p1y, p2x, p2y, p3x, p3y) >= 0) + { + int coords[6]; + float uv[6]; + coords[0] = p1x; + coords[1] = p1y; + coords[2] = p2x; + coords[3] = p2y; + coords[4] = p3x; + coords[5] = p3y; + uv[0] = 1; + uv[1] = 1; + uv[2] = 0; + uv[3] = 1; + uv[4] = 0; + uv[5] = 0; + caca_fill_triangle_textured(cv, coords, tex, uv); + coords[0] = p1x; + coords[1] = p1y; + coords[2] = p3x; + coords[3] = p3y; + coords[4] = p4x; + coords[5] = p4y; + uv[0] = 1; + uv[1] = 1; + uv[2] = 0; + uv[3] = 0; + uv[4] = 1; + uv[5] = 0; + caca_fill_triangle_textured(cv, coords, tex, uv); + caca_set_color_ansi(cv, color, CACA_BLACK); + if (borders) + { + caca_draw_thin_line(cv, p1x, p1y, p2x, p2y); + caca_draw_thin_line(cv, p2x, p2y, p3x, p3y); + caca_draw_thin_line(cv, p3x, p3y, p4x, p4y); + caca_draw_thin_line(cv, p4x, p4y, p1x, p1y); + } + } +} + + +void wm_refresh_cube(struct screen_list *screen_list) +{ + int i; + + if (!screen_list->cube.in_switch || !screen_list->eyecandy) + { + wm_refresh_full(screen_list); + // screen_list->force_refresh = 0; + } + else + { + long long unsigned int cur_time = get_us() - screen_list->last_switch; + + if (cur_time >= screen_list->cube.duration || screen_list->count == 1) + { + screen_list->changed = 1; + screen_list->force_refresh = 1; + screen_list->cube.in_switch = 0; + } + else + { + float cube[12][3] = { + {-1, -1, 1}, + {1, -1, 1}, + {1, 1, 1}, + {-1, 1, 1}, + + {1, -1, 1}, + {1, -1, -1}, + {1, 1, -1}, + {1, 1, 1}, + + {-1, -1, -1}, + {-1, -1, 1}, + {-1, 1, 1}, + {-1, 1, -1}, + }; + + float cube_transformed[12][3]; + float cube_projected[12][2]; + float fov = 0.5f; + float angle = + 90.0f * ((float)cur_time / (float)screen_list->cube.duration); + + angle *= (M_PI / 180.0f); + + if (screen_list->cube.side == 1) + angle = -angle; + + float sina = sin(angle); + float cosa = cos(angle); + + for (i = 0; i < 12; i++) + { + cube_transformed[i][2] = cube[i][2] * cosa - cube[i][0] * sina; + cube_transformed[i][0] = cube[i][2] * sina + cube[i][0] * cosa; + cube_transformed[i][1] = cube[i][1]; + + cube_transformed[i][2] -= 3; + + cube_projected[i][0] = + cube_transformed[i][0] / (cube_transformed[i][2] * fov); + cube_projected[i][1] = + cube_transformed[i][1] / (cube_transformed[i][2] * fov); + + cube_projected[i][0] /= 2.0f; + cube_projected[i][1] /= 2.0f; + cube_projected[i][0] += 0.5f; + cube_projected[i][1] += 0.5f; + + cube_projected[i][0] *= screen_list->width; + cube_projected[i][1] *= screen_list->height; + } + + caca_set_color_ansi(screen_list->cv, CACA_WHITE, CACA_BLACK); + caca_clear_canvas(screen_list->cv); + + caca_canvas_t *first = + screen_list->screen[screen_list->prevpty]->cv; + caca_canvas_t *second = screen_list->screen[screen_list->pty]->cv; + + draw_face(screen_list->cv, + cube_projected[0][0], cube_projected[0][1], + cube_projected[1][0], cube_projected[1][1], + cube_projected[2][0], cube_projected[2][1], + cube_projected[3][0], cube_projected[3][1], + first, CACA_LIGHTGREEN, screen_list->border_size); + + + if (screen_list->cube.side) + { + draw_face(screen_list->cv, + cube_projected[4][0], cube_projected[4][1], + cube_projected[5][0], cube_projected[5][1], + cube_projected[6][0], cube_projected[6][1], + cube_projected[7][0], cube_projected[7][1], + second, CACA_LIGHTGREEN, screen_list->border_size); + } + else + { + draw_face(screen_list->cv, + cube_projected[8][0], cube_projected[8][1], + cube_projected[9][0], cube_projected[9][1], + cube_projected[10][0], cube_projected[10][1], + cube_projected[11][0], cube_projected[11][1], + second, CACA_LIGHTGREEN, screen_list->border_size); + } + + screen_list->changed = 1; + screen_list->force_refresh = 1; + screen_list->cube.in_switch = 1; + } + } +}