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