| /* Public Domain Curses */ |
| |
| #include "pdcx11.h" |
| |
| RCSID("$Id: pdcx11.c,v 1.96 2008/07/14 04:24:52 wmcbrine Exp $") |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| |
| /*** Functions that are called by both processes ***/ |
| |
| unsigned char *Xcurscr; |
| |
| int XCursesProcess = 1; |
| int shmidSP; |
| int shmid_Xcurscr; |
| int shmkeySP; |
| int shmkey_Xcurscr; |
| int xc_otherpid; |
| int XCursesLINES = 24; |
| int XCursesCOLS = 80; |
| int xc_display_sock; |
| int xc_key_sock; |
| int xc_display_sockets[2]; |
| int xc_key_sockets[2]; |
| int xc_exit_sock; |
| |
| fd_set xc_readfds; |
| |
| static void _dummy_function(void) |
| { |
| } |
| |
| void XC_get_line_lock(int row) |
| { |
| /* loop until we can write to the line -- Patch by: |
| Georg Fuchs, georg.fuchs@rz.uni-regensburg.de */ |
| |
| while (*(Xcurscr + XCURSCR_FLAG_OFF + row)) |
| _dummy_function(); |
| |
| *(Xcurscr + XCURSCR_FLAG_OFF + row) = 1; |
| } |
| |
| void XC_release_line_lock(int row) |
| { |
| *(Xcurscr + XCURSCR_FLAG_OFF + row) = 0; |
| } |
| |
| int XC_write_socket(int sock_num, const void *buf, int len) |
| { |
| int start = 0, rc; |
| |
| PDC_LOG(("%s:XC_write_socket called: sock_num %d len %d\n", |
| XCLOGMSG, sock_num, len)); |
| |
| #ifdef MOUSE_DEBUG |
| if (sock_num == xc_key_sock) |
| printf("%s:XC_write_socket(key) len: %d\n", XCLOGMSG, len); |
| #endif |
| while (1) |
| { |
| rc = write(sock_num, buf + start, len); |
| |
| if (rc < 0 || rc == len) |
| return rc; |
| |
| len -= rc; |
| start = rc; |
| } |
| } |
| |
| int XC_read_socket(int sock_num, void *buf, int len) |
| { |
| int start = 0, length = len, rc; |
| |
| PDC_LOG(("%s:XC_read_socket called: sock_num %d len %d\n", |
| XCLOGMSG, sock_num, len)); |
| |
| while (1) |
| { |
| rc = read(sock_num, buf + start, length); |
| |
| #ifdef MOUSE_DEBUG |
| if (sock_num == xc_key_sock) |
| printf("%s:XC_read_socket(key) rc %d errno %d " |
| "resized: %d\n", XCLOGMSG, rc, errno, SP->resized); |
| #endif |
| if (rc < 0 && sock_num == xc_key_sock && errno == EINTR |
| && SP->resized != FALSE) |
| { |
| MOUSE_LOG(("%s:continuing\n", XCLOGMSG)); |
| |
| rc = 0; |
| |
| if (SP->resized > 1) |
| SP->resized = TRUE; |
| else |
| SP->resized = FALSE; |
| |
| memcpy(buf, &rc, sizeof(int)); |
| |
| return 0; |
| } |
| |
| if (rc <= 0 || rc == length) |
| return rc; |
| |
| length -= rc; |
| start = rc; |
| } |
| } |
| |
| int XC_write_display_socket_int(int x) |
| { |
| return XC_write_socket(xc_display_sock, &x, sizeof(int)); |
| } |
| |
| #ifdef PDCDEBUG |
| void XC_say(const char *msg) |
| { |
| PDC_LOG(("%s:%s", XCLOGMSG, msg)); |
| } |
| #endif |
| |
| /*** Functions that are called by the "curses" process ***/ |
| |
| int XCursesInstruct(int flag) |
| { |
| PDC_LOG(("%s:XCursesInstruct() - called flag %d\n", XCLOGMSG, flag)); |
| |
| /* Send a request to X */ |
| |
| if (XC_write_display_socket_int(flag) < 0) |
| XCursesExitCursesProcess(4, "exiting from XCursesInstruct"); |
| |
| return OK; |
| } |
| |
| int XCursesInstructAndWait(int flag) |
| { |
| int result; |
| |
| XC_LOG(("XCursesInstructAndWait() - called\n")); |
| |
| /* tell X we want to do something */ |
| |
| XCursesInstruct(flag); |
| |
| /* wait for X to say the refresh has occurred*/ |
| |
| if (XC_read_socket(xc_display_sock, &result, sizeof(int)) < 0) |
| XCursesExitCursesProcess(5, "exiting from XCursesInstructAndWait"); |
| |
| if (result != CURSES_CONTINUE) |
| XCursesExitCursesProcess(6, "exiting from XCursesInstructAndWait" |
| " - synchronization error"); |
| |
| return OK; |
| } |
| |
| static int _setup_curses(void) |
| { |
| int wait_value; |
| |
| XC_LOG(("_setup_curses called\n")); |
| |
| close(xc_display_sockets[1]); |
| close(xc_key_sockets[1]); |
| |
| xc_display_sock = xc_display_sockets[0]; |
| xc_key_sock = xc_key_sockets[0]; |
| |
| FD_ZERO(&xc_readfds); |
| |
| XC_read_socket(xc_display_sock, &wait_value, sizeof(int)); |
| |
| if (wait_value != CURSES_CHILD) |
| return ERR; |
| |
| /* Set LINES and COLS now so that the size of the shared memory |
| segment can be allocated */ |
| |
| if ((shmidSP = shmget(shmkeySP, sizeof(SCREEN) + XCURSESSHMMIN, 0700)) < 0) |
| { |
| perror("Cannot allocate shared memory for SCREEN"); |
| kill(xc_otherpid, SIGKILL); |
| return ERR; |
| } |
| |
| SP = (SCREEN*)shmat(shmidSP, 0, 0); |
| |
| XCursesLINES = SP->lines; |
| LINES = XCursesLINES - SP->linesrippedoff - SP->slklines; |
| XCursesCOLS = COLS = SP->cols; |
| |
| if ((shmid_Xcurscr = shmget(shmkey_Xcurscr, |
| SP->XcurscrSize + XCURSESSHMMIN, 0700)) < 0) |
| { |
| perror("Cannot allocate shared memory for curscr"); |
| kill(xc_otherpid, SIGKILL); |
| return ERR; |
| } |
| |
| PDC_LOG(("%s:shmid_Xcurscr %d shmkey_Xcurscr %d LINES %d COLS %d\n", |
| XCLOGMSG, shmid_Xcurscr, shmkey_Xcurscr, LINES, COLS)); |
| |
| Xcurscr = (unsigned char *)shmat(shmid_Xcurscr, 0, 0); |
| xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF); |
| |
| XC_LOG(("cursesprocess exiting from Xinitscr\n")); |
| |
| /* Always trap SIGWINCH if the C library supports SIGWINCH */ |
| |
| XCursesSetSignal(SIGWINCH, XCursesSigwinchHandler); |
| |
| atexit(XCursesExit); |
| |
| return OK; |
| } |
| |
| int XCursesInitscr(int argc, char *argv[]) |
| { |
| int pid, rc; |
| |
| XC_LOG(("XCursesInitscr() - called\n")); |
| |
| shmkeySP = getpid(); |
| |
| if (socketpair(AF_UNIX, SOCK_STREAM, 0, xc_display_sockets) < 0) |
| { |
| fprintf(stderr, "ERROR: cannot create display socketpair\n"); |
| return ERR; |
| } |
| |
| if (socketpair(AF_UNIX, SOCK_STREAM, 0, xc_key_sockets) < 0) |
| { |
| fprintf(stderr, "ERROR: cannot create key socketpair\n"); |
| return ERR; |
| } |
| |
| pid = fork(); |
| |
| switch(pid) |
| { |
| case -1: |
| fprintf(stderr, "ERROR: cannot fork()\n"); |
| return ERR; |
| break; |
| |
| case 0: /* child */ |
| shmkey_Xcurscr = getpid(); |
| #ifdef XISPARENT |
| XCursesProcess = 0; |
| rc = _setup_curses(); |
| #else |
| XCursesProcess = 1; |
| xc_otherpid = getppid(); |
| rc = XCursesSetupX(argc, argv); |
| #endif |
| break; |
| |
| default: /* parent */ |
| shmkey_Xcurscr = pid; |
| #ifdef XISPARENT |
| XCursesProcess = 1; |
| xc_otherpid = pid; |
| rc = XCursesSetupX(argc, argv); |
| #else |
| XCursesProcess = 0; |
| rc = _setup_curses(); |
| #endif |
| } |
| |
| return rc; |
| } |
| |
| static void _cleanup_curses_process(int rc) |
| { |
| PDC_LOG(("%s:_cleanup_curses_process() - called: %d\n", XCLOGMSG, rc)); |
| |
| shutdown(xc_display_sock, 2); |
| close(xc_display_sock); |
| |
| shutdown(xc_key_sock, 2); |
| close(xc_key_sock); |
| |
| shmdt((char *)SP); |
| shmdt((char *)Xcurscr); |
| |
| if (rc) |
| _exit(rc); |
| } |
| |
| void XCursesExitCursesProcess(int rc, char *msg) |
| { |
| PDC_LOG(("%s:XCursesExitCursesProcess() - called: %d %s\n", |
| XCLOGMSG, rc, msg)); |
| |
| endwin(); |
| _cleanup_curses_process(rc); |
| } |
| |
| void XCursesExit(void) |
| { |
| static bool called = FALSE; |
| |
| XC_LOG(("XCursesExit() - called\n")); |
| |
| if (FALSE == called) |
| { |
| XCursesInstruct(CURSES_EXIT); |
| _cleanup_curses_process(0); |
| |
| called = TRUE; |
| } |
| } |