| Index: chrome_frame/sync_msg_reply_dispatcher.h
|
| ===================================================================
|
| --- chrome_frame/sync_msg_reply_dispatcher.h (revision 0)
|
| +++ chrome_frame/sync_msg_reply_dispatcher.h (revision 0)
|
| @@ -0,0 +1,96 @@
|
| +// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#ifndef CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
|
| +#define CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
|
| +
|
| +#include <deque>
|
| +
|
| +#include "base/lock.h"
|
| +#include "ipc/ipc_channel_proxy.h"
|
| +
|
| +// Base class used to allow synchronous IPC messages to be sent and
|
| +// received in an asynchronous manner. To use this class add it as a filter to
|
| +// your IPC channel using ChannelProxy::AddFilter(). From then on, before
|
| +// sending a synchronous message, call SyncMessageReplyDispatcher::Push() with
|
| +// a callback and a key. This class will then handle the message response and
|
| +// will call the callback when it is received.
|
| +//
|
| +// This class is intended to be extended by classes implementing
|
| +// HandleMessageType with delegation for the messages they expect to receive in
|
| +// cases where you care about the return values of synchronous messages.
|
| +//
|
| +// Sample usage pattern:
|
| +//
|
| +// // Add handling for desired message types.
|
| +// class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher {
|
| +// virtual bool HandleMessageType(const IPC::Message& msg,
|
| +// const MessageSent& origin) {
|
| +// switch (origin.type) {
|
| +// case AutomationMsg_CreateExternalTab::ID:
|
| +// InvokeCallback<Tuple3<HWND, HWND, int> >(msg, origin);
|
| +// break;
|
| +// [HANDLING FOR OTHER EXPECTED MESSAGE TYPES]
|
| +// }
|
| +// }
|
| +//
|
| +// // Add the filter
|
| +// IPC::SyncChannel channel_;
|
| +// channel_.AddFilter(new SyncMessageReplyDispatcherImpl());
|
| +//
|
| +// sync_->Push(msg, NewCallback(this, CallbackMethod, this);
|
| +// channel_->ChannelProxy::Send(msg);
|
| +//
|
| +class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter {
|
| + public:
|
| + SyncMessageReplyDispatcher() {}
|
| + void Push(IPC::SyncMessage* msg, void* callback, void* key);
|
| + void Cancel(void* key);
|
| +
|
| + protected:
|
| + struct MessageSent {
|
| + MessageSent() {}
|
| + MessageSent(int id, uint16 type, void* callback, void* key)
|
| + : id(id), callback(callback), type(type), key(key) {}
|
| + int id;
|
| + void* callback;
|
| + void* key;
|
| + uint16 type;
|
| + };
|
| +
|
| + typedef std::deque<MessageSent> PendingSyncMessageQueue;
|
| +
|
| + bool Pop(const IPC::Message& msg, MessageSent* t);
|
| + virtual bool OnMessageReceived(const IPC::Message& msg);
|
| +
|
| + // Child classes must implement a handler for the message types they are
|
| + // interested in handling responses for. If you don't care about the replies
|
| + // to any of the sync messages you are handling, then you don't have to
|
| + // implement this.
|
| + virtual bool HandleMessageType(const IPC::Message& msg,
|
| + const MessageSent& origin);
|
| +
|
| + template <typename T>
|
| + void InvokeCallback(const IPC::Message& msg, const MessageSent& origin) {
|
| + // Ensure we delete the callback
|
| + scoped_ptr<CallbackRunner<T> > c(
|
| + reinterpret_cast<CallbackRunner<T>*>(origin.callback));
|
| + if (origin.key == NULL) { // Canceled
|
| + return;
|
| + }
|
| +
|
| + T tmp; // Acts as "initializer" for output parameters.
|
| + IPC::ParamDeserializer<T> deserializer(tmp);
|
| + if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) {
|
| + c->RunWithParams(deserializer.out_);
|
| + } else {
|
| + // TODO(stoyan): How to handle errors?
|
| + }
|
| + }
|
| +
|
| + PendingSyncMessageQueue message_queue_;
|
| + Lock message_queue_lock_;
|
| +};
|
| +
|
| +#endif // CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
|
|
|