blob: 370cedb0a7c3c809bcfe1b9589eebf0f9d180061 [file] [log] [blame]
/* 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;
}
}