/* * 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); }