Merge branch 'vim'
[MacVim.git] / src / integration.c
blob0d46c97bfdf7cfc600fd2e7a72d11afb16998f9c
1 /* vi:set ts=8 sw=8:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * Visual Workshop integration by Gordon Prieur
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 */
12 * Integration with Sun Workshop.
14 * This file should not change much, it's also used by other editors that
15 * connect to Workshop. Consider changing workshop.c instead.
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)
24 #include "vim.h"
26 #include <stdio.h>
27 #include <stdlib.h>
29 #ifdef INET_SOCKETS
30 #include <netdb.h>
31 #include <netinet/in.h>
32 #else
33 #include <sys/un.h>
34 #endif
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>
46 #include <X11/Intrinsic.h>
47 #include <Xm/Xm.h>
48 #include <Xm/AtomMgr.h>
49 #include <Xm/PushB.h>
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
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
66 #include "integration.h" /* <EditPlugin/integration.h> */
67 #ifdef HAVE_FRAME_H
68 # include <frame.h>
69 #endif
71 #ifndef MAX
72 # define MAX(a, b) (a) > (b) ? (a) : (b)
73 #endif
75 #ifndef NOCATGETS
76 # define NOCATGETS(x) x
77 #endif
79 /* Functions private to this file */
80 static void workshop_connection_closed(void);
81 static void messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2);
82 static void workshop_disconnect(void);
83 static void workshop_sensitivity(int num, char *table);
84 static void adjust_sign_name(char *filename);
85 static void process_menuItem(char *);
86 static void process_toolbarButton(char *);
87 static void workshop_set_option_first(char *name, char *value);
90 #define CMDBUFSIZ 2048
92 #ifdef DEBUG
93 static FILE *dfd;
94 static void pldebug(char *, ...);
95 static void unrecognised_message(char *);
97 #define HANDLE_ERRORS(cmd) else unrecognised_message(cmd);
98 #else
99 #define HANDLE_ERRORS(cmd)
100 #endif
103 * Version number of the protocol between an editor and eserve.
104 * This number should be incremented when the protocol
105 * is changed.
107 #define PROTOCOL_VERSION "4.0.0"
109 static int sd = -1;
110 static XtInputId inputHandler; /* Cookie for input */
112 Boolean save_files = True; /* When true, save all files before build actions */
114 void
115 workshop_connection_closed(void)
118 * socket closed on other end
120 XtRemoveInput(inputHandler);
121 inputHandler = 0;
122 sd = -1;
125 static char *
126 getCommand(void)
128 int len; /* length of this command */
129 char lenbuf[7]; /* get the length string here */
130 char *newcb; /* used to realloc cmdbuf */
131 static char *cmdbuf;/* get the command string here */
132 static int cbsize;/* size of cmdbuf */
134 if ((len = read(sd, &lenbuf, 6)) == 6) {
135 lenbuf[6] = 0; /* Terminate buffer such that atoi() works right */
136 len = atoi(lenbuf);
137 if (cbsize < (len + 1)) {
138 newcb = (char *) realloc(cmdbuf,
139 MAX((len + 256), CMDBUFSIZ));
140 if (newcb != NULL) {
141 cmdbuf = newcb;
142 cbsize = MAX((len + 256), CMDBUFSIZ);
145 if (cbsize >= len && (len = read(sd, cmdbuf, len)) > 0) {
146 cmdbuf[len] = 0;
147 return cmdbuf;
148 } else {
149 return NULL;
151 } else {
152 if (len == 0) { /* EOF */
153 workshop_connection_closed();
155 return NULL;
160 /*ARGSUSED*/
161 void
162 messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2)
164 char *cmd; /* the 1st word of the command */
166 cmd = getCommand();
167 if (cmd == NULL) {
168 /* We're being shut down by eserve and the "quit" message
169 * didn't arrive before the socket connection got closed */
170 return;
172 #ifdef DEBUG
173 pldebug("%s\n", cmd);
174 #endif
175 switch (*cmd) {
176 case 'a':
177 if (cmd[1] == 'c' &&
178 strncmp(cmd, NOCATGETS("ack "), 4) == 0) {
179 int ackNum;
180 char buf[20];
182 ackNum = atoi(&cmd[4]);
183 vim_snprintf(buf, sizeof(buf),
184 NOCATGETS("ack %d\n"), ackNum);
185 write(sd, buf, strlen(buf));
186 } else if (strncmp(cmd,
187 NOCATGETS("addMarkType "), 12) == 0) {
188 int idx;
189 char *color;
190 char *sign;
192 idx = atoi(strtok(&cmd[12], " "));
193 color = strtok(NULL, NOCATGETS("\001"));
194 sign = strtok(NULL, NOCATGETS("\001"));
195 /* Skip space that separates names */
196 if (color) {
197 color++;
199 if (sign) {
200 sign++;
202 /* Change sign name to accomodate a different size? */
203 adjust_sign_name(sign);
204 workshop_add_mark_type(idx, color, sign);
206 HANDLE_ERRORS(cmd);
207 break;
209 case 'b':
210 if (strncmp(cmd,
211 NOCATGETS("balloon "), 8) == 0) {
212 char *tip;
214 tip = strtok(&cmd[8], NOCATGETS("\001"));
215 workshop_show_balloon_tip(tip);
217 HANDLE_ERRORS(cmd);
218 break;
220 case 'c':
221 if (strncmp(cmd,
222 NOCATGETS("changeMarkType "), 15) == 0) {
223 char *file;
224 int markId;
225 int type;
227 file = strtok(&cmd[15], " ");
228 markId = atoi(strtok(NULL, " "));
229 type = atoi(strtok(NULL, " "));
230 workshop_change_mark_type(file, markId, type);
232 HANDLE_ERRORS(cmd);
233 break;
235 case 'd':
236 if (strncmp(cmd, NOCATGETS("deleteMark "), 11) == 0) {
237 char *file;
238 int markId;
240 file = strtok(&cmd[11], " ");
241 markId = atoi(strtok(NULL, " "));
242 workshop_delete_mark(file, markId);
244 HANDLE_ERRORS(cmd);
245 break;
247 case 'f':
248 if (cmd[1] == 'o' &&
249 strncmp(cmd, NOCATGETS("footerMsg "), 10) == 0) {
250 int severity;
251 char *message;
253 severity =
254 atoi(strtok(&cmd[10], " "));
255 message = strtok(NULL, NOCATGETS("\001"));
257 workshop_footer_message(message, severity);
258 } else if (strncmp(cmd,
259 NOCATGETS("frontFile "), 10) == 0) {
260 char *file;
262 file = strtok(&cmd[10], " ");
263 workshop_front_file(file);
265 HANDLE_ERRORS(cmd);
266 break;
268 case 'g':
269 if (cmd[1] == 'e' &&
270 strncmp(cmd, NOCATGETS("getMarkLine "), 12) == 0) {
271 char *file;
272 int markid;
273 int line;
274 char buf[100];
276 file = strtok(&cmd[12], " ");
277 markid = atoi(strtok(NULL, " "));
278 line = workshop_get_mark_lineno(file, markid);
279 vim_snprintf(buf, sizeof(buf),
280 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;
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;
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 vim_snprintf(buffer, sizeof(buffer),
306 NOCATGETS("currentFile %d %s"),
307 f ? strlen(f) : 0, f ? f : "");
308 workshop_send_message(buffer);
309 } else if (strcmp(cmd, NOCATGETS("getCursorRow")) == 0) {
310 int row = workshop_test_getcursorrow();
311 char buffer[2*MAXPATHLEN];
312 vim_snprintf(buffer, sizeof(buffer),
313 NOCATGETS("cursorRow %d"), row);
314 workshop_send_message(buffer);
315 } else if (strcmp(cmd, NOCATGETS("getCursorCol")) == 0) {
316 int col = workshop_test_getcursorcol();
317 char buffer[2*MAXPATHLEN];
318 vim_snprintf(buffer, sizeof(buffer),
319 NOCATGETS("cursorCol %d"), col);
320 workshop_send_message(buffer);
321 } else if (strcmp(cmd, NOCATGETS("getCursorRowText")) == 0) {
322 char *t = workshop_test_getcursorrowtext();
323 char buffer[2*MAXPATHLEN];
324 vim_snprintf(buffer, sizeof(buffer),
325 NOCATGETS("cursorRowText %d %s"),
326 t ? strlen(t) : 0, t ? t : "");
327 workshop_send_message(buffer);
328 } else if (strcmp(cmd, NOCATGETS("getSelectedText")) == 0) {
329 char *t = workshop_test_getselectedtext();
330 char buffer[2*MAXPATHLEN];
331 vim_snprintf(buffer, sizeof(buffer),
332 NOCATGETS("selectedText %d %s"),
333 t ? strlen(t) : 0, t ? t : "");
334 workshop_send_message(buffer);
335 #endif
337 HANDLE_ERRORS(cmd);
338 break;
340 case 'l':
341 if (strncmp(cmd, NOCATGETS("loadFile "), 9) == 0) {
342 char *file;
343 int line;
344 char *frameid;
346 file = strtok(&cmd[9], " ");
347 line = atoi(strtok(NULL, " "));
348 frameid = strtok(NULL, " ");
349 workshop_load_file(file, line, frameid);
351 HANDLE_ERRORS(cmd);
352 break;
354 case 'm': /* Menu, minimize, maximize */
355 if (cmd[1] == 'e' && cmd[4] == 'B' &&
356 strncmp(cmd, NOCATGETS("menuBegin "), 10) == 0) {
357 workshop_menu_begin(&cmd[10]);
358 } else if (cmd[1] == 'e' && cmd[4] == 'I' &&
359 strncmp(cmd, NOCATGETS("menuItem "), 9) == 0) {
360 process_menuItem(cmd);
361 } else if (cmd[1] == 'e' && cmd[4] == 'E' &&
362 strcmp(cmd, NOCATGETS("menuEnd")) == 0) {
363 workshop_menu_end();
364 } else if (cmd[1] == 'a' &&
365 strcmp(cmd, NOCATGETS("maximize")) == 0) {
366 workshop_maximize();
367 } else if (strcmp(cmd, NOCATGETS("minimize")) == 0) {
368 workshop_minimize();
370 HANDLE_ERRORS(cmd);
371 break;
373 case 'o':
374 if (cmd[1] == 'p' &&
375 strcmp(cmd, NOCATGETS("option"))) {
376 char *name;
377 char *value;
379 name = strtok(&cmd[7], " ");
380 value = strtok(NULL, " ");
381 workshop_set_option_first(name, value);
383 HANDLE_ERRORS(cmd);
384 break;
386 case 'p':
387 if (strcmp(cmd, NOCATGETS("ping")) == 0) {
388 #if 0
389 int pingNum;
391 pingNum = atoi(&cmd[5]);
392 workshop_send_ack(ackNum);
393 WHAT DO I DO HERE?
394 #endif
396 HANDLE_ERRORS(cmd);
397 break;
399 case 'q':
400 if (strncmp(cmd, NOCATGETS("quit"), 4) == 0) {
402 /* Close the connection. It's important to do
403 * that now, since workshop_quit might be
404 * looking at open files. For example, if you
405 * have modified one of the files without
406 * saving, NEdit will ask you what you want to
407 * do, and spin loop by calling
408 * XtAppProcessEvent while waiting for your
409 * reply. In this case, if we still have an
410 * input handler and the socket has been
411 * closed on the other side when eserve
412 * expired, we will hang in IoWait.
414 workshop_disconnect();
416 workshop_quit();
418 HANDLE_ERRORS(cmd);
419 break;
421 case 'r':
422 if (cmd[1] == 'e' &&
423 strncmp(cmd, NOCATGETS("reloadFile "), 11) == 0) {
424 char *file;
425 int line;
427 file = strtok(&cmd[11], " ");
428 line = atoi(strtok(NULL, " "));
429 workshop_reload_file(file, line);
431 HANDLE_ERRORS(cmd);
432 break;
434 case 's':
435 if (cmd[1] == 'e' && cmd[2] == 't' &&
436 strncmp(cmd, NOCATGETS("setMark "), 8) == 0) {
437 char *file;
438 int line;
439 int markId;
440 int type;
442 file = strtok(&cmd[8], " ");
443 line = atoi(strtok(NULL, " "));
444 markId = atoi(strtok(NULL, " "));
445 type = atoi(strtok(NULL, " "));
446 workshop_set_mark(file, line, markId, type);
447 } else if (cmd[1] == 'h' &&
448 strncmp(cmd, NOCATGETS("showFile "), 9) == 0) {
449 workshop_show_file(&cmd[9]);
450 } else if (cmd[1] == 'u' &&
451 strncmp(cmd, NOCATGETS("subMenu "), 8) == 0) {
452 char *label;
454 label = strtok(&cmd[8], NOCATGETS("\001"));
455 workshop_submenu_begin(label);
456 } else if (cmd[1] == 'u' &&
457 strcmp(cmd, NOCATGETS("subMenuEnd")) == 0) {
458 workshop_submenu_end();
459 } else if (cmd[1] == 'e' && cmd[2] == 'n' &&
460 strncmp(cmd, NOCATGETS("sensitivity "), 12) == 0) {
461 int num;
462 char *bracket;
463 char *table;
465 num = atoi(strtok(&cmd[12], " "));
466 bracket = strtok(NULL, " ");
467 if (*bracket != '[') {
468 fprintf(stderr, NOCATGETS("Parsing "
469 "error for sensitivity\n"));
470 } else {
471 table = strtok(NULL, NOCATGETS("]"));
472 workshop_sensitivity(num, table);
474 } else if (cmd[1] == 'e' && cmd[2] == 'n' && cmd[3] == 'd' &&
475 strncmp(cmd, NOCATGETS("sendVerb "), 9) == 0) {
476 /* Send the given verb back (used for the
477 * debug.lineno callback (such that other tools
478 * can obtain the position coordinates or the
479 * selection) */
480 char *verb;
482 verb = strtok(&cmd[9], " ");
483 workshop_perform_verb(verb, NULL);
484 } else if (cmd[1] == 'a' &&
485 strncmp(cmd, NOCATGETS("saveFile "), 9) == 0) {
486 workshop_save_file(&cmd[9]);
487 #ifdef NOHANDS_SUPPORT_FUNCTIONS
488 } else if (strncmp(cmd, NOCATGETS("saveSensitivity "), 16) == 0) {
489 char *file;
491 file = strtok(&cmd[16], " ");
492 workshop_save_sensitivity(file);
493 #endif
495 HANDLE_ERRORS(cmd);
496 break;
498 case 't': /* Toolbar */
499 if (cmd[8] == 'e' &&
500 strncmp(cmd, NOCATGETS("toolbarBegin"), 12) == 0) {
501 workshop_toolbar_begin();
502 } else if (cmd[8] == 'u' &&
503 strncmp(cmd, NOCATGETS("toolbarButton"), 13) == 0) {
504 process_toolbarButton(cmd);
505 } else if (cmd[7] == 'E' &&
506 strcmp(cmd, NOCATGETS("toolbarEnd")) == 0) {
507 workshop_toolbar_end();
509 HANDLE_ERRORS(cmd);
510 break;
512 #ifdef DEBUG
513 default:
514 unrecognised_message(cmd);
515 break;
516 #endif
520 static void
521 process_menuItem(
522 char *cmd)
524 char *label = strtok(&cmd[9], NOCATGETS("\001"));
525 char *verb = strtok(NULL, NOCATGETS("\001"));
526 char *acc = strtok(NULL, NOCATGETS("\001"));
527 char *accText = strtok(NULL, NOCATGETS("\001"));
528 char *name = strtok(NULL, NOCATGETS("\001"));
529 char *sense = strtok(NULL, NOCATGETS("\n"));
530 char *filepos = strtok(NULL, NOCATGETS("\n"));
531 if (*acc == '-') {
532 acc = NULL;
534 if (*accText == '-') {
535 accText = NULL;
537 workshop_menu_item(label, verb, acc, accText, name, filepos, sense);
542 static void
543 process_toolbarButton(
544 char *cmd) /* button definition */
546 char *label = strtok(&cmd[14], NOCATGETS("\001"));
547 char *verb = strtok(NULL, NOCATGETS("\001"));
548 char *senseVerb = strtok(NULL, NOCATGETS("\001"));
549 char *filepos = strtok(NULL, NOCATGETS("\001"));
550 char *help = strtok(NULL, NOCATGETS("\001"));
551 char *sense = strtok(NULL, NOCATGETS("\001"));
552 char *file = strtok(NULL, NOCATGETS("\001"));
553 char *left = strtok(NULL, NOCATGETS("\n"));
555 if (!strcmp(label, NOCATGETS("-"))) {
556 label = NULL;
558 if (!strcmp(help, NOCATGETS("-"))) {
559 help = NULL;
561 if (!strcmp(file, NOCATGETS("-"))) {
562 file = NULL;
564 if (!strcmp(senseVerb, NOCATGETS("-"))) {
565 senseVerb = NULL;
567 workshop_toolbar_button(label, verb, senseVerb, filepos, help,
568 sense, file, left);
572 #ifdef DEBUG
573 void
574 unrecognised_message(
575 char *cmd)
577 pldebug("Unrecognised eserve message:\n\t%s\n", cmd);
578 /* abort(); */
580 #endif
583 /* Change sign name to accomodate a different size:
584 * Create the filename based on the height. The filename format
585 * of multisize icons are:
586 * x.xpm : largest icon
587 * x1.xpm : smaller icon
588 * x2.xpm : smallest icon */
589 void
590 adjust_sign_name(char *filename)
592 char *s;
593 static int fontSize = -1;
595 if (fontSize == -1)
596 fontSize = workshop_get_font_height();
597 if (fontSize == 0)
598 return;
599 if (filename[0] == '-')
600 return;
602 /* This is ugly: later we should instead pass the fontheight over
603 * to eserve on startup and let eserve just send the right filenames
604 * to us in the first place
606 * I know that the filename will end with 1.xpm (see
607 * GuiEditor.cc`LispPrintSign if you wonder why) */
608 s = filename+strlen(filename)-5;
609 if (fontSize <= 11)
610 strcpy(s, "2.xpm");
611 else if (fontSize <= 15)
612 strcpy(s, "1.xpm");
613 else
614 strcpy(s, ".xpm");
617 /* Were we invoked by WorkShop? This function can be used early during startup
618 if you want to do things differently if the editor is started standalone
619 or in WorkShop mode. For example, in standalone mode you may not want to
620 add a footer/message area or a sign gutter. */
622 workshop_invoked()
624 static int result = -1;
625 if (result == -1) {
626 result = (getenv(NOCATGETS("SPRO_EDITOR_SOCKET")) != NULL);
628 return result;
631 /* Connect back to eserve */
632 void workshop_connect(XtAppContext context)
634 #ifdef INET_SOCKETS
635 struct sockaddr_in server;
636 struct hostent * host;
637 int port;
638 #else
639 struct sockaddr_un server;
640 #endif
641 char buf[32];
642 char * address;
643 #ifdef DEBUG
644 char *file;
645 #endif
647 address = getenv(NOCATGETS("SPRO_EDITOR_SOCKET"));
648 if (address == NULL) {
649 return;
652 #ifdef INET_SOCKETS
653 port = atoi(address);
655 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
656 PERROR(NOCATGETS("workshop_connect"));
657 return;
660 /* Get the server internet address and put into addr structure */
661 /* fill in the socket address structure and connect to server */
662 memset((char *)&server, '\0', sizeof(server));
663 server.sin_family = AF_INET;
664 server.sin_port = port;
665 if ((host = gethostbyname(NOCATGETS("localhost"))) == NULL) {
666 PERROR(NOCATGETS("gethostbyname"));
667 sd = -1;
668 return;
670 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
671 #else
672 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
673 PERROR(NOCATGETS("workshop_connect"));
674 return;
677 server.sun_family = AF_UNIX;
678 strcpy(server.sun_path, address);
679 #endif
680 /* Connect to server */
681 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) {
682 if (errno == ECONNREFUSED) {
683 close(sd);
684 #ifdef INET_SOCKETS
685 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
686 PERROR(NOCATGETS("workshop_connect"));
687 return;
689 #else
690 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
691 PERROR(NOCATGETS("workshop_connect"));
692 return;
694 #endif
695 if (connect(sd, (struct sockaddr *)&server,
696 sizeof(server))) {
697 PERROR(NOCATGETS("workshop_connect"));
698 return;
701 } else {
702 PERROR(NOCATGETS("workshop_connect"));
703 return;
707 /* tell notifier we are interested in being called
708 * when there is input on the editor connection socket
710 inputHandler = XtAppAddInput(context, sd, (XtPointer) XtInputReadMask,
711 messageFromEserve, NULL);
712 #ifdef DEBUG
713 if ((file = getenv(NOCATGETS("SPRO_PLUGIN_DEBUG"))) != NULL) {
714 char buf[BUFSIZ];
716 unlink(file);
717 vim_snprintf(buf, sizeof(buf), "date > %s", file);
718 system(buf);
719 dfd = fopen(file, "a");
720 } else {
721 dfd = NULL;
723 #endif
725 vim_snprintf(buf, sizeof(buf), NOCATGETS("connected %s %s %s\n"),
726 workshop_get_editor_name(),
727 PROTOCOL_VERSION,
728 workshop_get_editor_version());
729 write(sd, buf, strlen(buf));
731 vim_snprintf(buf, sizeof(buf), NOCATGETS("ack 1\n"));
732 write(sd, buf, strlen(buf));
735 void workshop_disconnect()
737 /* Probably need to send some message here */
740 * socket closed on other end
742 XtRemoveInput(inputHandler);
743 close(sd);
744 inputHandler = 0;
745 sd = -1;
750 * Utility functions
753 /* Set icon for the window */
754 void
755 workshop_set_icon(Display *display, Widget shell, char **xpmdata,
756 int width, int height)
758 Pixel bgPixel;
759 XpmAttributes xpmAttributes;
760 XSetWindowAttributes attr;
761 Window iconWindow;
762 int depth;
763 int screenNum;
764 Pixmap pixmap;
766 /* Create the pixmap/icon window which is shown when you
767 * iconify the sccs viewer
768 * This code snipped was adapted from Sun WorkShop's source base,
769 * setIcon.cc.
771 XtVaGetValues(shell, XmNbackground, &bgPixel, NULL);
772 screenNum = XScreenNumberOfScreen(XtScreen(shell));
773 depth = DisplayPlanes(display, screenNum);
774 xpmAttributes.valuemask = XpmColorSymbols;
775 xpmAttributes.numsymbols = 1;
776 xpmAttributes.colorsymbols =
777 (XpmColorSymbol *)XtMalloc(sizeof (XpmColorSymbol) *
778 xpmAttributes.numsymbols);
779 xpmAttributes.colorsymbols[0].name = NOCATGETS("BgColor");
780 xpmAttributes.colorsymbols[0].value = NULL;
781 xpmAttributes.colorsymbols[0].pixel = bgPixel;
782 if (XpmCreatePixmapFromData(display,
783 RootWindow(display, screenNum), xpmdata, &pixmap,
784 NULL, &xpmAttributes) >= 0) {
785 attr.background_pixmap = pixmap;
786 iconWindow = XCreateWindow(display, RootWindow(display,
787 screenNum), 0, 0, width, height, 0, depth,
788 (unsigned int)CopyFromParent,
789 CopyFromParent, CWBackPixmap, &attr);
791 XtVaSetValues(shell,
792 XtNiconWindow, iconWindow, NULL);
794 XtFree((char *)xpmAttributes.colorsymbols);
797 /* Minimize and maximize shells. From libutil's shell.cc. */
799 /* utility functions from libutil's shell.cc */
800 static Boolean
801 isWindowMapped(Display *display, Window win)
803 XWindowAttributes winAttrs;
804 XGetWindowAttributes(display,
805 win,
806 &winAttrs);
807 if (winAttrs.map_state == IsViewable) {
808 return(True);
809 } else {
810 return(False);
814 static Boolean
815 isMapped(Widget widget)
817 if (widget == NULL) {
818 return(False);
821 if (XtIsRealized(widget) == False) {
822 return(False);
825 return(isWindowMapped(XtDisplay(widget), XtWindow(widget)));
828 static Boolean
829 widgetIsIconified(
830 Widget w)
832 Atom wm_state;
833 Atom act_type; /* actual Atom type returned */
834 int act_fmt; /* actual format returned */
835 u_long nitems_ret; /* number of items returned */
836 u_long bytes_after; /* number of bytes remaining */
837 u_long *property; /* actual property returned */
840 * If a window is iconified its WM_STATE is set to IconicState. See
841 * ICCCM Version 2.0, section 4.1.3.1 for more details.
844 wm_state = XmInternAtom(XtDisplay(w), NOCATGETS("WM_STATE"), False);
845 if (XtWindow(w) != 0) { /* only check if window exists! */
846 XGetWindowProperty(XtDisplay(w), XtWindow(w), wm_state, 0L, 2L,
847 False, AnyPropertyType, &act_type, &act_fmt, &nitems_ret,
848 &bytes_after, (u_char **) &property);
849 if (nitems_ret == 2 && property[0] == IconicState) {
850 return True;
854 return False;
856 } /* end widgetIsIconified */
858 void
859 workshop_minimize_shell(Widget shell)
861 if (shell != NULL &&
862 XtIsObject(shell) &&
863 XtIsRealized(shell) == True) {
864 if (isMapped(shell) == True) {
865 XIconifyWindow(XtDisplay(shell), XtWindow(shell),
866 XScreenNumberOfScreen(XtScreen(shell)));
868 XtVaSetValues(shell,
869 XmNiconic, True,
870 NULL);
874 void workshop_maximize_shell(Widget shell)
876 if (shell != NULL &&
877 XtIsRealized(shell) == True &&
878 widgetIsIconified(shell) == True &&
879 isMapped(shell) == False) {
880 XtMapWidget(shell);
881 /* This used to be
882 XtPopdown(shell);
883 XtPopup(shell, XtGrabNone);
884 However, I found that that would drop any transient
885 windows that had been iconified with the window.
886 According to the ICCCM, XtMapWidget should be used
887 to bring a window from Iconic to Normal state.
888 However, Rich Mauri did a lot of work on this during
889 Bart, and found that XtPopDown,XtPopup was required
890 to fix several bugs involving multiple CDE workspaces.
891 I've tested it now and things seem to work fine but
892 I'm leaving this note for history in case this needs
893 to be revisited.
899 Boolean workshop_get_width_height(int *width, int *height)
901 static int wid = 0;
902 static int hgt = 0;
903 static Boolean firstTime = True;
904 static Boolean success = False;
906 if (firstTime) {
907 char *settings;
909 settings = getenv(NOCATGETS("SPRO_GUI_WIDTH_HEIGHT"));
910 if (settings != NULL) {
911 wid = atoi(settings);
912 settings = strrchr(settings, ':');
913 if (settings++ != NULL) {
914 hgt = atoi(settings);
916 if (wid > 0 && hgt > 0) {
917 success = True;
919 firstTime = False;
923 if (success) {
924 *width = wid;
925 *height = hgt;
927 return success;
931 Boolean workshop_get_rows_cols(int *rows, int *cols)
933 static int r = 0;
934 static int c = 0;
935 static Boolean firstTime = True;
936 static Boolean success = False;
938 if (firstTime) {
939 char *settings;
941 settings = getenv(NOCATGETS("SPRO_GUI_ROWS_COLS"));
942 if (settings != NULL) {
943 r = atoi(settings);
944 settings = strrchr(settings, ':');
945 if (settings++ != NULL) {
946 c = atoi(settings);
948 if (r > 0 && c > 0) {
949 success = True;
951 firstTime = False;
955 if (success) {
956 *rows = r;
957 *cols = c;
959 return success;
963 * Toolbar code
966 void workshop_sensitivity(int num, char *table)
968 /* build up a verb table */
969 VerbSense *vs;
970 int i;
971 char *s;
972 if ((num < 1) || (num > 500)) {
973 return;
976 vs = (VerbSense *)malloc((num+1)*sizeof(VerbSense));
978 /* Point to the individual names (destroys the table string, but
979 * that's okay -- this is more efficient than duplicating strings) */
980 s = table;
981 for (i = 0; i < num; i++) {
982 while (*s == ' ') {
983 s++;
985 vs[i].verb = s;
986 while (*s && (*s != ' ') && (*s != '\001')) {
987 s++;
989 if (*s == 0) {
990 vs[i].verb = NULL;
991 break;
993 if (*s == '\001') {
994 *s = 0;
995 s++;
997 *s = 0;
998 s++;
999 while (*s == ' ') {
1000 s++;
1002 if (*s == '1') {
1003 vs[i].sense = 1;
1004 } else {
1005 vs[i].sense = 0;
1007 s++;
1009 vs[i].verb = NULL;
1011 workshop_frame_sensitivities(vs);
1013 free(vs);
1017 * Options code
1019 /* Set an editor option.
1020 * IGNORE an option if you do not recognize it.
1022 void workshop_set_option_first(char *name, char *value)
1024 /* Currently value can only be on/off. This may change later (for
1025 * example to set an option like "balloon evaluate delay", but
1026 * for now just convert it into a boolean */
1027 Boolean on = !strcmp(value, "on");
1029 if (!strcmp(name, "workshopkeys")) {
1030 workshop_hotkeys(on);
1031 } else if (!strcmp(name, "savefiles")) {
1032 save_files = on;
1033 } else if (!strcmp(name, "balloon")) {
1034 workshop_balloon_mode(on);
1035 } else if (!strcmp(name, "balloondelay")) {
1036 int delay = atoi(value);
1037 /* Should I validate the number here?? */
1038 workshop_balloon_delay(delay);
1039 } else {
1040 /* Let editor interpret it */
1041 workshop_set_option(name, value);
1048 * Send information to eserve on certain editor events
1049 * You must make sure these are called when necessary
1052 void workshop_file_closed(char *filename)
1054 char buffer[2*MAXPATHLEN];
1055 vim_snprintf(buffer, sizeof(buffer),
1056 NOCATGETS("deletedFile %s\n"), filename);
1057 write(sd, buffer, strlen(buffer));
1060 void workshop_file_closed_lineno(char *filename, int lineno)
1062 char buffer[2*MAXPATHLEN];
1063 vim_snprintf(buffer, sizeof(buffer),
1064 NOCATGETS("deletedFile %s %d\n"), filename, lineno);
1065 write(sd, buffer, strlen(buffer));
1068 void workshop_file_opened(char *filename, int readOnly)
1070 char buffer[2*MAXPATHLEN];
1071 vim_snprintf(buffer, sizeof(buffer),
1072 NOCATGETS("loadedFile %s %d\n"), filename, readOnly);
1073 write(sd, buffer, strlen(buffer));
1077 void workshop_file_saved(char *filename)
1079 char buffer[2*MAXPATHLEN];
1080 vim_snprintf(buffer, sizeof(buffer),
1081 NOCATGETS("savedFile %s\n"), filename);
1082 write(sd, buffer, strlen(buffer));
1084 /* Let editor report any moved marks that the eserve client
1085 * should deal with (for example, moving location-based breakpoints) */
1086 workshop_moved_marks(filename);
1089 void workshop_move_mark(char *filename, int markId, int newLineno)
1091 char buffer[2*MAXPATHLEN];
1092 vim_snprintf(buffer, sizeof(buffer),
1093 NOCATGETS("moveMark %s %d %d\n"), filename, markId, newLineno);
1094 write(sd, buffer, strlen(buffer));
1097 void workshop_file_modified(char *filename)
1099 char buffer[2*MAXPATHLEN];
1100 vim_snprintf(buffer, sizeof(buffer),
1101 NOCATGETS("modifiedFile %s\n"), filename);
1102 write(sd, buffer, strlen(buffer));
1105 void workshop_frame_moved(int new_x, int new_y, int new_w, int new_h)
1107 char buffer[200];
1109 if (sd >= 0)
1111 vim_snprintf(buffer, sizeof(buffer),
1112 NOCATGETS("frameAt %d %d %d %d\n"),
1113 new_x, new_y, new_w, new_h);
1114 write(sd, buffer, strlen(buffer));
1118 /* A button in the toolbar has been pushed.
1119 * Clientdata is a pointer used by the editor code to figure out the
1120 * positions for this toolbar (probably by storing a window pointer,
1121 * and then fetching the current buffer for that window and looking up
1122 * cursor and selection positions etc.) */
1123 void workshop_perform_verb(char *verb, void *clientData)
1125 char *filename;
1126 int curLine;
1127 int curCol;
1128 int selStartLine;
1129 int selStartCol;
1130 int selEndLine;
1131 int selEndCol;
1132 int selLength;
1133 char *selection;
1135 char buf[2*MAXPATHLEN];
1136 /* Later: needsFilePos indicates whether or not we need to fetch all this
1137 * info for this verb... for now, however, it looks as if
1138 * eserve parsing routines depend on it always being present */
1140 if (workshop_get_positions(clientData,
1141 &filename,
1142 &curLine,
1143 &curCol,
1144 &selStartLine,
1145 &selStartCol,
1146 &selEndLine,
1147 &selEndCol,
1148 &selLength,
1149 &selection)) {
1150 if (selection == NULL) {
1151 selection = NOCATGETS("");
1154 /* Should I save the files??? This is currently done by checking
1155 if the verb is one of a few recognized ones. Later we can pass
1156 this list from eserve to the editor (it's currently hardcoded in
1157 vi and emacs as well). */
1158 if (save_files) {
1159 if (!strcmp(verb, "build.build") || !strcmp(verb, "build.build-file") ||
1160 !strcmp(verb, "debug.fix") || !strcmp(verb, "debug.fix-all")) {
1161 workshop_save_files();
1165 vim_snprintf(buf, sizeof(buf),
1166 NOCATGETS("toolVerb %s %s %d,%d %d,%d %d,%d %d %s\n"),
1167 verb,
1168 filename,
1169 curLine, curCol,
1170 selStartLine, selStartCol,
1171 selEndLine, selEndCol,
1172 selLength,
1173 selection);
1174 write(sd, buf, strlen(buf));
1175 if (*selection) {
1176 free(selection);
1181 /* Send a message to eserve */
1182 void workshop_send_message(char *buf)
1184 write(sd, buf, strlen(buf));
1187 /* Some methods, like currentFile, cursorPos, etc. are missing here.
1188 * But it looks like these are used for NoHands testing only so we
1189 * won't bother requiring editors to implement these
1193 #ifdef DEBUG
1195 void
1196 pldebug(
1197 char *fmt, /* a printf style format line */
1198 ...)
1200 va_list ap;
1202 if (dfd != NULL) {
1203 va_start(ap, fmt);
1204 vfprintf(dfd, fmt, ap);
1205 va_end(ap);
1206 fflush(dfd);
1209 } /* end pldebug */
1211 #endif