blob: 370cedb0a7c3c809bcfe1b9589eebf0f9d180061 [file] [log] [blame]
Patrick Georgi3b77b722011-07-07 15:41:53 +02001/* Public Domain Curses */
2
3#include "pdcx11.h"
4
5RCSID("$Id: pdcx11.c,v 1.96 2008/07/14 04:24:52 wmcbrine Exp $")
6
7#include <errno.h>
8#include <stdlib.h>
9
10/*** Functions that are called by both processes ***/
11
12unsigned char *Xcurscr;
13
14int XCursesProcess = 1;
15int shmidSP;
16int shmid_Xcurscr;
17int shmkeySP;
18int shmkey_Xcurscr;
19int xc_otherpid;
20int XCursesLINES = 24;
21int XCursesCOLS = 80;
22int xc_display_sock;
23int xc_key_sock;
24int xc_display_sockets[2];
25int xc_key_sockets[2];
26int xc_exit_sock;
27
28fd_set xc_readfds;
29
30static void _dummy_function(void)
31{
32}
33
34void XC_get_line_lock(int row)
35{
36 /* loop until we can write to the line -- Patch by:
37 Georg Fuchs, georg.fuchs@rz.uni-regensburg.de */
38
39 while (*(Xcurscr + XCURSCR_FLAG_OFF + row))
40 _dummy_function();
41
42 *(Xcurscr + XCURSCR_FLAG_OFF + row) = 1;
43}
44
45void XC_release_line_lock(int row)
46{
47 *(Xcurscr + XCURSCR_FLAG_OFF + row) = 0;
48}
49
50int XC_write_socket(int sock_num, const void *buf, int len)
51{
52 int start = 0, rc;
53
54 PDC_LOG(("%s:XC_write_socket called: sock_num %d len %d\n",
55 XCLOGMSG, sock_num, len));
56
57#ifdef MOUSE_DEBUG
58 if (sock_num == xc_key_sock)
59 printf("%s:XC_write_socket(key) len: %d\n", XCLOGMSG, len);
60#endif
61 while (1)
62 {
63 rc = write(sock_num, buf + start, len);
64
65 if (rc < 0 || rc == len)
66 return rc;
67
68 len -= rc;
69 start = rc;
70 }
71}
72
73int XC_read_socket(int sock_num, void *buf, int len)
74{
75 int start = 0, length = len, rc;
76
77 PDC_LOG(("%s:XC_read_socket called: sock_num %d len %d\n",
78 XCLOGMSG, sock_num, len));
79
80 while (1)
81 {
82 rc = read(sock_num, buf + start, length);
83
84#ifdef MOUSE_DEBUG
85 if (sock_num == xc_key_sock)
86 printf("%s:XC_read_socket(key) rc %d errno %d "
87 "resized: %d\n", XCLOGMSG, rc, errno, SP->resized);
88#endif
89 if (rc < 0 && sock_num == xc_key_sock && errno == EINTR
90 && SP->resized != FALSE)
91 {
92 MOUSE_LOG(("%s:continuing\n", XCLOGMSG));
93
94 rc = 0;
95
96 if (SP->resized > 1)
97 SP->resized = TRUE;
98 else
99 SP->resized = FALSE;
100
101 memcpy(buf, &rc, sizeof(int));
Stefan Reinauere11835e2011-10-31 12:54:00 -0700102
Patrick Georgi3b77b722011-07-07 15:41:53 +0200103 return 0;
104 }
105
106 if (rc <= 0 || rc == length)
107 return rc;
108
109 length -= rc;
110 start = rc;
111 }
112}
113
114int XC_write_display_socket_int(int x)
115{
116 return XC_write_socket(xc_display_sock, &x, sizeof(int));
117}
118
119#ifdef PDCDEBUG
120void XC_say(const char *msg)
121{
122 PDC_LOG(("%s:%s", XCLOGMSG, msg));
123}
124#endif
125
126/*** Functions that are called by the "curses" process ***/
127
128int XCursesInstruct(int flag)
129{
130 PDC_LOG(("%s:XCursesInstruct() - called flag %d\n", XCLOGMSG, flag));
131
132 /* Send a request to X */
133
134 if (XC_write_display_socket_int(flag) < 0)
135 XCursesExitCursesProcess(4, "exiting from XCursesInstruct");
136
137 return OK;
138}
139
140int XCursesInstructAndWait(int flag)
141{
142 int result;
143
144 XC_LOG(("XCursesInstructAndWait() - called\n"));
145
146 /* tell X we want to do something */
147
148 XCursesInstruct(flag);
149
150 /* wait for X to say the refresh has occurred*/
151
152 if (XC_read_socket(xc_display_sock, &result, sizeof(int)) < 0)
153 XCursesExitCursesProcess(5, "exiting from XCursesInstructAndWait");
154
155 if (result != CURSES_CONTINUE)
156 XCursesExitCursesProcess(6, "exiting from XCursesInstructAndWait"
157 " - synchronization error");
158
159 return OK;
160}
161
162static int _setup_curses(void)
163{
164 int wait_value;
165
166 XC_LOG(("_setup_curses called\n"));
167
168 close(xc_display_sockets[1]);
169 close(xc_key_sockets[1]);
170
171 xc_display_sock = xc_display_sockets[0];
172 xc_key_sock = xc_key_sockets[0];
173
174 FD_ZERO(&xc_readfds);
175
176 XC_read_socket(xc_display_sock, &wait_value, sizeof(int));
177
178 if (wait_value != CURSES_CHILD)
179 return ERR;
180
Stefan Reinauere11835e2011-10-31 12:54:00 -0700181 /* Set LINES and COLS now so that the size of the shared memory
Patrick Georgi3b77b722011-07-07 15:41:53 +0200182 segment can be allocated */
183
184 if ((shmidSP = shmget(shmkeySP, sizeof(SCREEN) + XCURSESSHMMIN, 0700)) < 0)
185 {
186 perror("Cannot allocate shared memory for SCREEN");
187 kill(xc_otherpid, SIGKILL);
188 return ERR;
189 }
190
191 SP = (SCREEN*)shmat(shmidSP, 0, 0);
192
193 XCursesLINES = SP->lines;
194 LINES = XCursesLINES - SP->linesrippedoff - SP->slklines;
195 XCursesCOLS = COLS = SP->cols;
196
197 if ((shmid_Xcurscr = shmget(shmkey_Xcurscr,
198 SP->XcurscrSize + XCURSESSHMMIN, 0700)) < 0)
199 {
200 perror("Cannot allocate shared memory for curscr");
201 kill(xc_otherpid, SIGKILL);
202 return ERR;
203 }
204
205 PDC_LOG(("%s:shmid_Xcurscr %d shmkey_Xcurscr %d LINES %d COLS %d\n",
206 XCLOGMSG, shmid_Xcurscr, shmkey_Xcurscr, LINES, COLS));
207
208 Xcurscr = (unsigned char *)shmat(shmid_Xcurscr, 0, 0);
209 xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF);
210
211 XC_LOG(("cursesprocess exiting from Xinitscr\n"));
212
213 /* Always trap SIGWINCH if the C library supports SIGWINCH */
214
215 XCursesSetSignal(SIGWINCH, XCursesSigwinchHandler);
216
217 atexit(XCursesExit);
218
219 return OK;
220}
221
222int XCursesInitscr(int argc, char *argv[])
223{
224 int pid, rc;
225
226 XC_LOG(("XCursesInitscr() - called\n"));
227
228 shmkeySP = getpid();
Stefan Reinauere11835e2011-10-31 12:54:00 -0700229
Patrick Georgi3b77b722011-07-07 15:41:53 +0200230 if (socketpair(AF_UNIX, SOCK_STREAM, 0, xc_display_sockets) < 0)
231 {
232 fprintf(stderr, "ERROR: cannot create display socketpair\n");
233 return ERR;
234 }
Stefan Reinauere11835e2011-10-31 12:54:00 -0700235
Patrick Georgi3b77b722011-07-07 15:41:53 +0200236 if (socketpair(AF_UNIX, SOCK_STREAM, 0, xc_key_sockets) < 0)
237 {
238 fprintf(stderr, "ERROR: cannot create key socketpair\n");
239 return ERR;
240 }
241
242 pid = fork();
243
244 switch(pid)
245 {
246 case -1:
247 fprintf(stderr, "ERROR: cannot fork()\n");
248 return ERR;
249 break;
250
251 case 0: /* child */
252 shmkey_Xcurscr = getpid();
253#ifdef XISPARENT
254 XCursesProcess = 0;
255 rc = _setup_curses();
256#else
257 XCursesProcess = 1;
258 xc_otherpid = getppid();
259 rc = XCursesSetupX(argc, argv);
260#endif
261 break;
262
263 default: /* parent */
264 shmkey_Xcurscr = pid;
265#ifdef XISPARENT
266 XCursesProcess = 1;
267 xc_otherpid = pid;
268 rc = XCursesSetupX(argc, argv);
269#else
270 XCursesProcess = 0;
271 rc = _setup_curses();
272#endif
273 }
274
275 return rc;
276}
277
278static void _cleanup_curses_process(int rc)
279{
280 PDC_LOG(("%s:_cleanup_curses_process() - called: %d\n", XCLOGMSG, rc));
281
282 shutdown(xc_display_sock, 2);
283 close(xc_display_sock);
284
285 shutdown(xc_key_sock, 2);
286 close(xc_key_sock);
287
288 shmdt((char *)SP);
289 shmdt((char *)Xcurscr);
290
291 if (rc)
292 _exit(rc);
293}
294
295void XCursesExitCursesProcess(int rc, char *msg)
296{
297 PDC_LOG(("%s:XCursesExitCursesProcess() - called: %d %s\n",
298 XCLOGMSG, rc, msg));
299
300 endwin();
301 _cleanup_curses_process(rc);
302}
303
304void XCursesExit(void)
305{
306 static bool called = FALSE;
307
308 XC_LOG(("XCursesExit() - called\n"));
309
310 if (FALSE == called)
311 {
312 XCursesInstruct(CURSES_EXIT);
313 _cleanup_curses_process(0);
314
315 called = TRUE;
316 }
317}