318 lines
6.9 KiB
C
318 lines
6.9 KiB
C
/* 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;
|
|
}
|
|
}
|