/* Public Domain Curses */ #include "pdcx11.h" RCSID("$Id: pdcx11.c,v 1.96 2008/07/14 04:24:52 wmcbrine Exp $") #include #include /*** 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; } }