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)) \
18 && !defined(MAC_CLIENTSERVER)
21 # include <X11/Intrinsic.h>
22 # include <X11/Xatom.h>
26 * This file provides procedures that implement the command server
27 * functionality of Vim when in contact with an X11 server.
29 * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution.
30 * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4
34 * Copyright (c) 1989-1993 The Regents of the University of California.
35 * All rights reserved.
37 * Permission is hereby granted, without written agreement and without
38 * license or royalty fees, to use, copy, modify, and distribute this
39 * software and its documentation for any purpose, provided that the
40 * above copyright notice and the following two paragraphs appear in
41 * all copies of this software.
43 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
44 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
45 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
46 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
49 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
50 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
51 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
52 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
57 * When a result is being awaited from a sent command, one of
58 * the following structures is present on a list of all outstanding
59 * sent commands. The information in the structure is used to
60 * process the result when it arrives. You're probably wondering
61 * how there could ever be multiple outstanding sent commands.
62 * This could happen if Vim instances invoke each other recursively.
63 * It's unlikely, but possible.
66 typedef struct PendingCommand
68 int serial
; /* Serial number expected in result. */
69 int code
; /* Result Code. 0 is OK */
70 char_u
*result
; /* String result for command (malloc'ed).
71 * NULL means command still pending. */
72 struct PendingCommand
*nextPtr
;
73 /* Next in list of all outstanding commands.
74 * NULL means end of list. */
77 static PendingCommand
*pendingCommands
= NULL
;
78 /* List of all commands currently
79 * being waited for. */
82 * The information below is used for communication between processes
83 * during "send" commands. Each process keeps a private window, never
84 * even mapped, with one property, "Comm". When a command is sent to
85 * an interpreter, the command is appended to the comm property of the
86 * communication window associated with the interp's process. Similarly,
87 * when a result is returned from a sent command, it is also appended
88 * to the comm property.
90 * Each command and each result takes the form of ASCII text. For a
91 * command, the text consists of a nul character followed by several
92 * nul-terminated ASCII strings. The first string consists of a
94 * "c" for an expression
97 * "n" for notification.
98 * Subsequent strings have the form "option value" where the following options
101 * -r commWindow serial
103 * This option means that a response should be sent to the window
104 * whose X identifier is "commWindow" (in hex), and the response should
105 * be identified with the serial number given by "serial" (in decimal).
106 * If this option isn't specified then the send is asynchronous and
107 * no response is sent.
110 * "Name" gives the name of the application for which the command is
111 * intended. This option must be present.
114 * Encoding name used for the text. This is the 'encoding' of the
115 * sender. The receiver may want to do conversion to his 'encoding'.
118 * "Script" is the script to be executed. This option must be
119 * present. Taken as a series of keystrokes in a "k" command where
120 * <Key>'s are expanded
122 * The options may appear in any order. The -n and -s options must be
123 * present, but -r may be omitted for asynchronous RPCs. For compatibility
124 * with future releases that may add new features, there may be additional
125 * options present; as long as they start with a "-" character, they will
128 * A result also consists of a zero character followed by several null-
129 * terminated ASCII strings. The first string consists of the single
130 * letter "r". Subsequent strings have the form "option value" where
131 * the following options are supported:
134 * Identifies the command for which this is the result. It is the
135 * same as the "serial" field from the -s option in the command. This
136 * option must be present.
139 * "Result" is the result string for the script, which may be either
140 * a result or an error message. If this field is omitted then it
141 * defaults to an empty string.
144 * 0: for OK. This is the default.
145 * 1: for error: Result is the last error
149 * Not applicable for Vim
151 * Options may appear in any order, and only the -s option must be
152 * present. As with commands, there may be additional options besides
153 * these; unknown options are ignored.
157 * Maximum size property that can be read at one time by
161 #define MAX_PROP_WORDS 100000
168 static garray_T serverReply
= { 0, 0, 0, 0, 0 };
169 enum ServerReplyOp
{ SROP_Find
, SROP_Add
, SROP_Delete
};
171 typedef int (*EndCond
) __ARGS((void *));
174 * Forward declarations for procedures defined later in this file:
177 static Window LookupName
__ARGS((Display
*dpy
, char_u
*name
, int delete, char_u
**loose
));
178 static int SendInit
__ARGS((Display
*dpy
));
179 static int DoRegisterName
__ARGS((Display
*dpy
, char_u
*name
));
180 static void DeleteAnyLingerer
__ARGS((Display
*dpy
, Window w
));
181 static int GetRegProp
__ARGS((Display
*dpy
, char_u
**regPropp
, long_u
*numItemsp
, int domsg
));
182 static int WaitForPend
__ARGS((void *p
));
183 static int WaitForReply
__ARGS((void *p
));
184 static int WindowValid
__ARGS((Display
*dpy
, Window w
));
185 static void ServerWait
__ARGS((Display
*dpy
, Window w
, EndCond endCond
, void *endData
, int localLoop
, int seconds
));
186 static struct ServerReply
*ServerReplyFind
__ARGS((Window w
, enum ServerReplyOp op
));
187 static int AppendPropCarefully
__ARGS((Display
*display
, Window window
, Atom property
, char_u
*value
, int length
));
188 static int x_error_check
__ARGS((Display
*dpy
, XErrorEvent
*error_event
));
189 static int IsSerialName
__ARGS((char_u
*name
));
191 /* Private variables for the "server" functionality */
192 static Atom registryProperty
= None
;
193 static Atom vimProperty
= None
;
194 static int got_x_error
= FALSE
;
196 static char_u
*empty_prop
= (char_u
*)""; /* empty GetRegProp() result */
199 * Associate an ASCII name with Vim. Try real hard to get a unique one.
200 * Returns FAIL or OK.
203 serverRegisterName(dpy
, name
)
204 Display
*dpy
; /* display to register with */
205 char_u
*name
; /* the name that will be used as a base */
211 res
= DoRegisterName(dpy
, name
);
217 if (res
< -1 || i
>= 1000)
219 MSG_ATTR(_("Unable to register a command server name"),
224 p
= alloc(STRLEN(name
) + 10);
230 sprintf((char *)p
, "%s%d", name
, i
++);
231 res
= DoRegisterName(dpy
, p
);
241 DoRegisterName(dpy
, name
)
246 XErrorHandler old_handler
;
247 #define MAX_NAME_LENGTH 100
248 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
250 if (commProperty
== None
)
252 if (SendInit(dpy
) < 0)
257 * Make sure the name is unique, and append info about it to
258 * the registry property. It's important to lock the server
259 * here to prevent conflicting changes to the registry property.
260 * WARNING: Do not step through this while debugging, it will hangup the X
264 w
= LookupName(dpy
, name
, FALSE
, NULL
);
269 unsigned int dummyUns
;
273 * The name is currently registered. See if the commWindow
274 * associated with the name exists. If not, or if the commWindow
275 * is *our* commWindow, then just unregister the old name (this
276 * could happen if an application dies without cleaning up the
279 old_handler
= XSetErrorHandler(x_error_check
);
280 status
= XGetGeometry(dpy
, w
, &dummyWin
, &dummyInt
, &dummyInt
,
281 &dummyUns
, &dummyUns
, &dummyUns
, &dummyUns
);
282 (void)XSetErrorHandler(old_handler
);
283 if (status
!= Success
&& w
!= commWindow
)
289 (void)LookupName(dpy
, name
, /*delete=*/TRUE
, NULL
);
291 sprintf((char *)propInfo
, "%x %.*s", (int_u
)commWindow
,
292 MAX_NAME_LENGTH
, name
);
293 old_handler
= XSetErrorHandler(x_error_check
);
295 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
296 PropModeAppend
, propInfo
, STRLEN(propInfo
) + 1);
299 (void)XSetErrorHandler(old_handler
);
304 set_vim_var_string(VV_SEND_SERVER
, name
, -1);
306 serverName
= vim_strsave(name
);
308 need_maketitle
= TRUE
;
315 #if defined(FEAT_GUI) || defined(PROTO)
317 * Clean out new ID from registry and set it as comm win.
318 * Change any registered window ID.
321 serverChangeRegisteredWindow(dpy
, newwin
)
322 Display
*dpy
; /* Display to register with */
323 Window newwin
; /* Re-register to this ID */
325 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
329 /* Always call SendInit() here, to make sure commWindow is marked as a Vim
331 if (SendInit(dpy
) < 0)
334 /* WARNING: Do not step through this while debugging, it will hangup the X
337 DeleteAnyLingerer(dpy
, newwin
);
338 if (serverName
!= NULL
)
340 /* Reinsert name if we was already registered */
341 (void)LookupName(dpy
, serverName
, /*delete=*/TRUE
, NULL
);
342 sprintf((char *)propInfo
, "%x %.*s",
343 (int_u
)newwin
, MAX_NAME_LENGTH
, serverName
);
344 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
345 PropModeAppend
, (char_u
*)propInfo
,
346 STRLEN(propInfo
) + 1);
353 * Send to an instance of Vim via the X display.
354 * Returns 0 for OK, negative for an error.
357 serverSendToVim(dpy
, name
, cmd
, result
, server
, asExpr
, localLoop
, silent
)
358 Display
*dpy
; /* Where to send. */
359 char_u
*name
; /* Where to send. */
360 char_u
*cmd
; /* What to send. */
361 char_u
**result
; /* Result of eval'ed expression */
362 Window
*server
; /* Actual ID of receiving app */
363 Bool asExpr
; /* Interpret as keystrokes or expr ? */
364 Bool localLoop
; /* Throw away everything but result */
365 int silent
; /* don't complain about no server */
371 static int serial
= 0; /* Running count of sent commands.
372 * Used to give each command a
373 * different serial number. */
374 PendingCommand pending
;
375 char_u
*loosename
= NULL
;
379 if (name
== NULL
|| *name
== NUL
)
380 name
= (char_u
*)"GVIM"; /* use a default name */
382 if (commProperty
== None
&& dpy
!= NULL
)
384 if (SendInit(dpy
) < 0)
388 /* Execute locally if no display or target is ourselves */
389 if (dpy
== NULL
|| (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0))
395 ret
= eval_client_expr_to_string(cmd
);
399 *result
= vim_strsave((char_u
*)_(e_invexprmsg
));
405 return ret
== NULL
? -1 : 0;
408 server_to_input_buf(cmd
);
413 * Bind the server name to a communication window.
415 * Find any survivor with a serialno attached to the name if the
416 * original registrant of the wanted name is no longer present.
418 * Delete any lingering names from dead editors.
422 w
= LookupName(dpy
, name
, FALSE
, &loosename
);
423 /* Check that the window is hot */
426 if (!WindowValid(dpy
, w
))
428 LookupName(dpy
, loosename
? loosename
: name
,
429 /*DELETE=*/TRUE
, NULL
);
438 EMSG2(_(e_noserver
), name
);
441 else if (loosename
!= NULL
)
447 * Send the command to target interpreter by appending it to the
448 * comm window in the communication window.
449 * Length must be computed exactly!
452 length
= STRLEN(name
) + STRLEN(p_enc
) + STRLEN(cmd
) + 14;
454 length
= STRLEN(name
) + STRLEN(cmd
) + 10;
456 property
= (char_u
*)alloc((unsigned)length
+ 30);
459 sprintf((char *)property
, "%c%c%c-n %s%c-E %s%c-s %s",
460 0, asExpr
? 'c' : 'k', 0, name
, 0, p_enc
, 0, cmd
);
462 sprintf((char *)property
, "%c%c%c-n %s%c-s %s",
463 0, asExpr
? 'c' : 'k', 0, name
, 0, cmd
);
465 if (name
== loosename
)
467 /* Add a back reference to our comm window */
469 sprintf((char *)property
+ length
, "%c-r %x %d",
470 0, (int_u
)commWindow
, serial
);
471 /* Add length of what "-r %x %d" resulted in, skipping the NUL. */
472 length
+= STRLEN(property
+ length
+ 1) + 1;
474 res
= AppendPropCarefully(dpy
, w
, commProperty
, property
, length
+ 1);
478 EMSG(_("E248: Failed to send command to the destination program"));
482 if (!asExpr
) /* There is no answer for this - Keys are sent async */
486 * Register the fact that we're waiting for a command to
487 * complete (this is needed by SendEventProc and by
488 * AppendErrorProc to pass back the command's results).
490 pending
.serial
= serial
;
492 pending
.result
= NULL
;
493 pending
.nextPtr
= pendingCommands
;
494 pendingCommands
= &pending
;
496 ServerWait(dpy
, w
, WaitForPend
, &pending
, localLoop
, 600);
499 * Unregister the information about the pending command
500 * and return the result.
502 if (pendingCommands
== &pending
)
503 pendingCommands
= pending
.nextPtr
;
506 PendingCommand
*pcPtr
;
508 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
509 if (pcPtr
->nextPtr
== &pending
)
511 pcPtr
->nextPtr
= pending
.nextPtr
;
516 *result
= pending
.result
;
518 vim_free(pending
.result
);
520 return pending
.code
== 0 ? 0 : -1;
527 PendingCommand
*pending
= (PendingCommand
*) p
;
528 return pending
->result
!= NULL
;
532 * Return TRUE if window "w" exists and has a "Vim" property on it.
539 XErrorHandler old_handler
;
544 old_handler
= XSetErrorHandler(x_error_check
);
546 plist
= XListProperties(dpy
, w
, &numProp
);
548 XSetErrorHandler(old_handler
);
549 if (plist
== NULL
|| got_x_error
)
552 for (i
= 0; i
< numProp
; i
++)
553 if (plist
[i
] == vimProperty
)
563 * Enter a loop processing X events & polling chars until we see a result
566 ServerWait(dpy
, w
, endCond
, endData
, localLoop
, seconds
)
578 XPropertyEvent
*e
= (XPropertyEvent
*)&event
;
579 # define SEND_MSEC_POLL 50
582 while (endCond(endData
) == 0)
585 if (seconds
>= 0 && (now
- start
) >= seconds
)
590 if (!WindowValid(dpy
, w
))
593 * Sometimes the PropertyChange event doesn't come.
594 * This can be seen in eg: vim -c 'echo remote_expr("gvim", "3+2")'
596 serverEventProc(dpy
, NULL
);
600 /* Just look out for the answer without calling back into Vim */
604 fds
.fd
= ConnectionNumber(dpy
);
606 if (poll(&fds
, 1, SEND_MSEC_POLL
) < 0)
613 tv
.tv_usec
= SEND_MSEC_POLL
* 1000;
615 FD_SET(ConnectionNumber(dpy
), &fds
);
616 if (select(ConnectionNumber(dpy
) + 1, &fds
, NULL
, NULL
, &tv
) < 0)
619 while (XEventsQueued(dpy
, QueuedAfterReading
) > 0)
621 XNextEvent(dpy
, &event
);
622 if (event
.type
== PropertyNotify
&& e
->window
== commWindow
)
623 serverEventProc(dpy
, &event
);
630 ui_delay((long)SEND_MSEC_POLL
, TRUE
);
638 * Fetch a list of all the Vim instance names currently registered for the
641 * Returns a newline separated list in allocated memory or NULL.
644 serverGetVimNames(dpy
)
654 if (registryProperty
== None
)
656 if (SendInit(dpy
) < 0)
659 ga_init2(&ga
, 1, 100);
662 * Read the registry property.
664 if (GetRegProp(dpy
, ®Prop
, &numItems
, TRUE
) == FAIL
)
668 * Scan all of the names out of the property.
670 ga_init2(&ga
, 1, 100);
671 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; p
++)
674 while (*p
!= 0 && !isspace(*p
))
679 sscanf((char *)entry
, "%x", &w
);
680 if (WindowValid(dpy
, (Window
)w
))
682 ga_concat(&ga
, p
+ 1);
683 ga_concat(&ga
, (char_u
*)"\n");
689 if (regProp
!= empty_prop
)
695 /* ----------------------------------------------------------
699 static struct ServerReply
*
700 ServerReplyFind(w
, op
)
702 enum ServerReplyOp op
;
704 struct ServerReply
*p
;
705 struct ServerReply e
;
708 p
= (struct ServerReply
*) serverReply
.ga_data
;
709 for (i
= 0; i
< serverReply
.ga_len
; i
++, p
++)
712 if (i
>= serverReply
.ga_len
)
715 if (p
== NULL
&& op
== SROP_Add
)
717 if (serverReply
.ga_growsize
== 0)
718 ga_init2(&serverReply
, sizeof(struct ServerReply
), 1);
719 if (ga_grow(&serverReply
, 1) == OK
)
721 p
= ((struct ServerReply
*) serverReply
.ga_data
)
722 + serverReply
.ga_len
;
724 ga_init2(&e
.strings
, 1, 100);
725 mch_memmove(p
, &e
, sizeof(e
));
726 serverReply
.ga_len
++;
729 else if (p
!= NULL
&& op
== SROP_Delete
)
731 ga_clear(&p
->strings
);
732 mch_memmove(p
, p
+ 1, (serverReply
.ga_len
- i
- 1) * sizeof(*p
));
733 serverReply
.ga_len
--;
740 * Convert string to windowid.
741 * Issue an error if the id is invalid.
749 sscanf((char *)str
, "0x%x", &id
);
751 EMSG2(_("E573: Invalid server id used: %s"), str
);
757 * Send a reply string (notification) to client with id "name".
758 * Return -1 if the window is invalid.
761 serverSendReply(name
, str
)
768 Display
*dpy
= X_DISPLAY
;
769 Window win
= serverStrToWin(name
);
771 if (commProperty
== None
)
773 if (SendInit(dpy
) < 0)
776 if (!WindowValid(dpy
, win
))
780 length
= STRLEN(p_enc
) + STRLEN(str
) + 14;
782 length
= STRLEN(str
) + 10;
784 if ((property
= (char_u
*)alloc((unsigned)length
+ 30)) != NULL
)
787 sprintf((char *)property
, "%cn%c-E %s%c-n %s%c-w %x",
788 0, 0, p_enc
, 0, str
, 0, (unsigned int)commWindow
);
790 sprintf((char *)property
, "%cn%c-n %s%c-w %x",
791 0, 0, str
, 0, (unsigned int)commWindow
);
793 /* Add length of what "%x" resulted in. */
794 length
+= STRLEN(property
+ length
);
795 res
= AppendPropCarefully(dpy
, win
, commProperty
, property
, length
+ 1);
806 Window
*w
= (Window
*) p
;
807 return ServerReplyFind(*w
, SROP_Find
) != NULL
;
811 * Wait for replies from id (win)
812 * Return 0 and the malloc'ed string when a reply is available.
813 * Return -1 if the window becomes invalid while waiting.
816 serverReadReply(dpy
, win
, str
, localLoop
)
824 struct ServerReply
*p
;
826 ServerWait(dpy
, win
, WaitForReply
, &win
, localLoop
, -1);
828 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
830 *str
= vim_strsave(p
->strings
.ga_data
);
831 len
= STRLEN(*str
) + 1;
832 if (len
< p
->strings
.ga_len
)
834 s
= (char_u
*) p
->strings
.ga_data
;
835 mch_memmove(s
, s
+ len
, p
->strings
.ga_len
- len
);
836 p
->strings
.ga_len
-= len
;
840 /* Last string read. Remove from list */
841 ga_clear(&p
->strings
);
842 ServerReplyFind(win
, SROP_Delete
);
850 * Check for replies from id (win).
851 * Return TRUE and a non-malloc'ed string if there is. Else return FALSE.
854 serverPeekReply(dpy
, win
, str
)
859 struct ServerReply
*p
;
861 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
864 *str
= p
->strings
.ga_data
;
867 if (!WindowValid(dpy
, win
))
874 * Initialize the communication channels for sending commands and receiving
881 XErrorHandler old_handler
;
884 * Create the window used for communication, and set up an
885 * event handler for it.
887 old_handler
= XSetErrorHandler(x_error_check
);
890 if (commProperty
== None
)
891 commProperty
= XInternAtom(dpy
, "Comm", False
);
892 if (vimProperty
== None
)
893 vimProperty
= XInternAtom(dpy
, "Vim", False
);
894 if (registryProperty
== None
)
895 registryProperty
= XInternAtom(dpy
, "VimRegistry", False
);
897 if (commWindow
== None
)
899 commWindow
= XCreateSimpleWindow(dpy
, XDefaultRootWindow(dpy
),
900 getpid(), 0, 10, 10, 0,
901 WhitePixel(dpy
, DefaultScreen(dpy
)),
902 WhitePixel(dpy
, DefaultScreen(dpy
)));
903 XSelectInput(dpy
, commWindow
, PropertyChangeMask
);
904 /* WARNING: Do not step through this while debugging, it will hangup
907 DeleteAnyLingerer(dpy
, commWindow
);
911 /* Make window recognizable as a vim window */
912 XChangeProperty(dpy
, commWindow
, vimProperty
, XA_STRING
,
913 8, PropModeReplace
, (char_u
*)VIM_VERSION_SHORT
,
914 (int)STRLEN(VIM_VERSION_SHORT
) + 1);
917 (void)XSetErrorHandler(old_handler
);
919 return got_x_error
? -1 : 0;
923 * Given a server name, see if the name exists in the registry for a
924 * particular display.
926 * If the given name is registered, return the ID of the window associated
927 * with the name. If the name isn't registered, then return 0.
930 * If the registry property is improperly formed, then it is deleted.
931 * If "delete" is non-zero, then if the named server is found it is
932 * removed from the registry property.
935 LookupName(dpy
, name
, delete, loose
)
936 Display
*dpy
; /* Display whose registry to check. */
937 char_u
*name
; /* Name of a server. */
938 int delete; /* If non-zero, delete info about name. */
939 char_u
**loose
; /* Do another search matching -999 if not found
940 Return result here if a match is found */
942 char_u
*regProp
, *entry
;
948 * Read the registry property.
950 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
954 * Scan the property for the desired name.
956 returnValue
= (int_u
)None
;
957 entry
= NULL
; /* Not needed, but eliminates compiler warning. */
958 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
961 while (*p
!= 0 && !isspace(*p
))
963 if (*p
!= 0 && STRICMP(name
, p
+ 1) == 0)
965 sscanf((char *)entry
, "%x", &returnValue
);
973 if (loose
!= NULL
&& returnValue
== (int_u
)None
&& !IsSerialName(name
))
975 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
978 while (*p
!= 0 && !isspace(*p
))
980 if (*p
!= 0 && IsSerialName(p
+ 1)
981 && STRNICMP(name
, p
+ 1, STRLEN(name
)) == 0)
983 sscanf((char *)entry
, "%x", &returnValue
);
984 *loose
= vim_strsave(p
+ 1);
994 * Delete the property, if that is desired (copy down the
995 * remainder of the registry property to overlay the deleted
996 * info, then rewrite the property).
998 if (delete && returnValue
!= (int_u
)None
)
1005 count
= numItems
- (p
- regProp
);
1007 mch_memmove(entry
, p
, count
);
1008 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
,
1009 8, PropModeReplace
, regProp
,
1010 (int)(numItems
- (p
- entry
)));
1014 if (regProp
!= empty_prop
)
1016 return (Window
)returnValue
;
1020 * Delete any lingering occurrence of window id. We promise that any
1021 * occurrence is not ours since it is not yet put into the registry (by us)
1023 * This is necessary in the following scenario:
1024 * 1. There is an old windowid for an exit'ed vim in the registry
1025 * 2. We get that id for our commWindow but only want to send, not register.
1026 * 3. The window will mistakenly be regarded valid because of own commWindow
1029 DeleteAnyLingerer(dpy
, win
)
1030 Display
*dpy
; /* Display whose registry to check. */
1031 Window win
; /* Window to remove */
1033 char_u
*regProp
, *entry
= NULL
;
1039 * Read the registry property.
1041 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
1044 /* Scan the property for the window id. */
1045 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
1049 sscanf((char *)p
, "%x", &wwin
);
1050 if ((Window
)wwin
== win
)
1054 /* Copy down the remainder to delete entry */
1059 lastHalf
= numItems
- (p
- regProp
);
1061 mch_memmove(entry
, p
, lastHalf
);
1062 numItems
= (entry
- regProp
) + lastHalf
;
1074 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
,
1075 XA_STRING
, 8, PropModeReplace
, regProp
,
1076 (int)(p
- regProp
));
1080 if (regProp
!= empty_prop
)
1085 * Read the registry property. Delete it when it's formatted wrong.
1086 * Return the property in "regPropp". "empty_prop" is used when it doesn't
1088 * Return OK when successful.
1091 GetRegProp(dpy
, regPropp
, numItemsp
, domsg
)
1095 int domsg
; /* When TRUE give error message. */
1097 int result
, actualFormat
;
1100 XErrorHandler old_handler
;
1103 old_handler
= XSetErrorHandler(x_error_check
);
1104 got_x_error
= FALSE
;
1106 result
= XGetWindowProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, 0L,
1107 (long)MAX_PROP_WORDS
, False
,
1108 XA_STRING
, &actualType
,
1109 &actualFormat
, numItemsp
, &bytesAfter
,
1113 (void)XSetErrorHandler(old_handler
);
1117 if (actualType
== None
)
1119 /* No prop yet. Logically equal to the empty list */
1121 *regPropp
= empty_prop
;
1125 /* If the property is improperly formed, then delete it. */
1126 if (result
!= Success
|| actualFormat
!= 8 || actualType
!= XA_STRING
)
1128 if (*regPropp
!= NULL
)
1130 XDeleteProperty(dpy
, RootWindow(dpy
, 0), registryProperty
);
1132 EMSG(_("E251: VIM instance registry property is badly formed. Deleted!"));
1139 * This procedure is invoked by the various X event loops throughout Vims when
1140 * a property changes on the communication window. This procedure reads the
1141 * property and handles command requests and responses.
1144 serverEventProc(dpy
, eventPtr
)
1146 XEvent
*eventPtr
; /* Information about event. */
1150 int result
, actualFormat
, code
;
1151 long_u numItems
, bytesAfter
;
1155 if (eventPtr
!= NULL
)
1157 if (eventPtr
->xproperty
.atom
!= commProperty
1158 || eventPtr
->xproperty
.state
!= PropertyNewValue
)
1163 * Read the comm property and delete it.
1166 result
= XGetWindowProperty(dpy
, commWindow
, commProperty
, 0L,
1167 (long)MAX_PROP_WORDS
, True
,
1168 XA_STRING
, &actualType
,
1169 &actualFormat
, &numItems
, &bytesAfter
,
1172 /* If the property doesn't exist or is improperly formed then ignore it. */
1173 if (result
!= Success
|| actualType
!= XA_STRING
|| actualFormat
!= 8)
1175 if (propInfo
!= NULL
)
1181 * Several commands and results could arrive in the property at
1182 * one time; each iteration through the outer loop handles a
1183 * single command or result.
1185 for (p
= propInfo
; (long_u
)(p
- propInfo
) < numItems
; )
1188 * Ignore leading NULs; each command or result starts with a
1189 * NUL so that no matter how badly formed a preceding command
1190 * is, we'll be able to tell that a new command/result is
1199 if ((*p
== 'c' || *p
== 'k') && (p
[1] == 0))
1202 char_u
*name
, *script
, *serial
, *end
, *res
;
1203 Bool asKeys
= *p
== 'k';
1208 * This is an incoming command from some other application.
1209 * Iterate over all of its options. Stop when we reach
1210 * the end of the property or something that doesn't look
1216 serial
= (char_u
*)"";
1219 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1224 end
= skipwhite(p
+ 2);
1226 while (vim_isxdigit(*end
))
1228 resWindow
= 16 * resWindow
+ (long_u
)hex2nr(*end
);
1231 if (end
== p
+ 2 || *end
!= ' ')
1235 p
= serial
= end
+ 1;
1236 clientWindow
= resWindow
; /* Remember in global */
1257 if (script
== NULL
|| name
== NULL
)
1261 * Initialize the result property, so that we're ready at any
1262 * time if we need to return an error.
1264 if (resWindow
!= None
)
1266 ga_init2(&reply
, 1, 100);
1268 ga_grow(&reply
, 50 + STRLEN(p_enc
));
1269 sprintf(reply
.ga_data
, "%cr%c-E %s%c-s %s%c-r ",
1270 0, 0, p_enc
, 0, serial
, 0);
1271 reply
.ga_len
= 14 + STRLEN(p_enc
) + STRLEN(serial
);
1273 ga_grow(&reply
, 50);
1274 sprintf(reply
.ga_data
, "%cr%c-s %s%c-r ", 0, 0, serial
, 0);
1275 reply
.ga_len
= 10 + STRLEN(serial
);
1279 if (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0)
1281 script
= serverConvert(enc
, script
, &tofree
);
1283 server_to_input_buf(script
);
1285 res
= eval_client_expr_to_string(script
);
1288 if (resWindow
!= None
)
1291 ga_concat(&reply
, res
);
1292 else if (asKeys
== 0)
1294 ga_concat(&reply
, (char_u
*)_(e_invexprmsg
));
1295 ga_append(&reply
, 0);
1296 ga_concat(&reply
, (char_u
*)"-c 1");
1298 ga_append(&reply
, NUL
);
1299 (void)AppendPropCarefully(dpy
, resWindow
, commProperty
,
1300 reply
.ga_data
, reply
.ga_len
);
1305 else if (*p
== 'r' && p
[1] == 0)
1307 int serial
, gotSerial
;
1309 PendingCommand
*pcPtr
;
1313 * This is a reply to some command that we sent out. Iterate
1314 * over all of its options. Stop when we reach the end of the
1315 * property or something that doesn't look like an option.
1322 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1335 if (sscanf((char *)p
+ 2, " %d", &serial
) == 1)
1339 if (sscanf((char *)p
+ 2, " %d", &code
) != 1)
1352 * Give the result information to anyone who's
1355 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
1357 if (serial
!= pcPtr
->serial
|| pcPtr
->result
!= NULL
)
1363 res
= serverConvert(enc
, res
, &tofree
);
1365 res
= vim_strsave(res
);
1366 pcPtr
->result
= res
;
1369 pcPtr
->result
= vim_strsave((char_u
*)"");
1373 else if (*p
== 'n' && p
[1] == 0)
1379 struct ServerReply
*r
;
1383 * This is a (n)otification. Sent with serverreply_send in VimL.
1384 * Execute any autocommand and save it for later retrieval
1390 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1403 if (sscanf((char *)p
+ 2, " %x", &u
) == 1)
1417 str
= serverConvert(enc
, str
, &tofree
);
1418 if ((r
= ServerReplyFind(win
, SROP_Add
)) != NULL
)
1420 ga_concat(&(r
->strings
), str
);
1421 ga_append(&(r
->strings
), NUL
);
1427 sprintf((char *)winstr
, "0x%x", (unsigned int)win
);
1428 apply_autocmds(EVENT_REMOTEREPLY
, winstr
, str
, TRUE
, curbuf
);
1436 * Didn't recognize this thing. Just skip through the next
1437 * null character and try again.
1438 * Even if we get an 'r'(eply) we will throw it away as we
1439 * never specify (and thus expect) one
1450 * Append a given property to a given window, but set up an X error handler so
1451 * that if the append fails this procedure can return an error code rather
1452 * than having Xlib panic.
1453 * Return: 0 for OK, -1 for error
1456 AppendPropCarefully(dpy
, window
, property
, value
, length
)
1457 Display
*dpy
; /* Display on which to operate. */
1458 Window window
; /* Window whose property is to be modified. */
1459 Atom property
; /* Name of property. */
1460 char_u
*value
; /* Characters to append to property. */
1461 int length
; /* How much to append */
1463 XErrorHandler old_handler
;
1465 old_handler
= XSetErrorHandler(x_error_check
);
1466 got_x_error
= FALSE
;
1467 XChangeProperty(dpy
, window
, property
, XA_STRING
, 8,
1468 PropModeAppend
, value
, length
);
1470 (void) XSetErrorHandler(old_handler
);
1471 return got_x_error
? -1 : 0;
1476 * Another X Error handler, just used to check for errors.
1479 x_error_check(dpy
, error_event
)
1480 Display
*dpy UNUSED
;
1481 XErrorEvent
*error_event UNUSED
;
1488 * Check if "str" looks like it had a serial number appended.
1489 * Actually just checks if the name ends in a digit.
1495 int len
= STRLEN(str
);
1497 return (len
> 1 && vim_isdigit(str
[len
- 1]));
1499 #endif /* FEAT_CLIENTSERVER */