Mercurial > vim
comparison src/integration.c @ 7:3fc0f57ecb91 v7.0001
updated for version 7.0001
author | vimboss |
---|---|
date | Sun, 13 Jun 2004 20:20:40 +0000 |
parents | |
children | ddada568db54 |
comparison
equal
deleted
inserted
replaced
6:c2daee826b8f | 7:3fc0f57ecb91 |
---|---|
1 /* vi:set ts=8 sw=8: | |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * Visual Workshop integration by Gordon Prieur | |
5 * | |
6 * Do ":help uganda" in Vim to read copying and usage conditions. | |
7 * Do ":help credits" in Vim to see a list of people who contributed. | |
8 * See README.txt for an overview of the Vim source code. | |
9 */ | |
10 | |
11 /* | |
12 * Integration with Sun Workshop. | |
13 * | |
14 * This file should not change much, it's also used by other editors that | |
15 * connect to Workshop. Consider changing workshop.c instead. | |
16 */ | |
17 /* | |
18 -> consider using MakeSelectionVisible instead of gotoLine hacks | |
19 to show the line properly | |
20 -> consider using glue instead of our own message wrapping functions | |
21 (but can only use glue if we don't have to distribute source) | |
22 */ | |
23 | |
24 #include "vim.h" | |
25 | |
26 #include <stdio.h> | |
27 #include <stdlib.h> | |
28 #include <stdarg.h> | |
29 #include <fcntl.h> | |
30 | |
31 #ifdef INET_SOCKETS | |
32 #include <netdb.h> | |
33 #include <netinet/in.h> | |
34 #else | |
35 #include <sys/un.h> | |
36 #endif | |
37 | |
38 #include <errno.h> | |
39 #include <sys/types.h> | |
40 #include <sys/socket.h> | |
41 #include <sys/param.h> | |
42 #ifdef HAVE_LIBGEN_H | |
43 # include <libgen.h> | |
44 #endif | |
45 #include <unistd.h> | |
46 #include <string.h> | |
47 | |
48 #include <X11/Intrinsic.h> | |
49 #include <Xm/Xm.h> | |
50 #include <Xm/AtomMgr.h> | |
51 #include <Xm/PushB.h> | |
52 | |
53 #ifdef HAVE_X11_XPM_H | |
54 # include <X11/xpm.h> | |
55 #else | |
56 # ifdef HAVE_XM_XPMP_H | |
57 # include <Xm/XpmP.h> | |
58 # endif | |
59 #endif | |
60 | |
61 #ifdef HAVE_UTIL_DEBUG_H | |
62 # include <util/debug.h> | |
63 #endif | |
64 #ifdef HAVE_UTIL_MSGI18N_H | |
65 # include <util/msgi18n.h> | |
66 #endif | |
67 | |
68 #include "integration.h" /* <EditPlugin/integration.h> */ | |
69 #ifdef HAVE_FRAME_H | |
70 # include <frame.h> | |
71 #endif | |
72 | |
73 #ifndef MAX | |
74 # define MAX(a, b) (a) > (b) ? (a) : (b) | |
75 #endif | |
76 | |
77 #ifndef NOCATGETS | |
78 # define NOCATGETS(x) x | |
79 #endif | |
80 | |
81 /* Functions private to this file */ | |
82 static void workshop_connection_closed(void); | |
83 static void messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2); | |
84 static void workshop_disconnect(void); | |
85 static void workshop_sensitivity(int num, char *table); | |
86 static void adjust_sign_name(char *filename); | |
87 static void process_menuItem(char *); | |
88 static void process_toolbarButton(char *); | |
89 static void workshop_set_option_first(char *name, char *value); | |
90 | |
91 | |
92 #define CMDBUFSIZ 2048 | |
93 | |
94 #ifdef DEBUG | |
95 static FILE *dfd; | |
96 static void pldebug(char *, ...); | |
97 static void unrecognised_message(char *); | |
98 | |
99 #define HANDLE_ERRORS(cmd) else unrecognised_message(cmd); | |
100 #else | |
101 #define HANDLE_ERRORS(cmd) | |
102 #endif | |
103 | |
104 /* | |
105 * Version number of the protocol between an editor and eserve. | |
106 * This number should be incremented when the protocol | |
107 * is changed. | |
108 */ | |
109 #define PROTOCOL_VERSION "4.0.0" | |
110 | |
111 static int sd = -1; | |
112 static XtInputId inputHandler; /* Cookie for input */ | |
113 | |
114 Boolean save_files = True; /* When true, save all files before build actions */ | |
115 | |
116 void | |
117 workshop_connection_closed(void) | |
118 { | |
119 /* | |
120 * socket closed on other end | |
121 */ | |
122 XtRemoveInput(inputHandler); | |
123 inputHandler = 0; | |
124 sd = -1; | |
125 } | |
126 | |
127 static char * | |
128 getCommand(void) | |
129 { | |
130 int len; /* length of this command */ | |
131 char lenbuf[7]; /* get the length string here */ | |
132 char *newcb; /* used to realloc cmdbuf */ | |
133 static char *cmdbuf;/* get the command string here */ | |
134 static int cbsize;/* size of cmdbuf */ | |
135 | |
136 if ((len = read(sd, &lenbuf, 6)) == 6) { | |
137 lenbuf[6] = 0; /* Terminate buffer such that atoi() works right */ | |
138 len = atoi(lenbuf); | |
139 if (cbsize < (len + 1)) { | |
140 newcb = (char *) realloc(cmdbuf, | |
141 MAX((len + 256), CMDBUFSIZ)); | |
142 if (newcb != NULL) { | |
143 cmdbuf = newcb; | |
144 cbsize = MAX((len + 256), CMDBUFSIZ); | |
145 } | |
146 } | |
147 if (cbsize >= len && (len = read(sd, cmdbuf, len)) > 0) { | |
148 cmdbuf[len] = 0; | |
149 return cmdbuf; | |
150 } else { | |
151 return NULL; | |
152 } | |
153 } else { | |
154 if (len == 0) { /* EOF */ | |
155 workshop_connection_closed(); | |
156 } | |
157 return NULL; | |
158 } | |
159 | |
160 } | |
161 | |
162 /*ARGSUSED*/ | |
163 void | |
164 messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2) | |
165 { | |
166 char *cmd; /* the 1st word of the command */ | |
167 | |
168 cmd = getCommand(); | |
169 if (cmd == NULL) { | |
170 /* We're being shut down by eserve and the "quit" message | |
171 * didn't arrive before the socket connection got closed */ | |
172 return; | |
173 } | |
174 #ifdef DEBUG | |
175 pldebug("%s\n", cmd); | |
176 #endif | |
177 switch (*cmd) { | |
178 case 'a': | |
179 if (cmd[1] == 'c' && | |
180 strncmp(cmd, NOCATGETS("ack "), 4) == 0) { | |
181 int ackNum; | |
182 char buf[20]; | |
183 | |
184 ackNum = atoi(&cmd[4]); | |
185 sprintf(buf, NOCATGETS("ack %d\n"), ackNum); | |
186 write(sd, buf, strlen(buf)); | |
187 } else if (strncmp(cmd, | |
188 NOCATGETS("addMarkType "), 12) == 0) { | |
189 int idx; | |
190 char *color; | |
191 char *sign; | |
192 | |
193 idx = atoi(strtok(&cmd[12], " ")); | |
194 color = strtok(NULL, NOCATGETS("\001")); | |
195 sign = strtok(NULL, NOCATGETS("\001")); | |
196 /* Skip space that separates names */ | |
197 if (color) { | |
198 color++; | |
199 } | |
200 if (sign) { | |
201 sign++; | |
202 } | |
203 /* Change sign name to accomodate a different size? */ | |
204 adjust_sign_name(sign); | |
205 workshop_add_mark_type(idx, color, sign); | |
206 } | |
207 HANDLE_ERRORS(cmd); | |
208 break; | |
209 | |
210 case 'b': | |
211 if (strncmp(cmd, | |
212 NOCATGETS("balloon "), 8) == 0) { | |
213 char *tip; | |
214 | |
215 tip = strtok(&cmd[8], NOCATGETS("\001")); | |
216 workshop_show_balloon_tip(tip); | |
217 } | |
218 HANDLE_ERRORS(cmd); | |
219 break; | |
220 | |
221 case 'c': | |
222 if (strncmp(cmd, | |
223 NOCATGETS("changeMarkType "), 15) == 0) { | |
224 char *file; | |
225 int markId; | |
226 int type; | |
227 | |
228 file = strtok(&cmd[15], " "); | |
229 markId = atoi(strtok(NULL, " ")); | |
230 type = atoi(strtok(NULL, " ")); | |
231 workshop_change_mark_type(file, markId, type); | |
232 } | |
233 HANDLE_ERRORS(cmd); | |
234 break; | |
235 | |
236 case 'd': | |
237 if (strncmp(cmd, NOCATGETS("deleteMark "), 11) == 0) { | |
238 char *file; | |
239 int markId; | |
240 | |
241 file = strtok(&cmd[11], " "); | |
242 markId = atoi(strtok(NULL, " ")); | |
243 workshop_delete_mark(file, markId); | |
244 } | |
245 HANDLE_ERRORS(cmd); | |
246 break; | |
247 | |
248 case 'f': | |
249 if (cmd[1] == 'o' && | |
250 strncmp(cmd, NOCATGETS("footerMsg "), 10) == 0) { | |
251 int severity; | |
252 char *message; | |
253 | |
254 severity = | |
255 atoi(strtok(&cmd[10], " ")); | |
256 message = strtok(NULL, NOCATGETS("\001")); | |
257 | |
258 workshop_footer_message(message, severity); | |
259 } else if (strncmp(cmd, | |
260 NOCATGETS("frontFile "), 10) == 0) { | |
261 char *file; | |
262 | |
263 file = strtok(&cmd[10], " "); | |
264 workshop_front_file(file); | |
265 } | |
266 HANDLE_ERRORS(cmd); | |
267 break; | |
268 | |
269 case 'g': | |
270 if (cmd[1] == 'e' && | |
271 strncmp(cmd, NOCATGETS("getMarkLine "), 12) == 0) { | |
272 char *file; | |
273 int markid; | |
274 int line; | |
275 char buf[100]; | |
276 | |
277 file = strtok(&cmd[12], " "); | |
278 markid = atoi(strtok(NULL, " ")); | |
279 line = workshop_get_mark_lineno(file, markid); | |
280 sprintf(buf, NOCATGETS("markLine %s %d %d\n"), | |
281 file, markid, line); | |
282 write(sd, buf, strlen(buf)); | |
283 } else if (cmd[1] == 'o' && cmd[4] == 'L' && | |
284 strncmp(cmd, NOCATGETS("gotoLine "), 9) == 0) { | |
285 char *file; | |
286 int lineno; | |
287 | |
288 file = strtok(&cmd[9], " "); | |
289 lineno = atoi(strtok(NULL, " ")); | |
290 workshop_goto_line(file, lineno); | |
291 } else if (strncmp(cmd, | |
292 NOCATGETS("gotoMark "), 9) == 0) { | |
293 char *file; | |
294 int markId; | |
295 char *message; | |
296 | |
297 file = strtok(&cmd[9], " "); | |
298 markId = atoi(strtok(NULL, " ")); | |
299 message = strtok(NULL, NOCATGETS("\001")); | |
300 workshop_goto_mark(file, markId, message); | |
301 #ifdef NOHANDS_SUPPORT_FUNCTIONS | |
302 } else if (strcmp(cmd, NOCATGETS("getCurrentFile")) == 0) { | |
303 char *f = workshop_test_getcurrentfile(); | |
304 char buffer[2*MAXPATHLEN]; | |
305 sprintf(buffer, NOCATGETS("currentFile %d %s"), | |
306 f ? strlen(f) : 0, f ? f : ""); | |
307 workshop_send_message(buffer); | |
308 } else if (strcmp(cmd, NOCATGETS("getCursorRow")) == 0) { | |
309 int row = workshop_test_getcursorrow(); | |
310 char buffer[2*MAXPATHLEN]; | |
311 sprintf(buffer, NOCATGETS("cursorRow %d"), row); | |
312 workshop_send_message(buffer); | |
313 } else if (strcmp(cmd, NOCATGETS("getCursorCol")) == 0) { | |
314 int col = workshop_test_getcursorcol(); | |
315 char buffer[2*MAXPATHLEN]; | |
316 sprintf(buffer, NOCATGETS("cursorCol %d"), col); | |
317 workshop_send_message(buffer); | |
318 } else if (strcmp(cmd, NOCATGETS("getCursorRowText")) == 0) { | |
319 char *t = workshop_test_getcursorrowtext(); | |
320 char buffer[2*MAXPATHLEN]; | |
321 sprintf(buffer, NOCATGETS("cursorRowText %d %s"), | |
322 t ? strlen(t) : 0, t ? t : ""); | |
323 workshop_send_message(buffer); | |
324 } else if (strcmp(cmd, NOCATGETS("getSelectedText")) == 0) { | |
325 char *t = workshop_test_getselectedtext(); | |
326 char buffer[2*MAXPATHLEN]; | |
327 sprintf(buffer, NOCATGETS("selectedText %d %s"), | |
328 t ? strlen(t) : 0, t ? t : ""); | |
329 workshop_send_message(buffer); | |
330 #endif | |
331 } | |
332 HANDLE_ERRORS(cmd); | |
333 break; | |
334 | |
335 case 'l': | |
336 if (strncmp(cmd, NOCATGETS("loadFile "), 9) == 0) { | |
337 char *file; | |
338 int line; | |
339 char *frameid; | |
340 | |
341 file = strtok(&cmd[9], " "); | |
342 line = atoi(strtok(NULL, " ")); | |
343 frameid = strtok(NULL, " "); | |
344 workshop_load_file(file, line, frameid); | |
345 } | |
346 HANDLE_ERRORS(cmd); | |
347 break; | |
348 | |
349 case 'm': /* Menu, minimize, maximize */ | |
350 if (cmd[1] == 'e' && cmd[4] == 'B' && | |
351 strncmp(cmd, NOCATGETS("menuBegin "), 10) == 0) { | |
352 workshop_menu_begin(&cmd[10]); | |
353 } else if (cmd[1] == 'e' && cmd[4] == 'I' && | |
354 strncmp(cmd, NOCATGETS("menuItem "), 9) == 0) { | |
355 process_menuItem(cmd); | |
356 } else if (cmd[1] == 'e' && cmd[4] == 'E' && | |
357 strcmp(cmd, NOCATGETS("menuEnd")) == 0) { | |
358 workshop_menu_end(); | |
359 } else if (cmd[1] == 'a' && | |
360 strcmp(cmd, NOCATGETS("maximize")) == 0) { | |
361 workshop_maximize(); | |
362 } else if (strcmp(cmd, NOCATGETS("minimize")) == 0) { | |
363 workshop_minimize(); | |
364 } | |
365 HANDLE_ERRORS(cmd); | |
366 break; | |
367 | |
368 case 'o': | |
369 if (cmd[1] == 'p' && | |
370 strcmp(cmd, NOCATGETS("option"))) { | |
371 char *name; | |
372 char *value; | |
373 | |
374 name = strtok(&cmd[7], " "); | |
375 value = strtok(NULL, " "); | |
376 workshop_set_option_first(name, value); | |
377 } | |
378 HANDLE_ERRORS(cmd); | |
379 break; | |
380 | |
381 case 'p': | |
382 if (strcmp(cmd, NOCATGETS("ping")) == 0) { | |
383 #if 0 | |
384 int pingNum; | |
385 | |
386 pingNum = atoi(&cmd[5]); | |
387 workshop_send_ack(ackNum); | |
388 WHAT DO I DO HERE? | |
389 #endif | |
390 } | |
391 HANDLE_ERRORS(cmd); | |
392 break; | |
393 | |
394 case 'q': | |
395 if (strncmp(cmd, NOCATGETS("quit"), 4) == 0) { | |
396 | |
397 /* Close the connection. It's important to do | |
398 * that now, since workshop_quit might be | |
399 * looking at open files. For example, if you | |
400 * have modified one of the files without | |
401 * saving, NEdit will ask you what you want to | |
402 * do, and spin loop by calling | |
403 * XtAppProcessEvent while waiting for your | |
404 * reply. In this case, if we still have an | |
405 * input handler and the socket has been | |
406 * closed on the other side when eserve | |
407 * expired, we will hang in IoWait. | |
408 */ | |
409 workshop_disconnect(); | |
410 | |
411 workshop_quit(); | |
412 } | |
413 HANDLE_ERRORS(cmd); | |
414 break; | |
415 | |
416 case 'r': | |
417 if (cmd[1] == 'e' && | |
418 strncmp(cmd, NOCATGETS("reloadFile "), 11) == 0) { | |
419 char *file; | |
420 int line; | |
421 | |
422 file = strtok(&cmd[11], " "); | |
423 line = atoi(strtok(NULL, " ")); | |
424 workshop_reload_file(file, line); | |
425 } | |
426 HANDLE_ERRORS(cmd); | |
427 break; | |
428 | |
429 case 's': | |
430 if (cmd[1] == 'e' && cmd[2] == 't' && | |
431 strncmp(cmd, NOCATGETS("setMark "), 8) == 0) { | |
432 char *file; | |
433 int line; | |
434 int markId; | |
435 int type; | |
436 | |
437 file = strtok(&cmd[8], " "); | |
438 line = atoi(strtok(NULL, " ")); | |
439 markId = atoi(strtok(NULL, " ")); | |
440 type = atoi(strtok(NULL, " ")); | |
441 workshop_set_mark(file, line, markId, type); | |
442 } else if (cmd[1] == 'h' && | |
443 strncmp(cmd, NOCATGETS("showFile "), 9) == 0) { | |
444 workshop_show_file(&cmd[9]); | |
445 } else if (cmd[1] == 'u' && | |
446 strncmp(cmd, NOCATGETS("subMenu "), 8) == 0) { | |
447 char *label; | |
448 | |
449 label = strtok(&cmd[8], NOCATGETS("\001")); | |
450 workshop_submenu_begin(label); | |
451 } else if (cmd[1] == 'u' && | |
452 strcmp(cmd, NOCATGETS("subMenuEnd")) == 0) { | |
453 workshop_submenu_end(); | |
454 } else if (cmd[1] == 'e' && cmd[2] == 'n' && | |
455 strncmp(cmd, NOCATGETS("sensitivity "), 12) == 0) { | |
456 int num; | |
457 char *bracket; | |
458 char *table; | |
459 | |
460 num = atoi(strtok(&cmd[12], " ")); | |
461 bracket = strtok(NULL, " "); | |
462 if (*bracket != '[') { | |
463 fprintf(stderr, NOCATGETS("Parsing " | |
464 "error for sensitivity\n")); | |
465 } else { | |
466 table = strtok(NULL, NOCATGETS("]")); | |
467 workshop_sensitivity(num, table); | |
468 } | |
469 } else if (cmd[1] == 'e' && cmd[2] == 'n' && cmd[3] == 'd' && | |
470 strncmp(cmd, NOCATGETS("sendVerb "), 9) == 0) { | |
471 /* Send the given verb back (used for the | |
472 * debug.lineno callback (such that other tools | |
473 * can obtain the position coordinates or the | |
474 * selection) */ | |
475 char *verb; | |
476 | |
477 verb = strtok(&cmd[9], " "); | |
478 workshop_perform_verb(verb, NULL); | |
479 } else if (cmd[1] == 'a' && | |
480 strncmp(cmd, NOCATGETS("saveFile "), 9) == 0) { | |
481 workshop_save_file(&cmd[9]); | |
482 #ifdef NOHANDS_SUPPORT_FUNCTIONS | |
483 } else if (strncmp(cmd, NOCATGETS("saveSensitivity "), 16) == 0) { | |
484 char *file; | |
485 | |
486 file = strtok(&cmd[16], " "); | |
487 workshop_save_sensitivity(file); | |
488 #endif | |
489 } | |
490 HANDLE_ERRORS(cmd); | |
491 break; | |
492 | |
493 case 't': /* Toolbar */ | |
494 if (cmd[8] == 'e' && | |
495 strncmp(cmd, NOCATGETS("toolbarBegin"), 12) == 0) { | |
496 workshop_toolbar_begin(); | |
497 } else if (cmd[8] == 'u' && | |
498 strncmp(cmd, NOCATGETS("toolbarButton"), 13) == 0) { | |
499 process_toolbarButton(cmd); | |
500 } else if (cmd[7] == 'E' && | |
501 strcmp(cmd, NOCATGETS("toolbarEnd")) == 0) { | |
502 workshop_toolbar_end(); | |
503 } | |
504 HANDLE_ERRORS(cmd); | |
505 break; | |
506 | |
507 #ifdef DEBUG | |
508 default: | |
509 unrecognised_message(cmd); | |
510 break; | |
511 #endif | |
512 } | |
513 } | |
514 | |
515 static void | |
516 process_menuItem( | |
517 char *cmd) | |
518 { | |
519 char *label = strtok(&cmd[9], NOCATGETS("\001")); | |
520 char *verb = strtok(NULL, NOCATGETS("\001")); | |
521 char *acc = strtok(NULL, NOCATGETS("\001")); | |
522 char *accText = strtok(NULL, NOCATGETS("\001")); | |
523 char *name = strtok(NULL, NOCATGETS("\001")); | |
524 char *sense = strtok(NULL, NOCATGETS("\n")); | |
525 char *filepos = strtok(NULL, NOCATGETS("\n")); | |
526 if (*acc == '-') { | |
527 acc = NULL; | |
528 } | |
529 if (*accText == '-') { | |
530 accText = NULL; | |
531 } | |
532 workshop_menu_item(label, verb, acc, accText, name, filepos, sense); | |
533 | |
534 } | |
535 | |
536 | |
537 static void | |
538 process_toolbarButton( | |
539 char *cmd) /* button definition */ | |
540 { | |
541 char *label = strtok(&cmd[14], NOCATGETS("\001")); | |
542 char *verb = strtok(NULL, NOCATGETS("\001")); | |
543 char *senseVerb = strtok(NULL, NOCATGETS("\001")); | |
544 char *filepos = strtok(NULL, NOCATGETS("\001")); | |
545 char *help = strtok(NULL, NOCATGETS("\001")); | |
546 char *sense = strtok(NULL, NOCATGETS("\001")); | |
547 char *file = strtok(NULL, NOCATGETS("\001")); | |
548 char *left = strtok(NULL, NOCATGETS("\n")); | |
549 | |
550 if (!strcmp(label, NOCATGETS("-"))) { | |
551 label = NULL; | |
552 } | |
553 if (!strcmp(help, NOCATGETS("-"))) { | |
554 help = NULL; | |
555 } | |
556 if (!strcmp(file, NOCATGETS("-"))) { | |
557 file = NULL; | |
558 } | |
559 if (!strcmp(senseVerb, NOCATGETS("-"))) { | |
560 senseVerb = NULL; | |
561 } | |
562 workshop_toolbar_button(label, verb, senseVerb, filepos, help, | |
563 sense, file, left); | |
564 } | |
565 | |
566 | |
567 #ifdef DEBUG | |
568 void | |
569 unrecognised_message( | |
570 char *cmd) | |
571 { | |
572 pldebug("Unrecognised eserve message:\n\t%s\n", cmd); | |
573 /* abort(); */ | |
574 } | |
575 #endif | |
576 | |
577 | |
578 /* Change sign name to accomodate a different size: | |
579 * Create the filename based on the height. The filename format | |
580 * of multisize icons are: | |
581 * x.xpm : largest icon | |
582 * x1.xpm : smaller icon | |
583 * x2.xpm : smallest icon */ | |
584 void | |
585 adjust_sign_name(char *filename) | |
586 { | |
587 char *s; | |
588 static int fontSize = -1; | |
589 | |
590 if (fontSize == -1) | |
591 fontSize = workshop_get_font_height(); | |
592 if (fontSize == 0) | |
593 return; | |
594 if (filename[0] == '-') | |
595 return; | |
596 | |
597 /* This is ugly: later we should instead pass the fontheight over | |
598 * to eserve on startup and let eserve just send the right filenames | |
599 * to us in the first place | |
600 | |
601 * I know that the filename will end with 1.xpm (see | |
602 * GuiEditor.cc`LispPrintSign if you wonder why) */ | |
603 s = filename+strlen(filename)-5; | |
604 if (fontSize <= 11) | |
605 strcpy(s, "2.xpm"); | |
606 else if (fontSize <= 15) | |
607 strcpy(s, "1.xpm"); | |
608 else | |
609 strcpy(s, ".xpm"); | |
610 } | |
611 | |
612 /* Were we invoked by WorkShop? This function can be used early during startup | |
613 if you want to do things differently if the editor is started standalone | |
614 or in WorkShop mode. For example, in standalone mode you may not want to | |
615 add a footer/message area or a sign gutter. */ | |
616 int | |
617 workshop_invoked() | |
618 { | |
619 static int result = -1; | |
620 if (result == -1) { | |
621 result = (getenv(NOCATGETS("SPRO_EDITOR_SOCKET")) != NULL); | |
622 } | |
623 return result; | |
624 } | |
625 | |
626 /* Connect back to eserve */ | |
627 void workshop_connect(XtAppContext context) | |
628 { | |
629 #ifdef INET_SOCKETS | |
630 struct sockaddr_in server; | |
631 struct hostent * host; | |
632 int port; | |
633 #else | |
634 struct sockaddr_un server; | |
635 #endif | |
636 char buf[32]; | |
637 char * address; | |
638 #ifdef DEBUG | |
639 char *file; | |
640 #endif | |
641 | |
642 address = getenv(NOCATGETS("SPRO_EDITOR_SOCKET")); | |
643 if (address == NULL) { | |
644 return; | |
645 } | |
646 | |
647 #ifdef INET_SOCKETS | |
648 port = atoi(address); | |
649 | |
650 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { | |
651 PERROR(NOCATGETS("workshop_connect")); | |
652 return; | |
653 } | |
654 | |
655 /* Get the server internet address and put into addr structure */ | |
656 /* fill in the socket address structure and connect to server */ | |
657 memset((char *)&server, '\0', sizeof(server)); | |
658 server.sin_family = AF_INET; | |
659 server.sin_port = port; | |
660 if ((host = gethostbyname(NOCATGETS("localhost"))) == NULL) { | |
661 PERROR(NOCATGETS("gethostbyname")); | |
662 sd = -1; | |
663 return; | |
664 } | |
665 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); | |
666 #else | |
667 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { | |
668 PERROR(NOCATGETS("workshop_connect")); | |
669 return; | |
670 } | |
671 | |
672 server.sun_family = AF_UNIX; | |
673 strcpy(server.sun_path, address); | |
674 #endif | |
675 /* Connect to server */ | |
676 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) { | |
677 if (errno == ECONNREFUSED) { | |
678 close(sd); | |
679 #ifdef INET_SOCKETS | |
680 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { | |
681 PERROR(NOCATGETS("workshop_connect")); | |
682 return; | |
683 } | |
684 #else | |
685 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { | |
686 PERROR(NOCATGETS("workshop_connect")); | |
687 return; | |
688 } | |
689 #endif | |
690 if (connect(sd, (struct sockaddr *)&server, | |
691 sizeof(server))) { | |
692 PERROR(NOCATGETS("workshop_connect")); | |
693 return; | |
694 } | |
695 | |
696 } else { | |
697 PERROR(NOCATGETS("workshop_connect")); | |
698 return; | |
699 } | |
700 } | |
701 | |
702 /* tell notifier we are interested in being called | |
703 * when there is input on the editor connection socket | |
704 */ | |
705 inputHandler = XtAppAddInput(context, sd, (XtPointer) XtInputReadMask, | |
706 messageFromEserve, NULL); | |
707 #ifdef DEBUG | |
708 if ((file = getenv(NOCATGETS("SPRO_PLUGIN_DEBUG"))) != NULL) { | |
709 char buf[BUFSIZ]; | |
710 | |
711 unlink(file); | |
712 sprintf(buf, "date > %s", file); | |
713 system(buf); | |
714 dfd = fopen(file, "a"); | |
715 } else { | |
716 dfd = NULL; | |
717 } | |
718 #endif | |
719 | |
720 sprintf(buf, NOCATGETS("connected %s %s %s\n"), | |
721 workshop_get_editor_name(), | |
722 PROTOCOL_VERSION, | |
723 workshop_get_editor_version()); | |
724 write(sd, buf, strlen(buf)); | |
725 | |
726 sprintf(buf, NOCATGETS("ack 1\n")); | |
727 write(sd, buf, strlen(buf)); | |
728 } | |
729 | |
730 void workshop_disconnect() | |
731 { | |
732 /* Probably need to send some message here */ | |
733 | |
734 /* | |
735 * socket closed on other end | |
736 */ | |
737 XtRemoveInput(inputHandler); | |
738 close(sd); | |
739 inputHandler = 0; | |
740 sd = -1; | |
741 | |
742 } | |
743 | |
744 /* | |
745 * Utility functions | |
746 */ | |
747 | |
748 /* Set icon for the window */ | |
749 void | |
750 workshop_set_icon(Display *display, Widget shell, char **xpmdata, | |
751 int width, int height) | |
752 { | |
753 Pixel bgPixel; | |
754 XpmAttributes xpmAttributes; | |
755 XSetWindowAttributes attr; | |
756 Window iconWindow; | |
757 int depth; | |
758 int screenNum; | |
759 Pixmap pixmap; | |
760 | |
761 /* Create the pixmap/icon window which is shown when you | |
762 * iconify the sccs viewer | |
763 * This code snipped was adapted from Sun WorkShop's source base, | |
764 * setIcon.cc. | |
765 */ | |
766 XtVaGetValues(shell, XmNbackground, &bgPixel, NULL); | |
767 screenNum = XScreenNumberOfScreen(XtScreen(shell)); | |
768 depth = DisplayPlanes(display, screenNum); | |
769 xpmAttributes.valuemask = XpmColorSymbols; | |
770 xpmAttributes.numsymbols = 1; | |
771 xpmAttributes.colorsymbols = | |
772 (XpmColorSymbol *)XtMalloc(sizeof (XpmColorSymbol) * | |
773 xpmAttributes.numsymbols); | |
774 xpmAttributes.colorsymbols[0].name = NOCATGETS("BgColor"); | |
775 xpmAttributes.colorsymbols[0].value = NULL; | |
776 xpmAttributes.colorsymbols[0].pixel = bgPixel; | |
777 if (XpmCreatePixmapFromData(display, | |
778 RootWindow(display, screenNum), xpmdata, &pixmap, | |
779 NULL, &xpmAttributes) >= 0) { | |
780 attr.background_pixmap = pixmap; | |
781 iconWindow = XCreateWindow(display, RootWindow(display, | |
782 screenNum), 0, 0, width, height, 0, depth, | |
783 (unsigned int)CopyFromParent, | |
784 CopyFromParent, CWBackPixmap, &attr); | |
785 | |
786 XtVaSetValues(shell, | |
787 XtNiconWindow, iconWindow, NULL); | |
788 } | |
789 XtFree((char *)xpmAttributes.colorsymbols); | |
790 } | |
791 | |
792 /* Minimize and maximize shells. From libutil's shell.cc. */ | |
793 | |
794 /* utility functions from libutil's shell.cc */ | |
795 static Boolean | |
796 isWindowMapped(Display *display, Window win) | |
797 { | |
798 XWindowAttributes winAttrs; | |
799 XGetWindowAttributes(display, | |
800 win, | |
801 &winAttrs); | |
802 if (winAttrs.map_state == IsViewable) { | |
803 return(True); | |
804 } else { | |
805 return(False); | |
806 } | |
807 } | |
808 | |
809 static Boolean | |
810 isMapped(Widget widget) | |
811 { | |
812 if (widget == NULL) { | |
813 return(False); | |
814 } | |
815 | |
816 if (XtIsRealized(widget) == False) { | |
817 return(False); | |
818 } | |
819 | |
820 return(isWindowMapped(XtDisplay(widget), XtWindow(widget))); | |
821 } | |
822 | |
823 static Boolean | |
824 widgetIsIconified( | |
825 Widget w) | |
826 { | |
827 Atom wm_state; | |
828 Atom act_type; /* actual Atom type returned */ | |
829 int act_fmt; /* actual format returned */ | |
830 u_long nitems_ret; /* number of items returned */ | |
831 u_long bytes_after; /* number of bytes remaining */ | |
832 u_long *property; /* actual property returned */ | |
833 | |
834 /* | |
835 * If a window is iconified its WM_STATE is set to IconicState. See | |
836 * ICCCM Version 2.0, section 4.1.3.1 for more details. | |
837 */ | |
838 | |
839 wm_state = XmInternAtom(XtDisplay(w), NOCATGETS("WM_STATE"), False); | |
840 if (XtWindow(w) != 0) { /* only check if window exists! */ | |
841 XGetWindowProperty(XtDisplay(w), XtWindow(w), wm_state, 0L, 2L, | |
842 False, AnyPropertyType, &act_type, &act_fmt, &nitems_ret, | |
843 &bytes_after, (u_char **) &property); | |
844 if (nitems_ret == 2 && property[0] == IconicState) { | |
845 return True; | |
846 } | |
847 } | |
848 | |
849 return False; | |
850 | |
851 } /* end widgetIsIconified */ | |
852 | |
853 void | |
854 workshop_minimize_shell(Widget shell) | |
855 { | |
856 if (shell != NULL && | |
857 XtIsObject(shell) && | |
858 XtIsRealized(shell) == True) { | |
859 if (isMapped(shell) == True) { | |
860 XIconifyWindow(XtDisplay(shell), XtWindow(shell), | |
861 XScreenNumberOfScreen(XtScreen(shell))); | |
862 } | |
863 XtVaSetValues(shell, | |
864 XmNiconic, True, | |
865 NULL); | |
866 } | |
867 } | |
868 | |
869 void workshop_maximize_shell(Widget shell) | |
870 { | |
871 if (shell != NULL && | |
872 XtIsRealized(shell) == True && | |
873 widgetIsIconified(shell) == True && | |
874 isMapped(shell) == False) { | |
875 XtMapWidget(shell); | |
876 /* This used to be | |
877 XtPopdown(shell); | |
878 XtPopup(shell, XtGrabNone); | |
879 However, I found that that would drop any transient | |
880 windows that had been iconified with the window. | |
881 According to the ICCCM, XtMapWidget should be used | |
882 to bring a window from Iconic to Normal state. | |
883 However, Rich Mauri did a lot of work on this during | |
884 Bart, and found that XtPopDown,XtPopup was required | |
885 to fix several bugs involving multiple CDE workspaces. | |
886 I've tested it now and things seem to work fine but | |
887 I'm leaving this note for history in case this needs | |
888 to be revisited. | |
889 */ | |
890 } | |
891 } | |
892 | |
893 | |
894 Boolean workshop_get_width_height(int *width, int *height) | |
895 { | |
896 static int wid = 0; | |
897 static int hgt = 0; | |
898 static Boolean firstTime = True; | |
899 static Boolean success = False; | |
900 | |
901 if (firstTime) { | |
902 char *settings; | |
903 | |
904 settings = getenv(NOCATGETS("SPRO_GUI_WIDTH_HEIGHT")); | |
905 if (settings != NULL) { | |
906 wid = atoi(settings); | |
907 settings = strrchr(settings, ':'); | |
908 if (settings++ != NULL) { | |
909 hgt = atoi(settings); | |
910 } | |
911 if (wid > 0 && hgt > 0) { | |
912 success = True; | |
913 } | |
914 firstTime = False; | |
915 } | |
916 } | |
917 | |
918 if (success) { | |
919 *width = wid; | |
920 *height = hgt; | |
921 } | |
922 return success; | |
923 } | |
924 | |
925 | |
926 Boolean workshop_get_rows_cols(int *rows, int *cols) | |
927 { | |
928 static int r = 0; | |
929 static int c = 0; | |
930 static Boolean firstTime = True; | |
931 static Boolean success = False; | |
932 | |
933 if (firstTime) { | |
934 char *settings; | |
935 | |
936 settings = getenv(NOCATGETS("SPRO_GUI_ROWS_COLS")); | |
937 if (settings != NULL) { | |
938 r = atoi(settings); | |
939 settings = strrchr(settings, ':'); | |
940 if (settings++ != NULL) { | |
941 c = atoi(settings); | |
942 } | |
943 if (r > 0 && c > 0) { | |
944 success = True; | |
945 } | |
946 firstTime = False; | |
947 } | |
948 } | |
949 | |
950 if (success) { | |
951 *rows = r; | |
952 *cols = c; | |
953 } | |
954 return success; | |
955 } | |
956 | |
957 /* | |
958 * Toolbar code | |
959 */ | |
960 | |
961 void workshop_sensitivity(int num, char *table) | |
962 { | |
963 /* build up a verb table */ | |
964 VerbSense *vs; | |
965 int i; | |
966 char *s; | |
967 if ((num < 1) || (num > 500)) { | |
968 return; | |
969 } | |
970 | |
971 vs = (VerbSense *)malloc((num+1)*sizeof(VerbSense)); | |
972 | |
973 /* Point to the individual names (destroys the table string, but | |
974 * that's okay -- this is more efficient than duplicating strings) */ | |
975 s = table; | |
976 for (i = 0; i < num; i++) { | |
977 while (*s == ' ') { | |
978 s++; | |
979 } | |
980 vs[i].verb = s; | |
981 while (*s && (*s != ' ') && (*s != '\001')) { | |
982 s++; | |
983 } | |
984 if (*s == 0) { | |
985 vs[i].verb = NULL; | |
986 break; | |
987 } | |
988 if (*s == '\001') { | |
989 *s = 0; | |
990 s++; | |
991 } | |
992 *s = 0; | |
993 s++; | |
994 while (*s == ' ') { | |
995 s++; | |
996 } | |
997 if (*s == '1') { | |
998 vs[i].sense = 1; | |
999 } else { | |
1000 vs[i].sense = 0; | |
1001 } | |
1002 s++; | |
1003 } | |
1004 vs[i].verb = NULL; | |
1005 | |
1006 workshop_frame_sensitivities(vs); | |
1007 | |
1008 free(vs); | |
1009 } | |
1010 | |
1011 /* | |
1012 * Options code | |
1013 */ | |
1014 /* Set an editor option. | |
1015 * IGNORE an option if you do not recognize it. | |
1016 */ | |
1017 void workshop_set_option_first(char *name, char *value) | |
1018 { | |
1019 /* Currently value can only be on/off. This may change later (for | |
1020 * example to set an option like "balloon evaluate delay", but | |
1021 * for now just convert it into a boolean */ | |
1022 Boolean on = !strcmp(value, "on"); | |
1023 | |
1024 if (!strcmp(name, "workshopkeys")) { | |
1025 workshop_hotkeys(on); | |
1026 } else if (!strcmp(name, "savefiles")) { | |
1027 save_files = on; | |
1028 } else if (!strcmp(name, "balloon")) { | |
1029 workshop_balloon_mode(on); | |
1030 } else if (!strcmp(name, "balloondelay")) { | |
1031 int delay = atoi(value); | |
1032 /* Should I validate the number here?? */ | |
1033 workshop_balloon_delay(delay); | |
1034 } else { | |
1035 /* Let editor interpret it */ | |
1036 workshop_set_option(name, value); | |
1037 } | |
1038 } | |
1039 | |
1040 | |
1041 | |
1042 /* | |
1043 * Send information to eserve on certain editor events | |
1044 * You must make sure these are called when necessary | |
1045 */ | |
1046 | |
1047 void workshop_file_closed(char *filename) | |
1048 { | |
1049 char buffer[2*MAXPATHLEN]; | |
1050 sprintf(buffer, NOCATGETS("deletedFile %s\n"), filename); | |
1051 write(sd, buffer, strlen(buffer)); | |
1052 } | |
1053 | |
1054 void workshop_file_closed_lineno(char *filename, int lineno) | |
1055 { | |
1056 char buffer[2*MAXPATHLEN]; | |
1057 sprintf(buffer, NOCATGETS("deletedFile %s %d\n"), filename, lineno); | |
1058 write(sd, buffer, strlen(buffer)); | |
1059 } | |
1060 | |
1061 void workshop_file_opened(char *filename, int readOnly) | |
1062 { | |
1063 char buffer[2*MAXPATHLEN]; | |
1064 sprintf(buffer, NOCATGETS("loadedFile %s %d\n"), filename, readOnly); | |
1065 write(sd, buffer, strlen(buffer)); | |
1066 } | |
1067 | |
1068 | |
1069 void workshop_file_saved(char *filename) | |
1070 { | |
1071 char buffer[2*MAXPATHLEN]; | |
1072 sprintf(buffer, NOCATGETS("savedFile %s\n"), filename); | |
1073 write(sd, buffer, strlen(buffer)); | |
1074 | |
1075 /* Let editor report any moved marks that the eserve client | |
1076 * should deal with (for example, moving location-based breakpoints) */ | |
1077 workshop_moved_marks(filename); | |
1078 } | |
1079 | |
1080 void workshop_move_mark(char *filename, int markId, int newLineno) | |
1081 { | |
1082 char buffer[2*MAXPATHLEN]; | |
1083 sprintf(buffer, NOCATGETS("moveMark %s %d %d\n"), filename, markId, newLineno); | |
1084 write(sd, buffer, strlen(buffer)); | |
1085 } | |
1086 | |
1087 void workshop_file_modified(char *filename) | |
1088 { | |
1089 char buffer[2*MAXPATHLEN]; | |
1090 sprintf(buffer, NOCATGETS("modifiedFile %s\n"), filename); | |
1091 write(sd, buffer, strlen(buffer)); | |
1092 } | |
1093 | |
1094 void workshop_frame_moved(int new_x, int new_y, int new_w, int new_h) | |
1095 { | |
1096 char buffer[200]; | |
1097 | |
1098 if (sd >= 0) | |
1099 { | |
1100 sprintf(buffer, NOCATGETS("frameAt %d %d %d %d\n"), | |
1101 new_x, new_y, new_w, new_h); | |
1102 write(sd, buffer, strlen(buffer)); | |
1103 } | |
1104 } | |
1105 | |
1106 /* A button in the toolbar has been pushed. | |
1107 * Clientdata is a pointer used by the editor code to figure out the | |
1108 * positions for this toolbar (probably by storing a window pointer, | |
1109 * and then fetching the current buffer for that window and looking up | |
1110 * cursor and selection positions etc.) */ | |
1111 void workshop_perform_verb(char *verb, void *clientData) | |
1112 { | |
1113 char *filename; | |
1114 int curLine; | |
1115 int curCol; | |
1116 int selStartLine; | |
1117 int selStartCol; | |
1118 int selEndLine; | |
1119 int selEndCol; | |
1120 int selLength; | |
1121 char *selection; | |
1122 | |
1123 char buf[2*MAXPATHLEN]; | |
1124 /* Later: needsFilePos indicates whether or not we need to fetch all this | |
1125 * info for this verb... for now, however, it looks as if | |
1126 * eserve parsing routines depend on it always being present */ | |
1127 | |
1128 if (workshop_get_positions(clientData, | |
1129 &filename, | |
1130 &curLine, | |
1131 &curCol, | |
1132 &selStartLine, | |
1133 &selStartCol, | |
1134 &selEndLine, | |
1135 &selEndCol, | |
1136 &selLength, | |
1137 &selection)) { | |
1138 if (selection == NULL) { | |
1139 selection = NOCATGETS(""); | |
1140 } | |
1141 | |
1142 /* Should I save the files??? This is currently done by checking | |
1143 if the verb is one of a few recognized ones. Later we can pass | |
1144 this list from eserve to the editor (it's currently hardcoded in | |
1145 vi and emacs as well). */ | |
1146 if (save_files) { | |
1147 if (!strcmp(verb, "build.build") || !strcmp(verb, "build.build-file") || | |
1148 !strcmp(verb, "debug.fix") || !strcmp(verb, "debug.fix-all")) { | |
1149 workshop_save_files(); | |
1150 } | |
1151 } | |
1152 | |
1153 sprintf(buf, NOCATGETS("toolVerb %s %s %d,%d %d,%d %d,%d %d %s\n"), | |
1154 verb, | |
1155 filename, | |
1156 curLine, curCol, | |
1157 selStartLine, selStartCol, | |
1158 selEndLine, selEndCol, | |
1159 selLength, | |
1160 selection); | |
1161 write(sd, buf, strlen(buf)); | |
1162 if (*selection) { | |
1163 free(selection); | |
1164 } | |
1165 } | |
1166 } | |
1167 | |
1168 /* Send a message to eserve */ | |
1169 void workshop_send_message(char *buf) | |
1170 { | |
1171 write(sd, buf, strlen(buf)); | |
1172 } | |
1173 | |
1174 /* Some methods, like currentFile, cursorPos, etc. are missing here. | |
1175 * But it looks like these are used for NoHands testing only so we | |
1176 * won't bother requiring editors to implement these | |
1177 */ | |
1178 | |
1179 | |
1180 #ifdef DEBUG | |
1181 | |
1182 void | |
1183 pldebug( | |
1184 char *fmt, /* a printf style format line */ | |
1185 ...) | |
1186 { | |
1187 va_list ap; | |
1188 | |
1189 if (dfd != NULL) { | |
1190 va_start(ap, fmt); | |
1191 vfprintf(dfd, fmt, ap); | |
1192 va_end(ap); | |
1193 fflush(dfd); | |
1194 } | |
1195 | |
1196 } /* end pldebug */ | |
1197 | |
1198 #endif |