diff options
Diffstat (limited to 'src/integration.c')
-rw-r--r-- | src/integration.c | 1198 |
1 files changed, 1198 insertions, 0 deletions
diff --git a/src/integration.c b/src/integration.c new file mode 100644 index 000000000..05a9dec3f --- /dev/null +++ b/src/integration.c @@ -0,0 +1,1198 @@ +/* vi:set ts=8 sw=8: + * + * VIM - Vi IMproved by Bram Moolenaar + * Visual Workshop integration by Gordon Prieur + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * Integration with Sun Workshop. + * + * This file should not change much, it's also used by other editors that + * connect to Workshop. Consider changing workshop.c instead. + */ +/* +-> consider using MakeSelectionVisible instead of gotoLine hacks + to show the line properly + -> consider using glue instead of our own message wrapping functions + (but can only use glue if we don't have to distribute source) +*/ + +#include "vim.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <fcntl.h> + +#ifdef INET_SOCKETS +#include <netdb.h> +#include <netinet/in.h> +#else +#include <sys/un.h> +#endif + +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/param.h> +#ifdef HAVE_LIBGEN_H +# include <libgen.h> +#endif +#include <unistd.h> +#include <string.h> + +#include <X11/Intrinsic.h> +#include <Xm/Xm.h> +#include <Xm/AtomMgr.h> +#include <Xm/PushB.h> + +#ifdef HAVE_X11_XPM_H +# include <X11/xpm.h> +#else +# ifdef HAVE_XM_XPMP_H +# include <Xm/XpmP.h> +# endif +#endif + +#ifdef HAVE_UTIL_DEBUG_H +# include <util/debug.h> +#endif +#ifdef HAVE_UTIL_MSGI18N_H +# include <util/msgi18n.h> +#endif + +#include "integration.h" /* <EditPlugin/integration.h> */ +#ifdef HAVE_FRAME_H +# include <frame.h> +#endif + +#ifndef MAX +# define MAX(a, b) (a) > (b) ? (a) : (b) +#endif + +#ifndef NOCATGETS +# define NOCATGETS(x) x +#endif + +/* Functions private to this file */ +static void workshop_connection_closed(void); +static void messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2); +static void workshop_disconnect(void); +static void workshop_sensitivity(int num, char *table); +static void adjust_sign_name(char *filename); +static void process_menuItem(char *); +static void process_toolbarButton(char *); +static void workshop_set_option_first(char *name, char *value); + + +#define CMDBUFSIZ 2048 + +#ifdef DEBUG +static FILE *dfd; +static void pldebug(char *, ...); +static void unrecognised_message(char *); + +#define HANDLE_ERRORS(cmd) else unrecognised_message(cmd); +#else +#define HANDLE_ERRORS(cmd) +#endif + +/* + * Version number of the protocol between an editor and eserve. + * This number should be incremented when the protocol + * is changed. + */ +#define PROTOCOL_VERSION "4.0.0" + +static int sd = -1; +static XtInputId inputHandler; /* Cookie for input */ + +Boolean save_files = True; /* When true, save all files before build actions */ + +void +workshop_connection_closed(void) +{ + /* + * socket closed on other end + */ + XtRemoveInput(inputHandler); + inputHandler = 0; + sd = -1; +} + + static char * +getCommand(void) +{ + int len; /* length of this command */ + char lenbuf[7]; /* get the length string here */ + char *newcb; /* used to realloc cmdbuf */ + static char *cmdbuf;/* get the command string here */ + static int cbsize;/* size of cmdbuf */ + + if ((len = read(sd, &lenbuf, 6)) == 6) { + lenbuf[6] = 0; /* Terminate buffer such that atoi() works right */ + len = atoi(lenbuf); + if (cbsize < (len + 1)) { + newcb = (char *) realloc(cmdbuf, + MAX((len + 256), CMDBUFSIZ)); + if (newcb != NULL) { + cmdbuf = newcb; + cbsize = MAX((len + 256), CMDBUFSIZ); + } + } + if (cbsize >= len && (len = read(sd, cmdbuf, len)) > 0) { + cmdbuf[len] = 0; + return cmdbuf; + } else { + return NULL; + } + } else { + if (len == 0) { /* EOF */ + workshop_connection_closed(); + } + return NULL; + } + +} + +/*ARGSUSED*/ +void +messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2) +{ + char *cmd; /* the 1st word of the command */ + + cmd = getCommand(); + if (cmd == NULL) { + /* We're being shut down by eserve and the "quit" message + * didn't arrive before the socket connection got closed */ + return; + } +#ifdef DEBUG + pldebug("%s\n", cmd); +#endif + switch (*cmd) { + case 'a': + if (cmd[1] == 'c' && + strncmp(cmd, NOCATGETS("ack "), 4) == 0) { + int ackNum; + char buf[20]; + + ackNum = atoi(&cmd[4]); + sprintf(buf, NOCATGETS("ack %d\n"), ackNum); + write(sd, buf, strlen(buf)); + } else if (strncmp(cmd, + NOCATGETS("addMarkType "), 12) == 0) { + int idx; + char *color; + char *sign; + + idx = atoi(strtok(&cmd[12], " ")); + color = strtok(NULL, NOCATGETS("\001")); + sign = strtok(NULL, NOCATGETS("\001")); + /* Skip space that separates names */ + if (color) { + color++; + } + if (sign) { + sign++; + } + /* Change sign name to accomodate a different size? */ + adjust_sign_name(sign); + workshop_add_mark_type(idx, color, sign); + } + HANDLE_ERRORS(cmd); + break; + + case 'b': + if (strncmp(cmd, + NOCATGETS("balloon "), 8) == 0) { + char *tip; + + tip = strtok(&cmd[8], NOCATGETS("\001")); + workshop_show_balloon_tip(tip); + } + HANDLE_ERRORS(cmd); + break; + + case 'c': + if (strncmp(cmd, + NOCATGETS("changeMarkType "), 15) == 0) { + char *file; + int markId; + int type; + + file = strtok(&cmd[15], " "); + markId = atoi(strtok(NULL, " ")); + type = atoi(strtok(NULL, " ")); + workshop_change_mark_type(file, markId, type); + } + HANDLE_ERRORS(cmd); + break; + + case 'd': + if (strncmp(cmd, NOCATGETS("deleteMark "), 11) == 0) { + char *file; + int markId; + + file = strtok(&cmd[11], " "); + markId = atoi(strtok(NULL, " ")); + workshop_delete_mark(file, markId); + } + HANDLE_ERRORS(cmd); + break; + + case 'f': + if (cmd[1] == 'o' && + strncmp(cmd, NOCATGETS("footerMsg "), 10) == 0) { + int severity; + char *message; + + severity = + atoi(strtok(&cmd[10], " ")); + message = strtok(NULL, NOCATGETS("\001")); + + workshop_footer_message(message, severity); + } else if (strncmp(cmd, + NOCATGETS("frontFile "), 10) == 0) { + char *file; + + file = strtok(&cmd[10], " "); + workshop_front_file(file); + } + HANDLE_ERRORS(cmd); + break; + + case 'g': + if (cmd[1] == 'e' && + strncmp(cmd, NOCATGETS("getMarkLine "), 12) == 0) { + char *file; + int markid; + int line; + char buf[100]; + + file = strtok(&cmd[12], " "); + markid = atoi(strtok(NULL, " ")); + line = workshop_get_mark_lineno(file, markid); + sprintf(buf, NOCATGETS("markLine %s %d %d\n"), + file, markid, line); + write(sd, buf, strlen(buf)); + } else if (cmd[1] == 'o' && cmd[4] == 'L' && + strncmp(cmd, NOCATGETS("gotoLine "), 9) == 0) { + char *file; + int lineno; + + file = strtok(&cmd[9], " "); + lineno = atoi(strtok(NULL, " ")); + workshop_goto_line(file, lineno); + } else if (strncmp(cmd, + NOCATGETS("gotoMark "), 9) == 0) { + char *file; + int markId; + char *message; + + file = strtok(&cmd[9], " "); + markId = atoi(strtok(NULL, " ")); + message = strtok(NULL, NOCATGETS("\001")); + workshop_goto_mark(file, markId, message); +#ifdef NOHANDS_SUPPORT_FUNCTIONS + } else if (strcmp(cmd, NOCATGETS("getCurrentFile")) == 0) { + char *f = workshop_test_getcurrentfile(); + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("currentFile %d %s"), + f ? strlen(f) : 0, f ? f : ""); + workshop_send_message(buffer); + } else if (strcmp(cmd, NOCATGETS("getCursorRow")) == 0) { + int row = workshop_test_getcursorrow(); + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("cursorRow %d"), row); + workshop_send_message(buffer); + } else if (strcmp(cmd, NOCATGETS("getCursorCol")) == 0) { + int col = workshop_test_getcursorcol(); + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("cursorCol %d"), col); + workshop_send_message(buffer); + } else if (strcmp(cmd, NOCATGETS("getCursorRowText")) == 0) { + char *t = workshop_test_getcursorrowtext(); + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("cursorRowText %d %s"), + t ? strlen(t) : 0, t ? t : ""); + workshop_send_message(buffer); + } else if (strcmp(cmd, NOCATGETS("getSelectedText")) == 0) { + char *t = workshop_test_getselectedtext(); + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("selectedText %d %s"), + t ? strlen(t) : 0, t ? t : ""); + workshop_send_message(buffer); +#endif + } + HANDLE_ERRORS(cmd); + break; + + case 'l': + if (strncmp(cmd, NOCATGETS("loadFile "), 9) == 0) { + char *file; + int line; + char *frameid; + + file = strtok(&cmd[9], " "); + line = atoi(strtok(NULL, " ")); + frameid = strtok(NULL, " "); + workshop_load_file(file, line, frameid); + } + HANDLE_ERRORS(cmd); + break; + + case 'm': /* Menu, minimize, maximize */ + if (cmd[1] == 'e' && cmd[4] == 'B' && + strncmp(cmd, NOCATGETS("menuBegin "), 10) == 0) { + workshop_menu_begin(&cmd[10]); + } else if (cmd[1] == 'e' && cmd[4] == 'I' && + strncmp(cmd, NOCATGETS("menuItem "), 9) == 0) { + process_menuItem(cmd); + } else if (cmd[1] == 'e' && cmd[4] == 'E' && + strcmp(cmd, NOCATGETS("menuEnd")) == 0) { + workshop_menu_end(); + } else if (cmd[1] == 'a' && + strcmp(cmd, NOCATGETS("maximize")) == 0) { + workshop_maximize(); + } else if (strcmp(cmd, NOCATGETS("minimize")) == 0) { + workshop_minimize(); + } + HANDLE_ERRORS(cmd); + break; + + case 'o': + if (cmd[1] == 'p' && + strcmp(cmd, NOCATGETS("option"))) { + char *name; + char *value; + + name = strtok(&cmd[7], " "); + value = strtok(NULL, " "); + workshop_set_option_first(name, value); + } + HANDLE_ERRORS(cmd); + break; + + case 'p': + if (strcmp(cmd, NOCATGETS("ping")) == 0) { +#if 0 + int pingNum; + + pingNum = atoi(&cmd[5]); + workshop_send_ack(ackNum); + WHAT DO I DO HERE? +#endif + } + HANDLE_ERRORS(cmd); + break; + + case 'q': + if (strncmp(cmd, NOCATGETS("quit"), 4) == 0) { + + /* Close the connection. It's important to do + * that now, since workshop_quit might be + * looking at open files. For example, if you + * have modified one of the files without + * saving, NEdit will ask you what you want to + * do, and spin loop by calling + * XtAppProcessEvent while waiting for your + * reply. In this case, if we still have an + * input handler and the socket has been + * closed on the other side when eserve + * expired, we will hang in IoWait. + */ + workshop_disconnect(); + + workshop_quit(); + } + HANDLE_ERRORS(cmd); + break; + + case 'r': + if (cmd[1] == 'e' && + strncmp(cmd, NOCATGETS("reloadFile "), 11) == 0) { + char *file; + int line; + + file = strtok(&cmd[11], " "); + line = atoi(strtok(NULL, " ")); + workshop_reload_file(file, line); + } + HANDLE_ERRORS(cmd); + break; + + case 's': + if (cmd[1] == 'e' && cmd[2] == 't' && + strncmp(cmd, NOCATGETS("setMark "), 8) == 0) { + char *file; + int line; + int markId; + int type; + + file = strtok(&cmd[8], " "); + line = atoi(strtok(NULL, " ")); + markId = atoi(strtok(NULL, " ")); + type = atoi(strtok(NULL, " ")); + workshop_set_mark(file, line, markId, type); + } else if (cmd[1] == 'h' && + strncmp(cmd, NOCATGETS("showFile "), 9) == 0) { + workshop_show_file(&cmd[9]); + } else if (cmd[1] == 'u' && + strncmp(cmd, NOCATGETS("subMenu "), 8) == 0) { + char *label; + + label = strtok(&cmd[8], NOCATGETS("\001")); + workshop_submenu_begin(label); + } else if (cmd[1] == 'u' && + strcmp(cmd, NOCATGETS("subMenuEnd")) == 0) { + workshop_submenu_end(); + } else if (cmd[1] == 'e' && cmd[2] == 'n' && + strncmp(cmd, NOCATGETS("sensitivity "), 12) == 0) { + int num; + char *bracket; + char *table; + + num = atoi(strtok(&cmd[12], " ")); + bracket = strtok(NULL, " "); + if (*bracket != '[') { + fprintf(stderr, NOCATGETS("Parsing " + "error for sensitivity\n")); + } else { + table = strtok(NULL, NOCATGETS("]")); + workshop_sensitivity(num, table); + } + } else if (cmd[1] == 'e' && cmd[2] == 'n' && cmd[3] == 'd' && + strncmp(cmd, NOCATGETS("sendVerb "), 9) == 0) { + /* Send the given verb back (used for the + * debug.lineno callback (such that other tools + * can obtain the position coordinates or the + * selection) */ + char *verb; + + verb = strtok(&cmd[9], " "); + workshop_perform_verb(verb, NULL); + } else if (cmd[1] == 'a' && + strncmp(cmd, NOCATGETS("saveFile "), 9) == 0) { + workshop_save_file(&cmd[9]); +#ifdef NOHANDS_SUPPORT_FUNCTIONS + } else if (strncmp(cmd, NOCATGETS("saveSensitivity "), 16) == 0) { + char *file; + + file = strtok(&cmd[16], " "); + workshop_save_sensitivity(file); +#endif + } + HANDLE_ERRORS(cmd); + break; + + case 't': /* Toolbar */ + if (cmd[8] == 'e' && + strncmp(cmd, NOCATGETS("toolbarBegin"), 12) == 0) { + workshop_toolbar_begin(); + } else if (cmd[8] == 'u' && + strncmp(cmd, NOCATGETS("toolbarButton"), 13) == 0) { + process_toolbarButton(cmd); + } else if (cmd[7] == 'E' && + strcmp(cmd, NOCATGETS("toolbarEnd")) == 0) { + workshop_toolbar_end(); + } + HANDLE_ERRORS(cmd); + break; + +#ifdef DEBUG + default: + unrecognised_message(cmd); + break; +#endif + } +} + +static void +process_menuItem( + char *cmd) +{ + char *label = strtok(&cmd[9], NOCATGETS("\001")); + char *verb = strtok(NULL, NOCATGETS("\001")); + char *acc = strtok(NULL, NOCATGETS("\001")); + char *accText = strtok(NULL, NOCATGETS("\001")); + char *name = strtok(NULL, NOCATGETS("\001")); + char *sense = strtok(NULL, NOCATGETS("\n")); + char *filepos = strtok(NULL, NOCATGETS("\n")); + if (*acc == '-') { + acc = NULL; + } + if (*accText == '-') { + accText = NULL; + } + workshop_menu_item(label, verb, acc, accText, name, filepos, sense); + +} + + +static void +process_toolbarButton( + char *cmd) /* button definition */ +{ + char *label = strtok(&cmd[14], NOCATGETS("\001")); + char *verb = strtok(NULL, NOCATGETS("\001")); + char *senseVerb = strtok(NULL, NOCATGETS("\001")); + char *filepos = strtok(NULL, NOCATGETS("\001")); + char *help = strtok(NULL, NOCATGETS("\001")); + char *sense = strtok(NULL, NOCATGETS("\001")); + char *file = strtok(NULL, NOCATGETS("\001")); + char *left = strtok(NULL, NOCATGETS("\n")); + + if (!strcmp(label, NOCATGETS("-"))) { + label = NULL; + } + if (!strcmp(help, NOCATGETS("-"))) { + help = NULL; + } + if (!strcmp(file, NOCATGETS("-"))) { + file = NULL; + } + if (!strcmp(senseVerb, NOCATGETS("-"))) { + senseVerb = NULL; + } + workshop_toolbar_button(label, verb, senseVerb, filepos, help, + sense, file, left); +} + + +#ifdef DEBUG +void +unrecognised_message( + char *cmd) +{ + pldebug("Unrecognised eserve message:\n\t%s\n", cmd); + /* abort(); */ +} +#endif + + +/* Change sign name to accomodate a different size: + * Create the filename based on the height. The filename format + * of multisize icons are: + * x.xpm : largest icon + * x1.xpm : smaller icon + * x2.xpm : smallest icon */ + void +adjust_sign_name(char *filename) +{ + char *s; + static int fontSize = -1; + + if (fontSize == -1) + fontSize = workshop_get_font_height(); + if (fontSize == 0) + return; + if (filename[0] == '-') + return; + + /* This is ugly: later we should instead pass the fontheight over + * to eserve on startup and let eserve just send the right filenames + * to us in the first place + + * I know that the filename will end with 1.xpm (see + * GuiEditor.cc`LispPrintSign if you wonder why) */ + s = filename+strlen(filename)-5; + if (fontSize <= 11) + strcpy(s, "2.xpm"); + else if (fontSize <= 15) + strcpy(s, "1.xpm"); + else + strcpy(s, ".xpm"); +} + +/* Were we invoked by WorkShop? This function can be used early during startup + if you want to do things differently if the editor is started standalone + or in WorkShop mode. For example, in standalone mode you may not want to + add a footer/message area or a sign gutter. */ +int +workshop_invoked() +{ + static int result = -1; + if (result == -1) { + result = (getenv(NOCATGETS("SPRO_EDITOR_SOCKET")) != NULL); + } + return result; +} + +/* Connect back to eserve */ +void workshop_connect(XtAppContext context) +{ +#ifdef INET_SOCKETS + struct sockaddr_in server; + struct hostent * host; + int port; +#else + struct sockaddr_un server; +#endif + char buf[32]; + char * address; +#ifdef DEBUG + char *file; +#endif + + address = getenv(NOCATGETS("SPRO_EDITOR_SOCKET")); + if (address == NULL) { + return; + } + +#ifdef INET_SOCKETS + port = atoi(address); + + if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + PERROR(NOCATGETS("workshop_connect")); + return; + } + + /* Get the server internet address and put into addr structure */ + /* fill in the socket address structure and connect to server */ + memset((char *)&server, '\0', sizeof(server)); + server.sin_family = AF_INET; + server.sin_port = port; + if ((host = gethostbyname(NOCATGETS("localhost"))) == NULL) { + PERROR(NOCATGETS("gethostbyname")); + sd = -1; + return; + } + memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); +#else + if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + PERROR(NOCATGETS("workshop_connect")); + return; + } + + server.sun_family = AF_UNIX; + strcpy(server.sun_path, address); +#endif + /* Connect to server */ + if (connect(sd, (struct sockaddr *)&server, sizeof(server))) { + if (errno == ECONNREFUSED) { + close(sd); +#ifdef INET_SOCKETS + if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + PERROR(NOCATGETS("workshop_connect")); + return; + } +#else + if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + PERROR(NOCATGETS("workshop_connect")); + return; + } +#endif + if (connect(sd, (struct sockaddr *)&server, + sizeof(server))) { + PERROR(NOCATGETS("workshop_connect")); + return; + } + + } else { + PERROR(NOCATGETS("workshop_connect")); + return; + } + } + + /* tell notifier we are interested in being called + * when there is input on the editor connection socket + */ + inputHandler = XtAppAddInput(context, sd, (XtPointer) XtInputReadMask, + messageFromEserve, NULL); +#ifdef DEBUG + if ((file = getenv(NOCATGETS("SPRO_PLUGIN_DEBUG"))) != NULL) { + char buf[BUFSIZ]; + + unlink(file); + sprintf(buf, "date > %s", file); + system(buf); + dfd = fopen(file, "a"); + } else { + dfd = NULL; + } +#endif + + sprintf(buf, NOCATGETS("connected %s %s %s\n"), + workshop_get_editor_name(), + PROTOCOL_VERSION, + workshop_get_editor_version()); + write(sd, buf, strlen(buf)); + + sprintf(buf, NOCATGETS("ack 1\n")); + write(sd, buf, strlen(buf)); +} + +void workshop_disconnect() +{ + /* Probably need to send some message here */ + + /* + * socket closed on other end + */ + XtRemoveInput(inputHandler); + close(sd); + inputHandler = 0; + sd = -1; + +} + +/* + * Utility functions + */ + +/* Set icon for the window */ +void +workshop_set_icon(Display *display, Widget shell, char **xpmdata, + int width, int height) +{ + Pixel bgPixel; + XpmAttributes xpmAttributes; + XSetWindowAttributes attr; + Window iconWindow; + int depth; + int screenNum; + Pixmap pixmap; + + /* Create the pixmap/icon window which is shown when you + * iconify the sccs viewer + * This code snipped was adapted from Sun WorkShop's source base, + * setIcon.cc. + */ + XtVaGetValues(shell, XmNbackground, &bgPixel, NULL); + screenNum = XScreenNumberOfScreen(XtScreen(shell)); + depth = DisplayPlanes(display, screenNum); + xpmAttributes.valuemask = XpmColorSymbols; + xpmAttributes.numsymbols = 1; + xpmAttributes.colorsymbols = + (XpmColorSymbol *)XtMalloc(sizeof (XpmColorSymbol) * + xpmAttributes.numsymbols); + xpmAttributes.colorsymbols[0].name = NOCATGETS("BgColor"); + xpmAttributes.colorsymbols[0].value = NULL; + xpmAttributes.colorsymbols[0].pixel = bgPixel; + if (XpmCreatePixmapFromData(display, + RootWindow(display, screenNum), xpmdata, &pixmap, + NULL, &xpmAttributes) >= 0) { + attr.background_pixmap = pixmap; + iconWindow = XCreateWindow(display, RootWindow(display, + screenNum), 0, 0, width, height, 0, depth, + (unsigned int)CopyFromParent, + CopyFromParent, CWBackPixmap, &attr); + + XtVaSetValues(shell, + XtNiconWindow, iconWindow, NULL); + } + XtFree((char *)xpmAttributes.colorsymbols); +} + +/* Minimize and maximize shells. From libutil's shell.cc. */ + +/* utility functions from libutil's shell.cc */ +static Boolean +isWindowMapped(Display *display, Window win) +{ + XWindowAttributes winAttrs; + XGetWindowAttributes(display, + win, + &winAttrs); + if (winAttrs.map_state == IsViewable) { + return(True); + } else { + return(False); + } +} + +static Boolean +isMapped(Widget widget) +{ + if (widget == NULL) { + return(False); + } + + if (XtIsRealized(widget) == False) { + return(False); + } + + return(isWindowMapped(XtDisplay(widget), XtWindow(widget))); +} + +static Boolean +widgetIsIconified( + Widget w) +{ + Atom wm_state; + Atom act_type; /* actual Atom type returned */ + int act_fmt; /* actual format returned */ + u_long nitems_ret; /* number of items returned */ + u_long bytes_after; /* number of bytes remaining */ + u_long *property; /* actual property returned */ + + /* + * If a window is iconified its WM_STATE is set to IconicState. See + * ICCCM Version 2.0, section 4.1.3.1 for more details. + */ + + wm_state = XmInternAtom(XtDisplay(w), NOCATGETS("WM_STATE"), False); + if (XtWindow(w) != 0) { /* only check if window exists! */ + XGetWindowProperty(XtDisplay(w), XtWindow(w), wm_state, 0L, 2L, + False, AnyPropertyType, &act_type, &act_fmt, &nitems_ret, + &bytes_after, (u_char **) &property); + if (nitems_ret == 2 && property[0] == IconicState) { + return True; + } + } + + return False; + +} /* end widgetIsIconified */ + +void +workshop_minimize_shell(Widget shell) +{ + if (shell != NULL && + XtIsObject(shell) && + XtIsRealized(shell) == True) { + if (isMapped(shell) == True) { + XIconifyWindow(XtDisplay(shell), XtWindow(shell), + XScreenNumberOfScreen(XtScreen(shell))); + } + XtVaSetValues(shell, + XmNiconic, True, + NULL); + } +} + +void workshop_maximize_shell(Widget shell) +{ + if (shell != NULL && + XtIsRealized(shell) == True && + widgetIsIconified(shell) == True && + isMapped(shell) == False) { + XtMapWidget(shell); + /* This used to be + XtPopdown(shell); + XtPopup(shell, XtGrabNone); + However, I found that that would drop any transient + windows that had been iconified with the window. + According to the ICCCM, XtMapWidget should be used + to bring a window from Iconic to Normal state. + However, Rich Mauri did a lot of work on this during + Bart, and found that XtPopDown,XtPopup was required + to fix several bugs involving multiple CDE workspaces. + I've tested it now and things seem to work fine but + I'm leaving this note for history in case this needs + to be revisited. + */ + } +} + + +Boolean workshop_get_width_height(int *width, int *height) +{ + static int wid = 0; + static int hgt = 0; + static Boolean firstTime = True; + static Boolean success = False; + + if (firstTime) { + char *settings; + + settings = getenv(NOCATGETS("SPRO_GUI_WIDTH_HEIGHT")); + if (settings != NULL) { + wid = atoi(settings); + settings = strrchr(settings, ':'); + if (settings++ != NULL) { + hgt = atoi(settings); + } + if (wid > 0 && hgt > 0) { + success = True; + } + firstTime = False; + } + } + + if (success) { + *width = wid; + *height = hgt; + } + return success; +} + + +Boolean workshop_get_rows_cols(int *rows, int *cols) +{ + static int r = 0; + static int c = 0; + static Boolean firstTime = True; + static Boolean success = False; + + if (firstTime) { + char *settings; + + settings = getenv(NOCATGETS("SPRO_GUI_ROWS_COLS")); + if (settings != NULL) { + r = atoi(settings); + settings = strrchr(settings, ':'); + if (settings++ != NULL) { + c = atoi(settings); + } + if (r > 0 && c > 0) { + success = True; + } + firstTime = False; + } + } + + if (success) { + *rows = r; + *cols = c; + } + return success; +} + +/* + * Toolbar code + */ + +void workshop_sensitivity(int num, char *table) +{ + /* build up a verb table */ + VerbSense *vs; + int i; + char *s; + if ((num < 1) || (num > 500)) { + return; + } + + vs = (VerbSense *)malloc((num+1)*sizeof(VerbSense)); + + /* Point to the individual names (destroys the table string, but + * that's okay -- this is more efficient than duplicating strings) */ + s = table; + for (i = 0; i < num; i++) { + while (*s == ' ') { + s++; + } + vs[i].verb = s; + while (*s && (*s != ' ') && (*s != '\001')) { + s++; + } + if (*s == 0) { + vs[i].verb = NULL; + break; + } + if (*s == '\001') { + *s = 0; + s++; + } + *s = 0; + s++; + while (*s == ' ') { + s++; + } + if (*s == '1') { + vs[i].sense = 1; + } else { + vs[i].sense = 0; + } + s++; + } + vs[i].verb = NULL; + + workshop_frame_sensitivities(vs); + + free(vs); +} + +/* + * Options code + */ +/* Set an editor option. + * IGNORE an option if you do not recognize it. + */ +void workshop_set_option_first(char *name, char *value) +{ + /* Currently value can only be on/off. This may change later (for + * example to set an option like "balloon evaluate delay", but + * for now just convert it into a boolean */ + Boolean on = !strcmp(value, "on"); + + if (!strcmp(name, "workshopkeys")) { + workshop_hotkeys(on); + } else if (!strcmp(name, "savefiles")) { + save_files = on; + } else if (!strcmp(name, "balloon")) { + workshop_balloon_mode(on); + } else if (!strcmp(name, "balloondelay")) { + int delay = atoi(value); + /* Should I validate the number here?? */ + workshop_balloon_delay(delay); + } else { + /* Let editor interpret it */ + workshop_set_option(name, value); + } +} + + + +/* + * Send information to eserve on certain editor events + * You must make sure these are called when necessary + */ + +void workshop_file_closed(char *filename) +{ + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("deletedFile %s\n"), filename); + write(sd, buffer, strlen(buffer)); +} + +void workshop_file_closed_lineno(char *filename, int lineno) +{ + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("deletedFile %s %d\n"), filename, lineno); + write(sd, buffer, strlen(buffer)); +} + +void workshop_file_opened(char *filename, int readOnly) +{ + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("loadedFile %s %d\n"), filename, readOnly); + write(sd, buffer, strlen(buffer)); +} + + +void workshop_file_saved(char *filename) +{ + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("savedFile %s\n"), filename); + write(sd, buffer, strlen(buffer)); + + /* Let editor report any moved marks that the eserve client + * should deal with (for example, moving location-based breakpoints) */ + workshop_moved_marks(filename); +} + +void workshop_move_mark(char *filename, int markId, int newLineno) +{ + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("moveMark %s %d %d\n"), filename, markId, newLineno); + write(sd, buffer, strlen(buffer)); +} + +void workshop_file_modified(char *filename) +{ + char buffer[2*MAXPATHLEN]; + sprintf(buffer, NOCATGETS("modifiedFile %s\n"), filename); + write(sd, buffer, strlen(buffer)); +} + +void workshop_frame_moved(int new_x, int new_y, int new_w, int new_h) +{ + char buffer[200]; + + if (sd >= 0) + { + sprintf(buffer, NOCATGETS("frameAt %d %d %d %d\n"), + new_x, new_y, new_w, new_h); + write(sd, buffer, strlen(buffer)); + } +} + +/* A button in the toolbar has been pushed. + * Clientdata is a pointer used by the editor code to figure out the + * positions for this toolbar (probably by storing a window pointer, + * and then fetching the current buffer for that window and looking up + * cursor and selection positions etc.) */ +void workshop_perform_verb(char *verb, void *clientData) +{ + char *filename; + int curLine; + int curCol; + int selStartLine; + int selStartCol; + int selEndLine; + int selEndCol; + int selLength; + char *selection; + + char buf[2*MAXPATHLEN]; +/* Later: needsFilePos indicates whether or not we need to fetch all this + * info for this verb... for now, however, it looks as if + * eserve parsing routines depend on it always being present */ + + if (workshop_get_positions(clientData, + &filename, + &curLine, + &curCol, + &selStartLine, + &selStartCol, + &selEndLine, + &selEndCol, + &selLength, + &selection)) { + if (selection == NULL) { + selection = NOCATGETS(""); + } + + /* Should I save the files??? This is currently done by checking + if the verb is one of a few recognized ones. Later we can pass + this list from eserve to the editor (it's currently hardcoded in + vi and emacs as well). */ + if (save_files) { + if (!strcmp(verb, "build.build") || !strcmp(verb, "build.build-file") || + !strcmp(verb, "debug.fix") || !strcmp(verb, "debug.fix-all")) { + workshop_save_files(); + } + } + + sprintf(buf, NOCATGETS("toolVerb %s %s %d,%d %d,%d %d,%d %d %s\n"), + verb, + filename, + curLine, curCol, + selStartLine, selStartCol, + selEndLine, selEndCol, + selLength, + selection); + write(sd, buf, strlen(buf)); + if (*selection) { + free(selection); + } + } +} + +/* Send a message to eserve */ +void workshop_send_message(char *buf) +{ + write(sd, buf, strlen(buf)); +} + +/* Some methods, like currentFile, cursorPos, etc. are missing here. + * But it looks like these are used for NoHands testing only so we + * won't bother requiring editors to implement these + */ + + +#ifdef DEBUG + +void +pldebug( + char *fmt, /* a printf style format line */ + ...) +{ + va_list ap; + + if (dfd != NULL) { + va_start(ap, fmt); + vfprintf(dfd, fmt, ap); + va_end(ap); + fflush(dfd); + } + +} /* end pldebug */ + +#endif |