From b2c69322a3c8d80b1e39a5fff0529b80df0e0105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se> Date: Tue, 23 Dec 1997 22:52:33 +0100 Subject: [PATCH] Opening a display works. Rev: lib/modules/Protocols.pmod/X.pmod/Xlib.pmod:1.2 Rev: lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod:1.1 Rev: lib/modules/Protocols.pmod/X.pmod/my_struct.pmod:1.1 --- lib/modules/Protocols.pmod/X.pmod/Xlib.pmod | 335 ++++++++++++++++-- lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod | 6 + .../Protocols.pmod/X.pmod/my_struct.pmod | 138 ++++++++ 3 files changed, 456 insertions(+), 23 deletions(-) create mode 100644 lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod create mode 100644 lib/modules/Protocols.pmod/X.pmod/my_struct.pmod diff --git a/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod b/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod index 9176c3dd27..81581e0397 100644 --- a/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod +++ b/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod @@ -2,24 +2,93 @@ * */ -object display_re = Regexp("([^:]+):([0-9]+).([0-9]+)"); - #define error(x) throw( ({ (x), backtrace() }) ) -constant XPORT 6000 -constant STATE_WAIT_FOR_CONNECT +constant XPORT = 6000; + +class rec_buffer +{ + string buffer; + int expected; + int pad; + + void create() + { + buffer = ""; + expected = pad = 0; + } + + void expect(int e) + { + expected = e; + } + + int needs() + { + return pad + expected - strlen(buffer); + } + + void add_data(string data) + { + buffer += data; + } + + string get_msg() + { + if (strlen(buffer) < (expected + pad)) + return 0; + string res = buffer[pad..pad+expected-1]; + buffer = buffer[pad+expected..]; + pad = (- expected) % 4; + return res; + } +} class Display { + import _Xlib; + inherit Stdio.File; + program Struct = my_struct.struct; + + constant STATE_WAIT_CONNECT = 0; + constant STATE_WAIT_CONNECT_DATA = 1; + constant STATE_WAIT_CONNECT_FAILURE = 2; + constant STATE_WAIT_HEADER = 3; + constant STATE_WAIT_REPLY = 4; + constant STATE_CLOSED = 4711; + + constant ACTION_CONNECT = 0; + constant ACTION_CONNECT_FAILED = 1; + constant ACTION_EVENT = 2; + constant ACTION_REPLY = 3; + constant ACTION_ERROR = 4; + int screen_number; string buffer; - + object received; + int state; + function io_error_handler; function error_handler; function close_handler; - function connected_callback; + function connect_handler; + function event_handler; + function reply_handler; + + /* Information about the X server */ + int majorVersion, minorVersion; /* Servers protocol version */ + int release; + int ridBase, ridMask; + int motionBufferSize; + string vendor; + int maxRequestSize; + array roots; + array formats; + int imageByteOrder, bitmapBitOrder; + int bitmapScanlineUnit, bitmapScanlinePad; + int minKeyCode, maxKeyCode; void write_callback() { @@ -34,7 +103,7 @@ class Display { buffer = buffer[written..]; if (!strlen(buffer)) - buffer->set_write_callback(0); + set_write_callback(0); } } @@ -45,19 +114,204 @@ class Display set_write_callback(write_callback); } + void default_error_handler(object me, mapping e) + { + error(sprintf("Xlib: Unhandled error %O\n", e)); + } + + string previous; /* Partially read reply or event */ + + array got_data(string data) + { + received->add_data(data); + string msg; + while (msg = received->get_msg()) + switch(state) + { + case STATE_WAIT_CONNECT: { + int success; + int len_reason; + int length; + + sscanf(msg, "%c%c%2c%2c%2c", + success, len_reason, + majorVersion, minorVersion, length); + if (success) + { + received->expect(length*4); + state = STATE_WAIT_CONNECT_DATA; + } else { + received->expect(len_reason); + state = STATE_WAIT_CONNECT_FAILURE; + } + break; + } + case STATE_WAIT_CONNECT_FAILURE: + return ({ ACTION_CONNECT_FAILED, msg }); + close(); + state = STATE_CLOSED; + break; + case STATE_WAIT_CONNECT_DATA: { + int nbytesVendor, numRoots, numFormats; + object struct = Struct(msg); + + release = struct->get_uint(4); + ridBase = struct->get_uint(4); + ridMask = struct->get_uint(4); + motionBufferSize = struct->get_uint(4); + nbytesVendor = struct->get_uint(2); + maxRequestSize = struct->get_uint(2); + numRoots = struct->get_uint(1); + numFormats = struct->get_uint(1); + imageByteOrder = struct->get_uint(1); + bitmapBitOrder = struct->get_uint(1); + bitmapScanlineUnit = struct->get_uint(1); + bitmapScanlinePad = struct->get_uint(1); + minKeyCode = struct->get_uint(1); + maxKeyCode = struct->get_uint(1); + /* pad2 */ struct->get_fix_string(4); + + vendor = struct->get_fix_string(nbytesVendor); + /* pad */ struct->get_fix_string( (- nbytesVendor) % 4); + + int i; + formats = allocate(numFormats); + for(i=0; i<numFormats; i++) + { + mapping m = ([]); + m->depth = struct->get_uint(1); + m->bitsPerPixel = struct->get_uint(1); + m->scanLinePad = struct->get_uint(1); + /* pad */ struct->get_fix_string(5); + formats[i] = m; + } + + roots = allocate(numRoots); + for(i=0; i<numRoots; i++) + { + mapping m = ([]); + m->windowId = struct->get_uint(4); + m->defaultColorMap = struct->get_uint(4); + m->whitePixel = struct->get_uint(4); + m->blackPixel = struct->get_uint(4); + m->currentInputMask = struct->get_uint(4); + m->pixWidth = struct->get_uint(2); + m->pixHeight = struct->get_uint(2); + m->mmWidth = struct->get_uint(2); + m->mmHeight = struct->get_uint(2); + m->minInstalledMaps = struct->get_uint(2); + m->maxInstalledMaps = struct->get_uint(2); + m->rootVisualID = struct->get_uint(4); + m->backingStore = struct->get_uint(1); + m->saveUnders = struct->get_uint(1); + m->rootDepth = struct->get_uint(1); + int nDepths = struct->get_uint(1); + + m->depths = allocate(nDepths); + for (int j=0; j<nDepths; j++) + { + mapping d = ([]); + d->depth = struct->get_uint(1); + /* pad */ struct->get_fix_string(1); + int nVisuals = struct->get_uint(2); + /* pad */ struct->get_fix_string(4); + + d->visuals = allocate(nVisuals); + for(int k=0; k<nVisuals; k++) + { + mapping v = ([]); + v->visualID = struct->get_uint(4); + v->c_class = struct->get_uint(1); + v->bitsPerRGB = struct->get_uint(1); + v->colorMapEntries = struct->get_uint(2); + v->redMask = struct->get_uint(4); + v->greenMask = struct->get_uint(4); + v->blueMask = struct->get_uint(4); + /* pad */ struct->get_fix_string(4); + d->visuals[k] = v; + } + m->depths[j] = d; + } + roots[i] = m; + } + state = STATE_WAIT_HEADER; + received->expect(32); + return ({ ACTION_CONNECT }); + } + case STATE_WAIT_HEADER: + received->expect(32); /* Correct for most of the cases */ + switch(msg[0]) + { + case 0: { /* X_Error */ + mapping m = ([]); + sscanf(msg, "%*c%c%2c%4c%2c%c", + m->errorCode, m->sequence_number, m->resourceID, + m->minorCode, m->majorCode); + return ({ ACTION_ERROR, m }); + } + case 1: { /* X_Reply */ + int length; + sscanf(msg[2..3], "%2c", length); + if (!length) + return ({ ACTION_REPLY, msg }); + + state = STATE_WAIT_REPLY; + received->expect(length*4); + previous = msg; + + break; + } + case 11: /* KeymapNotify */ + return ({ ACTION_EVENT, + ([ "type" : "KeymapNotify", + "map" : msg[1..] ]) }); + + default: /* Any other event */ + return ({ ACTION_EVENT, + ([ "type" : "Unimplemented", + "raw" : msg ]) }); + + } + break; + case STATE_WAIT_REPLY: + state = STATE_WAIT_HEADER; + received->expect(32); + return ({ ACTION_REPLY, previous + msg }); + } + return 0; + } + void read_callback(mixed id, string data) { - switch(state) - { - case WAIT_FOR_CONNECT: - - } + array a = got_data(data); + if (a) + switch(a[0]) + { + case ACTION_CONNECT: + connect_handler(this_object(), 1); + break; + case ACTION_CONNECT_FAILED: + connect_handler(this_object(), 0, a[1]); + break; + case ACTION_EVENT: + event_handler(this_object(), a[1]); + break; + case ACTION_REPLY: + reply_handler(this_object(), a[1]); + break; + case ACTION_ERROR: + (error_handler || default_error_handler)(this_object(), a[1]); + break; + default: + error("Xlib.Display->read_callback: internal error\n"); + break; + } } void close_callback(mixed id) { - if (state == WAIT_FOR_CONNECT) - connected_handler(this_object(), 0); + if (state == STATE_WAIT_CONNECT) + connect_handler(this_object(), 0); else if (close_handler) close_handler(this_object()); @@ -68,25 +322,60 @@ class Display int open(string|void display) { + int async = !!connect_handler; + display = display || getenv("DISPLAY"); if (!display) error("Xlib.pmod: $DISPLAY not set!\n"); - array(string) fields display_re->split(display); + array(string) fields = display_re->split(display); if (!fields) error("Xlib.pmod: Invalid display name!\n"); - set_nonblocking(0, 0, close_callback); - if (!connect(fields[0], XPORT + (int) fields[1])) - error("Xlib.pmod: Connection to " + display + " failed.\n"); + string host = strlen(fields[0]) ? fields[0] : "localhost"; - screen_number = (int) fields[2]; + if (async) + /* Asynchronous connection */ + set_nonblocking(0, 0, close_callback); + + if (!connect(host, XPORT + (int) fields[1])) + return 0; + screen_number = (int) fields[2]; + buffer = ""; + received = rec_buffer(); + /* Always uses network byteorder (big endian) * No authentication */ - send(sprintf("B\0%2c%2c%2c%2c\0\0", 11, 0, 0, 0)); - state = WAITING_FOR_CONNECT; + string msg = sprintf("B\0%2c%2c%2c%2c\0\0", 11, 0, 0, 0); + state = STATE_WAIT_CONNECT; + received->expect(8); + if (async) + { + send(msg); + set_nonblocking(read_callback, 0, close_callback); + return 1; + } + if (strlen(msg) != write(msg)) + return 0; + while(1) { + string data = read(received->needs()); + if (!data) + return 0; + array a = got_data(data); + if (!a) + continue; + switch(a[0]) + { + case ACTION_CONNECT: + set_nonblocking(read_callback, 0, close_callback); + return 1; + case ACTION_CONNECT_FAILED: + return 0; + default: + error("Xlib.Display->open: Internal error!\n"); + } + } } - - +} diff --git a/lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod b/lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod new file mode 100644 index 0000000000..930875a5e8 --- /dev/null +++ b/lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod @@ -0,0 +1,6 @@ +/* _Xlib.pmod + * + * kluge + */ + +object display_re = Regexp("([^:]*):([0-9]+).([0-9]+)"); diff --git a/lib/modules/Protocols.pmod/X.pmod/my_struct.pmod b/lib/modules/Protocols.pmod/X.pmod/my_struct.pmod new file mode 100644 index 0000000000..c05e452a27 --- /dev/null +++ b/lib/modules/Protocols.pmod/X.pmod/my_struct.pmod @@ -0,0 +1,138 @@ +/* my_struct.pmod + * + * This should replace ADT.struct at some time. + */ + +#define error(x) throw( ({ (x), backtrace() }) ) +// #include "error.h" + +class struct { + string buffer; + int index; + + void create(void|string s) + { + buffer = s || ""; + index = 0; + } + + /* Return data, without removing it */ + string contents() + { + buffer = buffer[index..]; + index = 0; + return buffer; + } + + void add_data(string s) + { + buffer += s; + } + + string pop_data() + { + string res = buffer; + create(); + return res; + } + + void put_uint(int i, int len) + { + if (i<0) + error("ADT.struct->put_uint: negative argument.\n"); + + add_data(sprintf("%*c", len, i)); + } + + void put_var_string(string s, int len) + { + if ( (len <= 3) && (strlen(s) >= ({ -1, 0x100, 0x10000, 0x1000000 })[len] )) + error("ADT.struct->put_var_String: Field overflow.\n"); + put_uint(strlen(s), len); + add_data(s); + } + + void put_bignum(object i, int|void len) + { + if (i<0) + error("ADT.struct->put_ubignum: negative argument.\n"); + put_var_string(i->digits(256), len || 2); + } + + void put_fix_string(string s) + { + add_data(s); + } + +#if 0 + void put_fix_array(array(int) data, int item_size) + { + foreach(data, int i) + put_int(i, item_size); + } + + void put_var_array(array(int) data, int item_size, int len) + { + put_int(sizeof(data), len); + put_fix_array(data, item_size); + } +#endif + + int get_uint(int len) + { + mixed i; + if ( (strlen(buffer) - index) < len) + error("ADT.struct->get_uint: no data\n"); + sscanf(buffer, "%*" + (string) index +"s%" + (string) len + "c", i); + index += len; + return i; + } + + string get_fix_string(int len) + { + string res; + + if ((strlen(buffer) - index) < len) + error("ADT.struct->get_fix_string: no data\n"); + res = buffer[index .. index + len - 1]; + index += len; + return res; + } + + string get_var_string(int len) + { + return get_fix_string(get_uint(len)); + } + + object get_bignum(int|void len) + { + return Gmp.mpz(get_var_string(len || 2), 256); + } + + string get_rest() + { + string s = buffer[index..]; + create(); + return s; + } + +#if 0 + array(mixed) get_fix_array(int item_size, int size) + { + array(mixed) res = allocate(size); + for(int i = 0; i<size; i++) + res[i] = get_int(item_size); + return res; + } + + array(mixed) get_var_array(int item_size, int len) + { + return get_fix_array(item_size, get_int(len)); + } +#endif + + int is_empty() + { + return (index == strlen(buffer)); + } +} -- GitLab