1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * X command server by Flemming Madsen
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.
10 * if_xcmdsrv.c: Functions for passing commands through an X11 display.
17 #if defined(FEAT_CLIENTSERVER) || defined(PROTO)
20 # include <X11/Intrinsic.h>
21 # include <X11/Xatom.h>
25 * This file provides procedures that implement the command server
26 * functionality of Vim when in contact with an X11 server.
28 * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution.
29 * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4
33 * Copyright (c) 1989-1993 The Regents of the University of California.
34 * All rights reserved.
36 * Permission is hereby granted, without written agreement and without
37 * license or royalty fees, to use, copy, modify, and distribute this
38 * software and its documentation for any purpose, provided that the
39 * above copyright notice and the following two paragraphs appear in
40 * all copies of this software.
42 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
43 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
44 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
45 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
48 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
49 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
50 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
51 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
56 * When a result is being awaited from a sent command, one of
57 * the following structures is present on a list of all outstanding
58 * sent commands. The information in the structure is used to
59 * process the result when it arrives. You're probably wondering
60 * how there could ever be multiple outstanding sent commands.
61 * This could happen if Vim instances invoke each other recursively.
62 * It's unlikely, but possible.
65 typedef struct PendingCommand
67 int serial
; /* Serial number expected in result. */
68 int code
; /* Result Code. 0 is OK */
69 char_u
*result
; /* String result for command (malloc'ed).
70 * NULL means command still pending. */
71 struct PendingCommand
*nextPtr
;
72 /* Next in list of all outstanding commands.
73 * NULL means end of list. */
76 static PendingCommand
*pendingCommands
= NULL
;
77 /* List of all commands currently
78 * being waited for. */
81 * The information below is used for communication between processes
82 * during "send" commands. Each process keeps a private window, never
83 * even mapped, with one property, "Comm". When a command is sent to
84 * an interpreter, the command is appended to the comm property of the
85 * communication window associated with the interp's process. Similarly,
86 * when a result is returned from a sent command, it is also appended
87 * to the comm property.
89 * Each command and each result takes the form of ASCII text. For a
90 * command, the text consists of a nul character followed by several
91 * nul-terminated ASCII strings. The first string consists of a
93 * "c" for an expression
96 * "n" for notification.
97 * Subsequent strings have the form "option value" where the following options
100 * -r commWindow serial
102 * This option means that a response should be sent to the window
103 * whose X identifier is "commWindow" (in hex), and the response should
104 * be identified with the serial number given by "serial" (in decimal).
105 * If this option isn't specified then the send is asynchronous and
106 * no response is sent.
109 * "Name" gives the name of the application for which the command is
110 * intended. This option must be present.
113 * Encoding name used for the text. This is the 'encoding' of the
114 * sender. The receiver may want to do conversion to his 'encoding'.
117 * "Script" is the script to be executed. This option must be
118 * present. Taken as a series of keystrokes in a "k" command where
119 * <Key>'s are expanded
121 * The options may appear in any order. The -n and -s options must be
122 * present, but -r may be omitted for asynchronous RPCs. For compatibility
123 * with future releases that may add new features, there may be additional
124 * options present; as long as they start with a "-" character, they will
127 * A result also consists of a zero character followed by several null-
128 * terminated ASCII strings. The first string consists of the single
129 * letter "r". Subsequent strings have the form "option value" where
130 * the following options are supported:
133 * Identifies the command for which this is the result. It is the
134 * same as the "serial" field from the -s option in the command. This
135 * option must be present.
138 * "Result" is the result string for the script, which may be either
139 * a result or an error message. If this field is omitted then it
140 * defaults to an empty string.
143 * 0: for OK. This is the default.
144 * 1: for error: Result is the last error
148 * Not applicable for Vim
150 * Options may appear in any order, and only the -s option must be
151 * present. As with commands, there may be additional options besides
152 * these; unknown options are ignored.
156 * Maximum size property that can be read at one time by
160 #define MAX_PROP_WORDS 100000
167 static garray_T serverReply
= { 0, 0, 0, 0, 0 };
168 enum ServerReplyOp
{ SROP_Find
, SROP_Add
, SROP_Delete
};
170 typedef int (*EndCond
) __ARGS((void *));
173 * Forward declarations for procedures defined later in this file:
176 static Window LookupName
__ARGS((Display
*dpy
, char_u
*name
, int delete, char_u
**loose
));
177 static int SendInit
__ARGS((Display
*dpy
));
178 static int DoRegisterName
__ARGS((Display
*dpy
, char_u
*name
));
179 static void DeleteAnyLingerer
__ARGS((Display
*dpy
, Window w
));
180 static int GetRegProp
__ARGS((Display
*dpy
, char_u
**regPropp
, long_u
*numItemsp
, int domsg
));
181 static int WaitForPend
__ARGS((void *p
));
182 static int WaitForReply
__ARGS((void *p
));
183 static int WindowValid
__ARGS((Display
*dpy
, Window w
));
184 static void ServerWait
__ARGS((Display
*dpy
, Window w
, EndCond endCond
, void *endData
, int localLoop
, int seconds
));
185 static struct ServerReply
*ServerReplyFind
__ARGS((Window w
, enum ServerReplyOp op
));
186 static int AppendPropCarefully
__ARGS((Display
*display
, Window window
, Atom property
, char_u
*value
, int length
));
187 static int x_error_check
__ARGS((Display
*dpy
, XErrorEvent
*error_event
));
188 static int IsSerialName
__ARGS((char_u
*name
));
190 /* Private variables for the "server" functionality */
191 static Atom registryProperty
= None
;
192 static Atom vimProperty
= None
;
193 static int got_x_error
= FALSE
;
195 static char_u
*empty_prop
= (char_u
*)""; /* empty GetRegProp() result */
198 * Associate an ASCII name with Vim. Try real hard to get a unique one.
199 * Returns FAIL or OK.
202 serverRegisterName(dpy
, name
)
203 Display
*dpy
; /* display to register with */
204 char_u
*name
; /* the name that will be used as a base */
210 res
= DoRegisterName(dpy
, name
);
216 if (res
< -1 || i
>= 1000)
218 MSG_ATTR(_("Unable to register a command server name"),
223 p
= alloc(STRLEN(name
) + 10);
229 sprintf((char *)p
, "%s%d", name
, i
++);
230 res
= DoRegisterName(dpy
, p
);
240 DoRegisterName(dpy
, name
)
245 XErrorHandler old_handler
;
246 #define MAX_NAME_LENGTH 100
247 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
249 if (commProperty
== None
)
251 if (SendInit(dpy
) < 0)
256 * Make sure the name is unique, and append info about it to
257 * the registry property. It's important to lock the server
258 * here to prevent conflicting changes to the registry property.
259 * WARNING: Do not step through this while debugging, it will hangup the X
263 w
= LookupName(dpy
, name
, FALSE
, NULL
);
268 unsigned int dummyUns
;
272 * The name is currently registered. See if the commWindow
273 * associated with the name exists. If not, or if the commWindow
274 * is *our* commWindow, then just unregister the old name (this
275 * could happen if an application dies without cleaning up the
278 old_handler
= XSetErrorHandler(x_error_check
);
279 status
= XGetGeometry(dpy
, w
, &dummyWin
, &dummyInt
, &dummyInt
,
280 &dummyUns
, &dummyUns
, &dummyUns
, &dummyUns
);
281 (void)XSetErrorHandler(old_handler
);
282 if (status
!= Success
&& w
!= commWindow
)
288 (void)LookupName(dpy
, name
, /*delete=*/TRUE
, NULL
);
290 sprintf((char *)propInfo
, "%x %.*s", (int_u
)commWindow
,
291 MAX_NAME_LENGTH
, name
);
292 old_handler
= XSetErrorHandler(x_error_check
);
294 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
295 PropModeAppend
, propInfo
, STRLEN(propInfo
) + 1);
298 (void)XSetErrorHandler(old_handler
);
303 set_vim_var_string(VV_SEND_SERVER
, name
, -1);
305 serverName
= vim_strsave(name
);
307 need_maketitle
= TRUE
;
314 #if defined(FEAT_GUI) || defined(PROTO)
316 * Clean out new ID from registry and set it as comm win.
317 * Change any registered window ID.
320 serverChangeRegisteredWindow(dpy
, newwin
)
321 Display
*dpy
; /* Display to register with */
322 Window newwin
; /* Re-register to this ID */
324 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
328 /* Always call SendInit() here, to make sure commWindow is marked as a Vim
330 if (SendInit(dpy
) < 0)
333 /* WARNING: Do not step through this while debugging, it will hangup the X
336 DeleteAnyLingerer(dpy
, newwin
);
337 if (serverName
!= NULL
)
339 /* Reinsert name if we was already registered */
340 (void)LookupName(dpy
, serverName
, /*delete=*/TRUE
, NULL
);
341 sprintf((char *)propInfo
, "%x %.*s",
342 (int_u
)newwin
, MAX_NAME_LENGTH
, serverName
);
343 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
344 PropModeAppend
, (char_u
*)propInfo
,
345 STRLEN(propInfo
) + 1);
352 * Send to an instance of Vim via the X display.
353 * Returns 0 for OK, negative for an error.
356 serverSendToVim(dpy
, name
, cmd
, result
, server
, asExpr
, localLoop
, silent
)
357 Display
*dpy
; /* Where to send. */
358 char_u
*name
; /* Where to send. */
359 char_u
*cmd
; /* What to send. */
360 char_u
**result
; /* Result of eval'ed expression */
361 Window
*server
; /* Actual ID of receiving app */
362 Bool asExpr
; /* Interpret as keystrokes or expr ? */
363 Bool localLoop
; /* Throw away everything but result */
364 int silent
; /* don't complain about no server */
370 static int serial
= 0; /* Running count of sent commands.
371 * Used to give each command a
372 * different serial number. */
373 PendingCommand pending
;
374 char_u
*loosename
= NULL
;
378 if (name
== NULL
|| *name
== NUL
)
379 name
= (char_u
*)"GVIM"; /* use a default name */
381 if (commProperty
== None
&& dpy
!= NULL
)
383 if (SendInit(dpy
) < 0)
387 /* Execute locally if no display or target is ourselves */
388 if (dpy
== NULL
|| (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0))
394 ret
= eval_client_expr_to_string(cmd
);
398 *result
= vim_strsave((char_u
*)_(e_invexprmsg
));
404 return ret
== NULL
? -1 : 0;
407 server_to_input_buf(cmd
);
412 * Bind the server name to a communication window.
414 * Find any survivor with a serialno attached to the name if the
415 * original registrant of the wanted name is no longer present.
417 * Delete any lingering names from dead editors.
421 w
= LookupName(dpy
, name
, FALSE
, &loosename
);
422 /* Check that the window is hot */
425 if (!WindowValid(dpy
, w
))
427 LookupName(dpy
, loosename
? loosename
: name
,
428 /*DELETE=*/TRUE
, NULL
);
437 EMSG2(_(e_noserver
), name
);
440 else if (loosename
!= NULL
)
446 * Send the command to target interpreter by appending it to the
447 * comm window in the communication window.
448 * Length must be computed exactly!
451 length
= STRLEN(name
) + STRLEN(p_enc
) + STRLEN(cmd
) + 14;
453 length
= STRLEN(name
) + STRLEN(cmd
) + 10;
455 property
= (char_u
*)alloc((unsigned)length
+ 30);
458 sprintf((char *)property
, "%c%c%c-n %s%c-E %s%c-s %s",
459 0, asExpr
? 'c' : 'k', 0, name
, 0, p_enc
, 0, cmd
);
461 sprintf((char *)property
, "%c%c%c-n %s%c-s %s",
462 0, asExpr
? 'c' : 'k', 0, name
, 0, cmd
);
464 if (name
== loosename
)
466 /* Add a back reference to our comm window */
468 sprintf((char *)property
+ length
, "%c-r %x %d",
469 0, (int_u
)commWindow
, serial
);
470 /* Add length of what "-r %x %d" resulted in, skipping the NUL. */
471 length
+= STRLEN(property
+ length
+ 1) + 1;
473 res
= AppendPropCarefully(dpy
, w
, commProperty
, property
, length
+ 1);
477 EMSG(_("E248: Failed to send command to the destination program"));
481 if (!asExpr
) /* There is no answer for this - Keys are sent async */
485 * Register the fact that we're waiting for a command to
486 * complete (this is needed by SendEventProc and by
487 * AppendErrorProc to pass back the command's results).
489 pending
.serial
= serial
;
491 pending
.result
= NULL
;
492 pending
.nextPtr
= pendingCommands
;
493 pendingCommands
= &pending
;
495 ServerWait(dpy
, w
, WaitForPend
, &pending
, localLoop
, 600);
498 * Unregister the information about the pending command
499 * and return the result.
501 if (pendingCommands
== &pending
)
502 pendingCommands
= pending
.nextPtr
;
505 PendingCommand
*pcPtr
;
507 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
508 if (pcPtr
->nextPtr
== &pending
)
510 pcPtr
->nextPtr
= pending
.nextPtr
;
515 *result
= pending
.result
;
517 vim_free(pending
.result
);
519 return pending
.code
== 0 ? 0 : -1;
526 PendingCommand
*pending
= (PendingCommand
*) p
;
527 return pending
->result
!= NULL
;
531 * Return TRUE if window "w" exists and has a "Vim" property on it.
538 XErrorHandler old_handler
;
543 old_handler
= XSetErrorHandler(x_error_check
);
545 plist
= XListProperties(dpy
, w
, &numProp
);
547 XSetErrorHandler(old_handler
);
548 if (plist
== NULL
|| got_x_error
)
551 for (i
= 0; i
< numProp
; i
++)
552 if (plist
[i
] == vimProperty
)
562 * Enter a loop processing X events & polling chars until we see a result
565 ServerWait(dpy
, w
, endCond
, endData
, localLoop
, seconds
)
577 XPropertyEvent
*e
= (XPropertyEvent
*)&event
;
578 # define SEND_MSEC_POLL 50
581 while (endCond(endData
) == 0)
584 if (seconds
>= 0 && (now
- start
) >= seconds
)
589 if (!WindowValid(dpy
, w
))
592 * Sometimes the PropertyChange event doesn't come.
593 * This can be seen in eg: vim -c 'echo remote_expr("gvim", "3+2")'
595 serverEventProc(dpy
, NULL
);
599 /* Just look out for the answer without calling back into Vim */
603 fds
.fd
= ConnectionNumber(dpy
);
605 if (poll(&fds
, 1, SEND_MSEC_POLL
) < 0)
612 tv
.tv_usec
= SEND_MSEC_POLL
* 1000;
614 FD_SET(ConnectionNumber(dpy
), &fds
);
615 if (select(ConnectionNumber(dpy
) + 1, &fds
, NULL
, NULL
, &tv
) < 0)
618 while (XEventsQueued(dpy
, QueuedAfterReading
) > 0)
620 XNextEvent(dpy
, &event
);
621 if (event
.type
== PropertyNotify
&& e
->window
== commWindow
)
622 serverEventProc(dpy
, &event
);
629 ui_delay((long)SEND_MSEC_POLL
, TRUE
);
637 * Fetch a list of all the Vim instance names currently registered for the
640 * Returns a newline separated list in allocated memory or NULL.
643 serverGetVimNames(dpy
)
653 if (registryProperty
== None
)
655 if (SendInit(dpy
) < 0)
658 ga_init2(&ga
, 1, 100);
661 * Read the registry property.
663 if (GetRegProp(dpy
, ®Prop
, &numItems
, TRUE
) == FAIL
)
667 * Scan all of the names out of the property.
669 ga_init2(&ga
, 1, 100);
670 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; p
++)
673 while (*p
!= 0 && !isspace(*p
))
678 sscanf((char *)entry
, "%x", &w
);
679 if (WindowValid(dpy
, (Window
)w
))
681 ga_concat(&ga
, p
+ 1);
682 ga_concat(&ga
, (char_u
*)"\n");
688 if (regProp
!= empty_prop
)
694 /* ----------------------------------------------------------
698 static struct ServerReply
*
699 ServerReplyFind(w
, op
)
701 enum ServerReplyOp op
;
703 struct ServerReply
*p
;
704 struct ServerReply e
;
707 p
= (struct ServerReply
*) serverReply
.ga_data
;
708 for (i
= 0; i
< serverReply
.ga_len
; i
++, p
++)
711 if (i
>= serverReply
.ga_len
)
714 if (p
== NULL
&& op
== SROP_Add
)
716 if (serverReply
.ga_growsize
== 0)
717 ga_init2(&serverReply
, sizeof(struct ServerReply
), 1);
718 if (ga_grow(&serverReply
, 1) == OK
)
720 p
= ((struct ServerReply
*) serverReply
.ga_data
)
721 + serverReply
.ga_len
;
723 ga_init2(&e
.strings
, 1, 100);
724 mch_memmove(p
, &e
, sizeof(e
));
725 serverReply
.ga_len
++;
728 else if (p
!= NULL
&& op
== SROP_Delete
)
730 ga_clear(&p
->strings
);
731 mch_memmove(p
, p
+ 1, (serverReply
.ga_len
- i
- 1) * sizeof(*p
));
732 serverReply
.ga_len
--;
739 * Convert string to windowid.
740 * Issue an error if the id is invalid.
748 sscanf((char *)str
, "0x%x", &id
);
750 EMSG2(_("E573: Invalid server id used: %s"), str
);
756 * Send a reply string (notification) to client with id "name".
757 * Return -1 if the window is invalid.
760 serverSendReply(name
, str
)
767 Display
*dpy
= X_DISPLAY
;
768 Window win
= serverStrToWin(name
);
770 if (commProperty
== None
)
772 if (SendInit(dpy
) < 0)
775 if (!WindowValid(dpy
, win
))
779 length
= STRLEN(p_enc
) + STRLEN(str
) + 14;
781 length
= STRLEN(str
) + 10;
783 if ((property
= (char_u
*)alloc((unsigned)length
+ 30)) != NULL
)
786 sprintf((char *)property
, "%cn%c-E %s%c-n %s%c-w %x",
787 0, 0, p_enc
, 0, str
, 0, (unsigned int)commWindow
);
789 sprintf((char *)property
, "%cn%c-n %s%c-w %x",
790 0, 0, str
, 0, (unsigned int)commWindow
);
792 /* Add length of what "%x" resulted in. */
793 length
+= STRLEN(property
+ length
);
794 res
= AppendPropCarefully(dpy
, win
, commProperty
, property
, length
+ 1);
805 Window
*w
= (Window
*) p
;
806 return ServerReplyFind(*w
, SROP_Find
) != NULL
;
810 * Wait for replies from id (win)
811 * Return 0 and the malloc'ed string when a reply is available.
812 * Return -1 if the window becomes invalid while waiting.
815 serverReadReply(dpy
, win
, str
, localLoop
)
823 struct ServerReply
*p
;
825 ServerWait(dpy
, win
, WaitForReply
, &win
, localLoop
, -1);
827 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
829 *str
= vim_strsave(p
->strings
.ga_data
);
830 len
= STRLEN(*str
) + 1;
831 if (len
< p
->strings
.ga_len
)
833 s
= (char_u
*) p
->strings
.ga_data
;
834 mch_memmove(s
, s
+ len
, p
->strings
.ga_len
- len
);
835 p
->strings
.ga_len
-= len
;
839 /* Last string read. Remove from list */
840 ga_clear(&p
->strings
);
841 ServerReplyFind(win
, SROP_Delete
);
849 * Check for replies from id (win).
850 * Return TRUE and a non-malloc'ed string if there is. Else return FALSE.
853 serverPeekReply(dpy
, win
, str
)
858 struct ServerReply
*p
;
860 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
863 *str
= p
->strings
.ga_data
;
866 if (!WindowValid(dpy
, win
))
873 * Initialize the communication channels for sending commands and receiving
880 XErrorHandler old_handler
;
883 * Create the window used for communication, and set up an
884 * event handler for it.
886 old_handler
= XSetErrorHandler(x_error_check
);
889 if (commProperty
== None
)
890 commProperty
= XInternAtom(dpy
, "Comm", False
);
891 if (vimProperty
== None
)
892 vimProperty
= XInternAtom(dpy
, "Vim", False
);
893 if (registryProperty
== None
)
894 registryProperty
= XInternAtom(dpy
, "VimRegistry", False
);
896 if (commWindow
== None
)
898 commWindow
= XCreateSimpleWindow(dpy
, XDefaultRootWindow(dpy
),
899 getpid(), 0, 10, 10, 0,
900 WhitePixel(dpy
, DefaultScreen(dpy
)),
901 WhitePixel(dpy
, DefaultScreen(dpy
)));
902 XSelectInput(dpy
, commWindow
, PropertyChangeMask
);
903 /* WARNING: Do not step through this while debugging, it will hangup
906 DeleteAnyLingerer(dpy
, commWindow
);
910 /* Make window recognizable as a vim window */
911 XChangeProperty(dpy
, commWindow
, vimProperty
, XA_STRING
,
912 8, PropModeReplace
, (char_u
*)VIM_VERSION_SHORT
,
913 (int)STRLEN(VIM_VERSION_SHORT
) + 1);
916 (void)XSetErrorHandler(old_handler
);
918 return got_x_error
? -1 : 0;
922 * Given a server name, see if the name exists in the registry for a
923 * particular display.
925 * If the given name is registered, return the ID of the window associated
926 * with the name. If the name isn't registered, then return 0.
929 * If the registry property is improperly formed, then it is deleted.
930 * If "delete" is non-zero, then if the named server is found it is
931 * removed from the registry property.
934 LookupName(dpy
, name
, delete, loose
)
935 Display
*dpy
; /* Display whose registry to check. */
936 char_u
*name
; /* Name of a server. */
937 int delete; /* If non-zero, delete info about name. */
938 char_u
**loose
; /* Do another search matching -999 if not found
939 Return result here if a match is found */
941 char_u
*regProp
, *entry
;
947 * Read the registry property.
949 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
953 * Scan the property for the desired name.
955 returnValue
= (int_u
)None
;
956 entry
= NULL
; /* Not needed, but eliminates compiler warning. */
957 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
960 while (*p
!= 0 && !isspace(*p
))
962 if (*p
!= 0 && STRICMP(name
, p
+ 1) == 0)
964 sscanf((char *)entry
, "%x", &returnValue
);
972 if (loose
!= NULL
&& returnValue
== (int_u
)None
&& !IsSerialName(name
))
974 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
977 while (*p
!= 0 && !isspace(*p
))
979 if (*p
!= 0 && IsSerialName(p
+ 1)
980 && STRNICMP(name
, p
+ 1, STRLEN(name
)) == 0)
982 sscanf((char *)entry
, "%x", &returnValue
);
983 *loose
= vim_strsave(p
+ 1);
993 * Delete the property, if that is desired (copy down the
994 * remainder of the registry property to overlay the deleted
995 * info, then rewrite the property).
997 if (delete && returnValue
!= (int_u
)None
)
1004 count
= numItems
- (p
- regProp
);
1006 mch_memmove(entry
, p
, count
);
1007 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
,
1008 8, PropModeReplace
, regProp
,
1009 (int)(numItems
- (p
- entry
)));
1013 if (regProp
!= empty_prop
)
1015 return (Window
)returnValue
;
1019 * Delete any lingering occurrence of window id. We promise that any
1020 * occurrence is not ours since it is not yet put into the registry (by us)
1022 * This is necessary in the following scenario:
1023 * 1. There is an old windowid for an exit'ed vim in the registry
1024 * 2. We get that id for our commWindow but only want to send, not register.
1025 * 3. The window will mistakenly be regarded valid because of own commWindow
1028 DeleteAnyLingerer(dpy
, win
)
1029 Display
*dpy
; /* Display whose registry to check. */
1030 Window win
; /* Window to remove */
1032 char_u
*regProp
, *entry
= NULL
;
1038 * Read the registry property.
1040 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
1043 /* Scan the property for the window id. */
1044 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
1048 sscanf((char *)p
, "%x", &wwin
);
1049 if ((Window
)wwin
== win
)
1053 /* Copy down the remainder to delete entry */
1058 lastHalf
= numItems
- (p
- regProp
);
1060 mch_memmove(entry
, p
, lastHalf
);
1061 numItems
= (entry
- regProp
) + lastHalf
;
1073 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
,
1074 XA_STRING
, 8, PropModeReplace
, regProp
,
1075 (int)(p
- regProp
));
1079 if (regProp
!= empty_prop
)
1084 * Read the registry property. Delete it when it's formatted wrong.
1085 * Return the property in "regPropp". "empty_prop" is used when it doesn't
1087 * Return OK when successful.
1090 GetRegProp(dpy
, regPropp
, numItemsp
, domsg
)
1094 int domsg
; /* When TRUE give error message. */
1096 int result
, actualFormat
;
1099 XErrorHandler old_handler
;
1102 old_handler
= XSetErrorHandler(x_error_check
);
1103 got_x_error
= FALSE
;
1105 result
= XGetWindowProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, 0L,
1106 (long)MAX_PROP_WORDS
, False
,
1107 XA_STRING
, &actualType
,
1108 &actualFormat
, numItemsp
, &bytesAfter
,
1112 (void)XSetErrorHandler(old_handler
);
1116 if (actualType
== None
)
1118 /* No prop yet. Logically equal to the empty list */
1120 *regPropp
= empty_prop
;
1124 /* If the property is improperly formed, then delete it. */
1125 if (result
!= Success
|| actualFormat
!= 8 || actualType
!= XA_STRING
)
1127 if (*regPropp
!= NULL
)
1129 XDeleteProperty(dpy
, RootWindow(dpy
, 0), registryProperty
);
1131 EMSG(_("E251: VIM instance registry property is badly formed. Deleted!"));
1138 * This procedure is invoked by the various X event loops throughout Vims when
1139 * a property changes on the communication window. This procedure reads the
1140 * property and handles command requests and responses.
1143 serverEventProc(dpy
, eventPtr
)
1145 XEvent
*eventPtr
; /* Information about event. */
1149 int result
, actualFormat
, code
;
1150 long_u numItems
, bytesAfter
;
1154 if (eventPtr
!= NULL
)
1156 if (eventPtr
->xproperty
.atom
!= commProperty
1157 || eventPtr
->xproperty
.state
!= PropertyNewValue
)
1162 * Read the comm property and delete it.
1165 result
= XGetWindowProperty(dpy
, commWindow
, commProperty
, 0L,
1166 (long)MAX_PROP_WORDS
, True
,
1167 XA_STRING
, &actualType
,
1168 &actualFormat
, &numItems
, &bytesAfter
,
1171 /* If the property doesn't exist or is improperly formed then ignore it. */
1172 if (result
!= Success
|| actualType
!= XA_STRING
|| actualFormat
!= 8)
1174 if (propInfo
!= NULL
)
1180 * Several commands and results could arrive in the property at
1181 * one time; each iteration through the outer loop handles a
1182 * single command or result.
1184 for (p
= propInfo
; (long_u
)(p
- propInfo
) < numItems
; )
1187 * Ignore leading NULs; each command or result starts with a
1188 * NUL so that no matter how badly formed a preceding command
1189 * is, we'll be able to tell that a new command/result is
1198 if ((*p
== 'c' || *p
== 'k') && (p
[1] == 0))
1201 char_u
*name
, *script
, *serial
, *end
, *res
;
1202 Bool asKeys
= *p
== 'k';
1207 * This is an incoming command from some other application.
1208 * Iterate over all of its options. Stop when we reach
1209 * the end of the property or something that doesn't look
1215 serial
= (char_u
*)"";
1218 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1223 end
= skipwhite(p
+ 2);
1225 while (vim_isxdigit(*end
))
1227 resWindow
= 16 * resWindow
+ (long_u
)hex2nr(*end
);
1230 if (end
== p
+ 2 || *end
!= ' ')
1234 p
= serial
= end
+ 1;
1235 clientWindow
= resWindow
; /* Remember in global */
1256 if (script
== NULL
|| name
== NULL
)
1260 * Initialize the result property, so that we're ready at any
1261 * time if we need to return an error.
1263 if (resWindow
!= None
)
1265 ga_init2(&reply
, 1, 100);
1267 ga_grow(&reply
, 50 + STRLEN(p_enc
));
1268 sprintf(reply
.ga_data
, "%cr%c-E %s%c-s %s%c-r ",
1269 0, 0, p_enc
, 0, serial
, 0);
1270 reply
.ga_len
= 14 + STRLEN(p_enc
) + STRLEN(serial
);
1272 ga_grow(&reply
, 50);
1273 sprintf(reply
.ga_data
, "%cr%c-s %s%c-r ", 0, 0, serial
, 0);
1274 reply
.ga_len
= 10 + STRLEN(serial
);
1278 if (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0)
1280 script
= serverConvert(enc
, script
, &tofree
);
1282 server_to_input_buf(script
);
1284 res
= eval_client_expr_to_string(script
);
1287 if (resWindow
!= None
)
1290 ga_concat(&reply
, res
);
1291 else if (asKeys
== 0)
1293 ga_concat(&reply
, (char_u
*)_(e_invexprmsg
));
1294 ga_append(&reply
, 0);
1295 ga_concat(&reply
, (char_u
*)"-c 1");
1297 ga_append(&reply
, NUL
);
1298 (void)AppendPropCarefully(dpy
, resWindow
, commProperty
,
1299 reply
.ga_data
, reply
.ga_len
);
1304 else if (*p
== 'r' && p
[1] == 0)
1306 int serial
, gotSerial
;
1308 PendingCommand
*pcPtr
;
1312 * This is a reply to some command that we sent out. Iterate
1313 * over all of its options. Stop when we reach the end of the
1314 * property or something that doesn't look like an option.
1321 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1334 if (sscanf((char *)p
+ 2, " %d", &serial
) == 1)
1338 if (sscanf((char *)p
+ 2, " %d", &code
) != 1)
1351 * Give the result information to anyone who's
1354 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
1356 if (serial
!= pcPtr
->serial
|| pcPtr
->result
!= NULL
)
1362 res
= serverConvert(enc
, res
, &tofree
);
1364 res
= vim_strsave(res
);
1365 pcPtr
->result
= res
;
1368 pcPtr
->result
= vim_strsave((char_u
*)"");
1372 else if (*p
== 'n' && p
[1] == 0)
1378 struct ServerReply
*r
;
1382 * This is a (n)otification. Sent with serverreply_send in VimL.
1383 * Execute any autocommand and save it for later retrieval
1389 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1402 if (sscanf((char *)p
+ 2, " %x", &u
) == 1)
1416 str
= serverConvert(enc
, str
, &tofree
);
1417 if ((r
= ServerReplyFind(win
, SROP_Add
)) != NULL
)
1419 ga_concat(&(r
->strings
), str
);
1420 ga_append(&(r
->strings
), NUL
);
1426 sprintf((char *)winstr
, "0x%x", (unsigned int)win
);
1427 apply_autocmds(EVENT_REMOTEREPLY
, winstr
, str
, TRUE
, curbuf
);
1435 * Didn't recognize this thing. Just skip through the next
1436 * null character and try again.
1437 * Even if we get an 'r'(eply) we will throw it away as we
1438 * never specify (and thus expect) one
1449 * Append a given property to a given window, but set up an X error handler so
1450 * that if the append fails this procedure can return an error code rather
1451 * than having Xlib panic.
1452 * Return: 0 for OK, -1 for error
1455 AppendPropCarefully(dpy
, window
, property
, value
, length
)
1456 Display
*dpy
; /* Display on which to operate. */
1457 Window window
; /* Window whose property is to be modified. */
1458 Atom property
; /* Name of property. */
1459 char_u
*value
; /* Characters to append to property. */
1460 int length
; /* How much to append */
1462 XErrorHandler old_handler
;
1464 old_handler
= XSetErrorHandler(x_error_check
);
1465 got_x_error
= FALSE
;
1466 XChangeProperty(dpy
, window
, property
, XA_STRING
, 8,
1467 PropModeAppend
, value
, length
);
1469 (void) XSetErrorHandler(old_handler
);
1470 return got_x_error
? -1 : 0;
1475 * Another X Error handler, just used to check for errors.
1478 x_error_check(dpy
, error_event
)
1479 Display
*dpy UNUSED
;
1480 XErrorEvent
*error_event UNUSED
;
1487 * Check if "str" looks like it had a serial number appended.
1488 * Actually just checks if the name ends in a digit.
1494 int len
= STRLEN(str
);
1496 return (len
> 1 && vim_isdigit(str
[len
- 1]));
1498 #endif /* FEAT_CLIENTSERVER */