1 /* Public Domain Curses */
2
3 #include "pdcx11.h"
4
5 RCSID("$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
12 unsigned char *Xcurscr;
13
14 int XCursesProcess = 1;
15 int shmidSP;
16 int shmid_Xcurscr;
17 int shmkeySP;
18 int shmkey_Xcurscr;
19 int xc_otherpid;
20 int XCursesLINES = 24;
21 int XCursesCOLS = 80;
22 int xc_display_sock;
23 int xc_key_sock;
24 int xc_display_sockets[2];
25 int xc_key_sockets[2];
26 int xc_exit_sock;
27
28 fd_set xc_readfds;
29
_dummy_function(void)30 static void _dummy_function(void)
31 {
32 }
33
XC_get_line_lock(int row)34 void XC_get_line_lock(int row)
35 {
36 /* loop until we can write to the line -- Patch by:
37 Georg Fuchs, [email protected] */
38
39 while (*(Xcurscr + XCURSCR_FLAG_OFF + row))
40 _dummy_function();
41
42 *(Xcurscr + XCURSCR_FLAG_OFF + row) = 1;
43 }
44
XC_release_line_lock(int row)45 void XC_release_line_lock(int row)
46 {
47 *(Xcurscr + XCURSCR_FLAG_OFF + row) = 0;
48 }
49
XC_write_socket(int sock_num,const void * buf,int len)50 int 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
XC_read_socket(int sock_num,void * buf,int len)73 int 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));
102
103 return 0;
104 }
105
106 if (rc <= 0 || rc == length)
107 return rc;
108
109 length -= rc;
110 start = rc;
111 }
112 }
113
XC_write_display_socket_int(int x)114 int XC_write_display_socket_int(int x)
115 {
116 return XC_write_socket(xc_display_sock, &x, sizeof(int));
117 }
118
119 #ifdef PDCDEBUG
XC_say(const char * msg)120 void 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
XCursesInstruct(int flag)128 int 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
XCursesInstructAndWait(int flag)140 int 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
_setup_curses(void)162 static 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
181 /* Set LINES and COLS now so that the size of the shared memory
182 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
XCursesInitscr(int argc,char * argv[])222 int XCursesInitscr(int argc, char *argv[])
223 {
224 int pid, rc;
225
226 XC_LOG(("XCursesInitscr() - called\n"));
227
228 shmkeySP = getpid();
229
230 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 }
235
236 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
_cleanup_curses_process(int rc)278 static 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
XCursesExitCursesProcess(int rc,char * msg)295 void 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
XCursesExit(void)304 void 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 }
318