Exemple #1
0
/*
 * This procedure is invoked by the various X event loops throughout Vims when
 * a property changes on the communication window.  This procedure reads the
 * property and handles command requests and responses.
 */
static void serverEventProc(VimRemotingClient *client, XEvent *eventPtr)
{
    unsigned char *propInfo = NULL;
    char *p;
    int  result, actualFormat, code;
    unsigned long numItems, bytesAfter;
    Atom actualType;
    char *tofree;

    if (eventPtr != NULL) {
        if (eventPtr->xproperty.atom != client->commProperty
                || eventPtr->xproperty.state != PropertyNewValue)
            return;
    }

    /*
     * Read the comm property and delete it.
     */
    result = XGetWindowProperty(
            client->dpy, client->window, client->commProperty, 0L,
            (long)MAX_PROP_WORDS, True, XA_STRING, &actualType,
            &actualFormat, &numItems, &bytesAfter, &propInfo);

    /* If the property doesn't exist or is improperly formed then ignore it. */
    if (result != Success || actualType != XA_STRING || actualFormat != 8) {
        if (propInfo)
            XFree(propInfo);
        return;
    }

    /*
     * Several commands and results could arrive in the property at
     * one time;  each iteration through the outer loop handles a
     * single command or result.
     */
    for (p = (char *)propInfo; (p - (char *)propInfo) < numItems; ) {
        /*
         * Ignore leading NULs; each command or result starts with a
         * NUL so that no matter how badly formed a preceding command
         * is, we'll be able to tell that a new command/result is
         * starting.
         */
        if (*p == 0) {
            p++;
            continue;
        }

        if (*p == 'r' && p[1] == 0) {
            int                    serial, gotSerial;
            char            *res;
            VimRemotingClient_PendingCommand  *pcPtr;
            char            *enc;

            /*
             * This is a reply to some command that we sent out.  Iterate
             * over all of its options.  Stop when we reach the end of the
             * property or something that doesn't look like an option.
             */
            p += 2;
            gotSerial = 0;
            res = (char *)"";
            code = 0;
            enc = NULL;
            while ((p - (char *)propInfo) < numItems && *p == '-') {
                switch (p[1]) {
                    case 'r':
                        if (p[2] == ' ')
                            res = p + 3;
                        break;
                    case 'E':
                        if (p[2] == ' ')
                            enc = p + 3;
                        break;
                    case 's':
                        if (sscanf((char *)p + 2, " %d", &serial) == 1)
                            gotSerial = 1;
                        break;
                    case 'c':
                        if (sscanf((char *)p + 2, " %d", &code) != 1)
                            code = 0;
                        break;
                }
                while (*p != 0)
                    p++;
                p++;
            }

            if (!gotSerial)
                continue;

            /*
             * Give the result information to anyone who's
             * waiting for it.
             */
            for (pcPtr = client->pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr) {
                if (serial != pcPtr->serial || pcPtr->result != NULL)
                    continue;

                pcPtr->code = code;
                if (res != NULL) {
                    res = serverConvert(client, enc, res, &tofree);
                    if (tofree == NULL)
                        res = strdup(res);
                    pcPtr->result = res;
                }
                else
                    pcPtr->result = strdup((char *)"");
                break;
            }
        } else if (*p == 'n' && p[1] == 0) {
            Window        win = 0;
            unsigned int u;
            int gotWindow;
            char *str;
            VimRemotingClient_ServerReply *r;
            char        *enc;

            /*
             * This is a (n)otification.  Sent with serverreply_send in VimL.
             * Execute any autocommand and save it for later retrieval
             */
            p += 2;
            gotWindow = 0;
            str = (char *)"";
            enc = NULL;
            while ((p - (char *)propInfo) < numItems && *p == '-') {
                switch (p[1]) {
                    case 'n':
                        if (p[2] == ' ')
                            str = p + 3;
                        break;
                    case 'E':
                        if (p[2] == ' ')
                            enc = p + 3;
                        break;
                    case 'w':
                        if (sscanf((char *)p + 2, " %x", &u) == 1) {
                            win = u;
                            gotWindow = 1;
                        }
                        break;
                }
                while (*p != 0)
                    p++;
                p++;
            }

            if (!gotWindow)
                continue;
            str = serverConvert(client, enc, str, &tofree);
            if ((r = findReply(client, win, SROP_Add)) != NULL) {
                ga_concat(&(r->strings), str);
                ga_append(&(r->strings), '\0');
            }
            free(tofree);
        } else {
            /*
             * Didn't recognize this thing.  Just skip through the next
             * null character and try again.
             * Even if we get an 'r'(eply) we will throw it away as we
             * never specify (and thus expect) one
             */
            while (*p != 0)
                p++;
            p++;
        }
    }
    XFree(propInfo);
}
/*s
 * The window procedure for the hidden message window.
 * It handles callback messages and notifications from servers.
 * In order to process these messages, it is necessary to run a
 * message loop. Code which may run before the main message loop
 * is started (in the GUI) is careful to pump messages when it needs
 * to. Features which require message delivery during normal use will
 * not work in the console version - this basically means those
 * features which allow Vim to act as a server, rather than a client.
 */
    static LRESULT CALLBACK
Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    int err;

    if (msg == WM_COPYDATA)
    {
	/* This is a message from another Vim. The dwData member of the
	 * COPYDATASTRUCT determines the type of message:
	 *   COPYDATA_ENCODING:
	 *	The encoding that the client uses. Following messages will
	 *	use this encoding, convert if needed.
	 *   COPYDATA_KEYS:
	 *	A key sequence. We are a server, and a client wants these keys
	 *	adding to the input queue.
	 *   COPYDATA_REPLY:
	 *	A reply. We are a client, and a server has sent this message
	 *	in response to a request.  (server2client())
	 *   COPYDATA_EXPR:
	 *	An expression. We are a server, and a client wants us to
	 *	evaluate this expression.
	 *   COPYDATA_RESULT:
	 *	A reply. We are a client, and a server has sent this message
	 *	in response to a COPYDATA_EXPR.
	 *   COPYDATA_ERROR_RESULT:
	 *	A reply. We are a client, and a server has sent this message
	 *	in response to a COPYDATA_EXPR that failed to evaluate.
	 */
	COPYDATASTRUCT	*data = (COPYDATASTRUCT*)lParam;
	HWND		sender = (HWND)wParam;
	COPYDATASTRUCT	reply;
	char_u		*res;
	int		retval;
	char_u		*str;
	char_u		*tofree;

	switch (data->dwData)
	{
	case COPYDATA_ENCODING:
	    /* Remember the encoding that the client uses. */
	    vim_free(client_enc);
            // TODO:
	    //client_enc = enc_canonize((char_u *)data->lpData);
	    client_enc = vim_strsave(data->lpData);
	    return 1;

	case COPYDATA_KEYS:
            /* not supported */
	    return 1;

	case COPYDATA_EXPR:
	    str = serverConvert(client_enc, (char_u *)data->lpData, &tofree);

            if (usereval == NULL)
            {
                err = -1;
                res = NULL;
            }
            else
            {
                res = NULL;
                err = usereval((char *)str, (char **)&res);
            }

	    vim_free(tofree);

            if (!err)
		reply.dwData = COPYDATA_RESULT;
            else
		reply.dwData = COPYDATA_ERROR_RESULT;
	    reply.lpData = (res == NULL) ? (char_u *)"" : res;
	    reply.cbData = (res == NULL) ? 1 : (DWORD)STRLEN(res) + 1;

	    serverSendEnc(sender);
	    retval = (int)SendMessage(sender, WM_COPYDATA, (WPARAM)message_window,
							    (LPARAM)(&reply));
	    vim_free(res);
	    return retval;

	case COPYDATA_REPLY:
	case COPYDATA_RESULT:
	case COPYDATA_ERROR_RESULT:
	    if (data->lpData != NULL)
	    {
		str = serverConvert(client_enc, (char_u *)data->lpData,
								     &tofree);
		if (tofree == NULL)
		    str = vim_strsave(str);
		if (save_reply(sender, str,
			   (data->dwData == COPYDATA_REPLY ?  0 :
			   (data->dwData == COPYDATA_RESULT ? 1 :
							      2))) == FAIL)
		    vim_free(str);
	    }
	    return 1;
	}

	return 0;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}