"Fossies" - the Fresh Open Source Software Archive

Member "google-gadgets-for-linux-0.11.2/ggadget/view.cc" (8 Jan 2010, 79054 Bytes) of package /linux/misc/old/google-gadgets-for-linux-0.11.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2   Copyright 2008 Google Inc.
    3 
    4   Licensed under the Apache License, Version 2.0 (the "License");
    5   you may not use this file except in compliance with the License.
    6   You may obtain a copy of the License at
    7 
    8        http://www.apache.org/licenses/LICENSE-2.0
    9 
   10   Unless required by applicable law or agreed to in writing, software
   11   distributed under the License is distributed on an "AS IS" BASIS,
   12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13   See the License for the specific language governing permissions and
   14   limitations under the License.
   15 */
   16 
   17 // Enable it to print verbose debug info
   18 // #define VIEW_VERBOSE_DEBUG
   19 // #define EVENT_VERBOSE_DEBUG
   20 
   21 #include <sys/time.h>
   22 #include <time.h>
   23 #include <list>
   24 #include <set>
   25 #include <vector>
   26 #include <cstdlib>
   27 #include <algorithm>
   28 
   29 #include "view.h"
   30 #include "basic_element.h"
   31 #include "clip_region.h"
   32 #include "contentarea_element.h"
   33 #include "content_item.h"
   34 #include "details_view_data.h"
   35 #include "element_factory.h"
   36 #include "elements.h"
   37 #include "event.h"
   38 #include "file_manager_interface.h"
   39 #include "file_manager_factory.h"
   40 #include "main_loop_interface.h"
   41 #include "gadget_consts.h"
   42 #include "gadget.h"
   43 #include "graphics_interface.h"
   44 #include "image_cache.h"
   45 #include "image_interface.h"
   46 #include "logger.h"
   47 #include "math_utils.h"
   48 #include "menu_interface.h"
   49 #include "options_interface.h"
   50 #include "script_context_interface.h"
   51 #include "scriptable_binary_data.h"
   52 #include "scriptable_event.h"
   53 #include "scriptable_helper.h"
   54 #include "scriptable_image.h"
   55 #include "scriptable_interface.h"
   56 #include "scriptable_menu.h"
   57 #include "slot.h"
   58 #include "string_utils.h"
   59 #include "texture.h"
   60 #include "view_host_interface.h"
   61 #include "xml_dom_interface.h"
   62 #include "xml_http_request_interface.h"
   63 #include "xml_parser_interface.h"
   64 #include "xml_utils.h"
   65 #include "small_object.h"
   66 
   67 namespace ggadget {
   68 
   69 DECLARE_VARIANT_PTR_TYPE(CanvasInterface);
   70 
   71 static const char *kResizableNames[] = { "false", "true", "zoom" };
   72 static const Variant kConfirmDefaultArgs[] = { Variant(), Variant(false) };
   73 
   74 class View::Impl : public SmallObject<> {
   75  public:
   76   /**
   77    * Callback object for timer watches.
   78    * if duration > 0 then it's a animation timer.
   79    * else if duration == 0 then it's a timeout timer.
   80    * else if duration < 0 then it's a interval timer.
   81    */
   82   class TimerWatchCallback : public WatchCallbackInterface {
   83    public:
   84     TimerWatchCallback(Impl *impl, Slot *slot, int start, int end,
   85                        int duration, uint64_t start_time,
   86                        bool is_event)
   87       : start_time_(start_time),
   88         last_finished_time_(0),
   89         impl_(impl),
   90         slot_(slot),
   91         destroy_connection_(NULL),
   92         event_(0, 0),
   93         scriptable_event_(&event_, NULL, NULL),
   94         start_(start),
   95         end_(end),
   96         duration_(duration),
   97         last_value_(start),
   98         is_event_(is_event) {
   99       destroy_connection_ = impl_->on_destroy_signal_.Connect(
  100           NewSlot(this, &TimerWatchCallback::OnDestroy));
  101     }
  102 
  103     ~TimerWatchCallback() {
  104       destroy_connection_->Disconnect();
  105       delete slot_;
  106     }
  107 
  108     void SetWatchId(int watch_id) {
  109       event_.SetToken(watch_id);
  110     }
  111 
  112     virtual bool Call(MainLoopInterface *main_loop, int watch_id) {
  113       GGL_UNUSED(watch_id);
  114       ASSERT(event_.GetToken() == watch_id);
  115       ScopedLogContext log_context(impl_->gadget_);
  116 
  117       bool fire = true;
  118       bool ret = true;
  119       int value = end_; // In case of duration <= 0.
  120       uint64_t current_time = main_loop->GetCurrentTime();
  121 
  122       // Animation timer
  123       if (duration_ > 0) {
  124         double progress =
  125             static_cast<double>(current_time - start_time_) / duration_;
  126         progress = std::min(1.0, std::max(0.0, progress));
  127         value = start_ + static_cast<int>(round(progress * (end_ - start_)));
  128         fire = (value != last_value_);
  129         ret = (progress < 1.0);
  130         last_value_ = value;
  131       } else if (duration_ == 0) {
  132         ret = false;
  133       }
  134 
  135       // If ret is false then fire, to make sure that the last event will
  136       // always be fired.
  137       if (fire && (!ret || current_time - last_finished_time_ >
  138                    kMinTimeBetweenTimerCall)) {
  139         if (is_event_) {
  140           // Because timer events are still fired during modal dialog opened
  141           // in key/mouse event handlers, switch off the user interaction
  142           // flag when the timer event is handled, to prevent unexpected
  143           // openUrl() etc.
  144           bool old_interaction = impl_->gadget_ ?
  145               impl_->gadget_->SetInUserInteraction(false) : false;
  146           event_.SetValue(value);
  147           impl_->FireEventSlot(&scriptable_event_, slot_);
  148           if (impl_->gadget_)
  149             impl_->gadget_->SetInUserInteraction(old_interaction);
  150         } else {
  151           slot_->Call(NULL, 0, NULL);
  152         }
  153       }
  154 
  155       last_finished_time_ = main_loop->GetCurrentTime();
  156       return ret;
  157     }
  158 
  159     virtual void OnRemove(MainLoopInterface *main_loop, int watch_id) {
  160       GGL_UNUSED(main_loop);
  161       GGL_UNUSED(watch_id);
  162       ASSERT(event_.GetToken() == watch_id);
  163       delete this;
  164     }
  165 
  166     void OnDestroy() {
  167       impl_->RemoveTimer(event_.GetToken());
  168     }
  169 
  170    private:
  171     uint64_t start_time_;
  172     uint64_t last_finished_time_;
  173     Impl *impl_;
  174     Slot *slot_;
  175     Connection *destroy_connection_;
  176     TimerEvent event_;
  177     ScriptableEvent scriptable_event_;
  178     int start_;
  179     int end_;
  180     int duration_;
  181     int last_value_;
  182     bool is_event_;
  183   };
  184 
  185   Impl(View *owner,
  186        ViewHostInterface *view_host,
  187        Gadget *gadget,
  188        ElementFactory *element_factory,
  189        ScriptContextInterface *script_context)
  190     :
  191       width_(0),
  192       height_(0),
  193       default_width_(320),
  194       default_height_(240),
  195       resize_border_left_(0),
  196       resize_border_top_(0),
  197       resize_border_right_(0),
  198       resize_border_bottom_(0),
  199       owner_(owner),
  200       gadget_(gadget),
  201       element_factory_(element_factory),
  202       main_loop_(GetGlobalMainLoop()),
  203       view_host_(view_host),
  204       script_context_(script_context),
  205       onoptionchanged_connection_(NULL),
  206       canvas_cache_(NULL),
  207       graphics_(NULL),
  208       scriptable_view_(NULL),
  209       clip_region_(0.9),
  210       children_(element_factory, NULL, owner),
  211 #ifdef _DEBUG
  212       draw_count_(0),
  213       view_draw_count_(0),
  214       accum_draw_time_(0),
  215 #endif
  216       hittest_(HT_CLIENT),
  217       last_hittest_(HT_CLIENT),
  218       last_cursor_type_(CURSOR_DEFAULT),
  219       resizable_(RESIZABLE_ZOOM),
  220       dragover_result_(EVENT_RESULT_UNHANDLED),
  221       clip_region_enabled_(true),
  222       enable_cache_(true),
  223       show_caption_always_(false),
  224       draw_queued_(false),
  225       events_enabled_(true),
  226       need_redraw_(true),
  227       theme_changed_(false),
  228       resize_border_specified_(false),
  229       mouse_over_(false),
  230       view_focused_(false),
  231       safe_to_destroy_(true),
  232       content_changed_(true) {
  233     ASSERT(main_loop_);
  234 
  235     if (gadget_) {
  236       onoptionchanged_connection_ =
  237           gadget_->GetOptions()->ConnectOnOptionChanged(
  238               NewSlot(this, &Impl::OnOptionChanged));
  239     }
  240   }
  241 
  242   ~Impl() {
  243     ASSERT(event_stack_.empty());
  244 
  245     on_destroy_signal_.Emit(0, NULL);
  246 
  247     if (onoptionchanged_connection_) {
  248       onoptionchanged_connection_->Disconnect();
  249       onoptionchanged_connection_ = NULL;
  250     }
  251 
  252     if (canvas_cache_) {
  253       canvas_cache_->Destroy();
  254       canvas_cache_ = NULL;
  255     }
  256 
  257     if (view_host_) {
  258       view_host_->SetView(NULL);
  259       view_host_->Destroy();
  260       view_host_ = NULL;
  261     }
  262   }
  263 
  264   void RegisterProperties(RegisterableInterface *obj) {
  265     obj->RegisterProperty("caption",
  266                           NewSlot(owner_, &View::GetCaption),
  267                           NewSlot(owner_, &View::SetCaption));
  268     // Note: "event" property will be overrided in ScriptableView,
  269     // because ScriptableView will set itself to ScriptableEvent as SrcElement.
  270     obj->RegisterProperty("event", NewSlot(this, &Impl::GetEvent), NULL);
  271     obj->RegisterProperty("width",
  272                           NewSlot(owner_, &View::GetWidth),
  273                           NewSlot(owner_, &View::SetWidth));
  274     obj->RegisterProperty("height",
  275                           NewSlot(owner_, &View::GetHeight),
  276                           NewSlot(owner_, &View::SetHeight));
  277     obj->RegisterStringEnumProperty("resizable",
  278                           NewSlot(owner_, &View::GetResizable),
  279                           NewSlot(owner_, &View::SetResizable),
  280                           kResizableNames,
  281                           arraysize(kResizableNames));
  282     obj->RegisterProperty("showCaptionAlways",
  283                           NewSlot(owner_, &View::GetShowCaptionAlways),
  284                           NewSlot(owner_, &View::SetShowCaptionAlways));
  285 
  286     obj->RegisterVariantConstant("children", Variant(&children_));
  287     obj->RegisterMethod("appendElement",
  288                         NewSlot(&children_, &Elements::AppendElementVariant));
  289     // insertElement was deprecated by insertElementBehind.
  290     obj->RegisterMethod("insertElement",
  291                         NewSlot(&children_, &Elements::InsertElementVariant));
  292     obj->RegisterMethod("insertElementBehind",
  293                         NewSlot(&children_, &Elements::InsertElementVariant));
  294     // Added in 5.8 API.
  295     obj->RegisterMethod("insertElementInFrontOf",
  296                         NewSlot(&children_,
  297                                 &Elements::InsertElementVariantAfter));
  298     obj->RegisterMethod("removeElement",
  299                         NewSlot(&children_, &Elements::RemoveElement));
  300     obj->RegisterMethod("removeAllElements",
  301                         NewSlot(&children_, &Elements::RemoveAllElements));
  302 
  303     // Here register ViewImpl::BeginAnimation because the Slot1<void, int> *
  304     // parameter in View::BeginAnimation can't be automatically reflected.
  305     obj->RegisterMethod("beginAnimation", NewSlot(this, &Impl::BeginAnimation));
  306     obj->RegisterMethod("cancelAnimation", NewSlot(this, &Impl::RemoveTimer));
  307     obj->RegisterMethod("setTimeout", NewSlot(this, &Impl::SetTimeout));
  308     obj->RegisterMethod("clearTimeout", NewSlot(this, &Impl::RemoveTimer));
  309     obj->RegisterMethod("setInterval", NewSlot(this, &Impl::SetInterval));
  310     obj->RegisterMethod("clearInterval", NewSlot(this, &Impl::RemoveTimer));
  311 
  312     obj->RegisterMethod("alert", NewSlot(owner_, &View::Alert));
  313     obj->RegisterMethod("confirm",
  314                         NewSlotWithDefaultArgs(NewSlot(owner_, &View::Confirm),
  315                                                kConfirmDefaultArgs));
  316     obj->RegisterMethod("prompt", NewSlot(owner_, &View::Prompt));
  317 
  318     obj->RegisterMethod("resizeBy", NewSlot(this, &Impl::ResizeBy));
  319     obj->RegisterMethod("resizeTo", NewSlot(this, &Impl::SetSize));
  320 
  321     // Added in GDWin 5.8
  322     obj->RegisterProperty("resizeBorder",
  323                           NewSlot(this, &Impl::GetResizeBorder),
  324                           NewSlot(this, &Impl::SetResizeBorder));
  325 
  326     // Extended APIs.
  327 #if 0
  328     obj->RegisterProperty("focusedElement",
  329                           NewSlot(owner_, &View::GetFocusedElement), NULL);
  330     obj->RegisterProperty("mouseOverElement",
  331                           NewSlot(owner_, &View::GetMouseOverElement), NULL);
  332 #endif
  333 
  334     obj->RegisterSignal(kOnCancelEvent, &oncancel_event_);
  335     obj->RegisterSignal(kOnClickEvent, &onclick_event_);
  336     obj->RegisterSignal(kOnCloseEvent, &onclose_event_);
  337     obj->RegisterSignal(kOnDblClickEvent, &ondblclick_event_);
  338     obj->RegisterSignal(kOnRClickEvent, &onrclick_event_);
  339     obj->RegisterSignal(kOnRDblClickEvent, &onrdblclick_event_);
  340     obj->RegisterSignal(kOnDockEvent, &ondock_event_);
  341     obj->RegisterSignal(kOnKeyDownEvent, &onkeydown_event_);
  342     obj->RegisterSignal(kOnKeyPressEvent, &onkeypress_event_);
  343     obj->RegisterSignal(kOnKeyUpEvent, &onkeyup_event_);
  344     obj->RegisterSignal(kOnMinimizeEvent, &onminimize_event_);
  345     obj->RegisterSignal(kOnMouseDownEvent, &onmousedown_event_);
  346     obj->RegisterSignal(kOnMouseMoveEvent, &onmousemove_event_);
  347     obj->RegisterSignal(kOnMouseOutEvent, &onmouseout_event_);
  348     obj->RegisterSignal(kOnMouseOverEvent, &onmouseover_event_);
  349     obj->RegisterSignal(kOnMouseUpEvent, &onmouseup_event_);
  350     obj->RegisterSignal(kOnMouseWheelEvent, &onmousewheel_event_);
  351     obj->RegisterSignal(kOnOkEvent, &onok_event_);
  352     obj->RegisterSignal(kOnOpenEvent, &onopen_event_);
  353     obj->RegisterSignal(kOnOptionChangedEvent, &onoptionchanged_event_);
  354     obj->RegisterSignal(kOnPopInEvent, &onpopin_event_);
  355     obj->RegisterSignal(kOnPopOutEvent, &onpopout_event_);
  356     obj->RegisterSignal(kOnRestoreEvent, &onrestore_event_);
  357     obj->RegisterSignal(kOnSizeEvent, &onsize_event_);
  358     obj->RegisterSignal(kOnSizingEvent, &onsizing_event_);
  359     obj->RegisterSignal(kOnUndockEvent, &onundock_event_);
  360     // Not a standard signal.
  361     obj->RegisterSignal(kOnContextMenuEvent, &oncontextmenu_event_);
  362     // 5.8 API.
  363     obj->RegisterSignal(kOnThemeChangedEvent, &onthemechanged_event_);
  364   }
  365 
  366   void MapChildPositionEvent(const PositionEvent &org_event,
  367                              BasicElement *child,
  368                              PositionEvent *new_event) {
  369     ASSERT(child);
  370     double x, y;
  371     child->ViewCoordToSelfCoord(org_event.GetX(), org_event.GetY(), &x, &y);
  372     new_event->SetX(x);
  373     new_event->SetY(y);
  374   }
  375 
  376   void MapChildMouseEvent(const MouseEvent &org_event,
  377                           BasicElement *child,
  378                           MouseEvent *new_event) {
  379     MapChildPositionEvent(org_event, child, new_event);
  380     BasicElement::FlipMode flip = child->GetFlip();
  381     if (flip & BasicElement::FLIP_HORIZONTAL)
  382       new_event->SetWheelDeltaX(-org_event.GetWheelDeltaX());
  383     if (flip & BasicElement::FLIP_VERTICAL)
  384       new_event->SetWheelDeltaY(-org_event.GetWheelDeltaY());
  385   }
  386 
  387   EventResult SendMouseEventToChildren(const MouseEvent &event) {
  388     Event::Type type = event.GetType();
  389     if (type == Event::EVENT_MOUSE_OVER) {
  390       // View's EVENT_MOUSE_OVER only applicable to itself.
  391       // Children's EVENT_MOUSE_OVER is triggered by other mouse events.
  392       return EVENT_RESULT_UNHANDLED;
  393     }
  394 
  395     BasicElement *temp, *temp1; // Used to receive unused output parameters.
  396     EventResult result = EVENT_RESULT_UNHANDLED;
  397     HitTest temp_hittest;
  398     // If some element is grabbing mouse, send all EVENT_MOUSE_MOVE,
  399     // EVENT_MOUSE_UP and EVENT_MOUSE_CLICK events to it directly, until
  400     // an EVENT_MOUSE_CLICK received, or any mouse event received without
  401     // left button down.
  402     // FIXME: Is it necessary to update hittest_ when mouse is grabbing?
  403     if (grabmouse_element_.Get()) {
  404       // We used to check IsReallyEnabled() here, which seems too strict
  405       // because the grabmouse_element_ may move out of the visible area, but
  406       // it should still grab the mouse.
  407       // EVENT_MOUSE_UP should always be fired no matter if the element is
  408       // enabled or not.
  409       if ((grabmouse_element_.Get()->IsEnabled() ||
  410            type == Event::EVENT_MOUSE_UP) &&
  411           (event.GetButton() & MouseEvent::BUTTON_LEFT) &&
  412           (type == Event::EVENT_MOUSE_MOVE || type == Event::EVENT_MOUSE_UP ||
  413            type == Event::EVENT_MOUSE_CLICK)) {
  414         MouseEvent new_event(event);
  415         MapChildMouseEvent(event, grabmouse_element_.Get(), &new_event);
  416         result = grabmouse_element_.Get()->OnMouseEvent(
  417             new_event, true, &temp, &temp1, &temp_hittest);
  418         // Set correct mouse cursor.
  419         if (grabmouse_element_.Get()) {
  420           owner_->SetCursor(grabmouse_element_.Get()->GetCursor());
  421         }
  422         // Release the grabbing on EVENT_MOUSE_CLICK not EVENT_MOUSE_UP,
  423         // otherwise the click event may be sent to wrong element.
  424         if (type == Event::EVENT_MOUSE_CLICK) {
  425           grabmouse_element_.Reset(NULL);
  426         }
  427         return result;
  428       } else {
  429         // Release the grabbing on any mouse event without left button down.
  430         grabmouse_element_.Reset(NULL);
  431       }
  432     }
  433 
  434     if (type == Event::EVENT_MOUSE_OUT) {
  435       // The mouse has been moved out of the view, clear the mouseover state.
  436       if (mouseover_element_.Get()) {
  437         MouseEvent new_event(event);
  438         MapChildMouseEvent(event, mouseover_element_.Get(), &new_event);
  439         result = mouseover_element_.Get()->OnMouseEvent(
  440             new_event, true, &temp, &temp1, &temp_hittest);
  441         mouseover_element_.Reset(NULL);
  442       }
  443       return result;
  444     }
  445 
  446     BasicElement *fired_element = NULL;
  447     BasicElement *in_element = NULL;
  448     HitTest child_hittest = HT_CLIENT;
  449 
  450     // Dispatch the event to children normally,
  451     // unless popup is active and event is inside popup element.
  452     bool outside_popup = true;
  453     if (popup_element_.Get()) {
  454       if (popup_element_.Get()->IsReallyVisible()) {
  455         MouseEvent new_event(event);
  456         MapChildMouseEvent(event, popup_element_.Get(), &new_event);
  457         if (popup_element_.Get()->IsPointIn(new_event.GetX(),
  458                                             new_event.GetY())) {
  459           // Not direct.
  460           result = popup_element_.Get()->OnMouseEvent(
  461               new_event, false, &fired_element, &in_element, &child_hittest);
  462           outside_popup = false;
  463         }
  464       } else {
  465         SetPopupElement(NULL);
  466       }
  467     }
  468     if (outside_popup) {
  469       result = children_.OnMouseEvent(event, &fired_element,
  470                                       &in_element, &child_hittest);
  471       // The following might hit if a grabbed element is
  472       // turned invisible or disabled while under grab.
  473       if (type == Event::EVENT_MOUSE_DOWN && result != EVENT_RESULT_CANCELED) {
  474         SetPopupElement(NULL);
  475       }
  476     }
  477 
  478     // If the mouse pointer moves out of the view after calling children's
  479     // mouse event handler, then just return the result without handling the
  480     // mouse over/out things.
  481     if (!mouse_over_)
  482       return result;
  483 
  484     ElementHolder in_element_holder(in_element);
  485 
  486     if (fired_element && type == Event::EVENT_MOUSE_DOWN &&
  487         (event.GetButton() & MouseEvent::BUTTON_LEFT)) {
  488       // Start grabbing.
  489       grabmouse_element_.Reset(fired_element);
  490       // Focus is handled in BasicElement.
  491     }
  492 
  493     if (fired_element != mouseover_element_.Get()) {
  494       BasicElement *old_mouseover_element = mouseover_element_.Get();
  495       // Store it early to prevent crash if fired_element is removed in
  496       // the mouseout handler.
  497       mouseover_element_.Reset(fired_element);
  498 
  499       if (old_mouseover_element) {
  500         MouseEvent mouseout_event(Event::EVENT_MOUSE_OUT,
  501                                   event.GetX(), event.GetY(),
  502                                   event.GetWheelDeltaX(),
  503                                   event.GetWheelDeltaY(),
  504                                   event.GetButton(),
  505                                   event.GetModifier());
  506         MapChildMouseEvent(event, old_mouseover_element, &mouseout_event);
  507         old_mouseover_element->OnMouseEvent(mouseout_event, true,
  508                                             &temp, &temp1, &temp_hittest);
  509       }
  510 
  511       if (mouseover_element_.Get()) {
  512         // Always fire the mouse over event even if the element's visibility
  513         // and enabled state changed during the above mouse out, to keep the
  514         // same behaviour as the Windows version.
  515         MouseEvent mouseover_event(Event::EVENT_MOUSE_OVER,
  516                                    event.GetX(), event.GetY(),
  517                                    event.GetWheelDeltaX(),
  518                                    event.GetWheelDeltaY(),
  519                                    event.GetButton(),
  520                                    event.GetModifier());
  521         MapChildMouseEvent(event, mouseover_element_.Get(), &mouseover_event);
  522         mouseover_element_.Get()->OnMouseEvent(mouseover_event, true,
  523                                                &temp, &temp1, &temp_hittest);
  524       }
  525     }
  526 
  527     if (in_element_holder.Get()) {
  528       hittest_ = child_hittest;
  529       if (type == Event::EVENT_MOUSE_MOVE &&
  530           in_element != tooltip_element_.Get()) {
  531         owner_->ShowElementTooltip(in_element);
  532       }
  533     } else {
  534       // FIXME: If HT_NOWHERE is more suitable?
  535       hittest_ = HT_TRANSPARENT;
  536       tooltip_element_.Reset(NULL);
  537     }
  538 
  539     // If in element has a special hittest value, then use its cursor instead
  540     // of mouseover element's cursor.
  541     if (hittest_ != HT_CLIENT && in_element_holder.Get()) {
  542       owner_->SetCursor(in_element_holder.Get()->GetCursor());
  543     } else if (mouseover_element_.Get()) {
  544       owner_->SetCursor(mouseover_element_.Get()->GetCursor());
  545     } else {
  546       owner_->SetCursor(CURSOR_DEFAULT);
  547     }
  548 
  549 #if defined(_DEBUG) && defined(EVENT_VERBOSE_DEBUG)
  550     if (in_element_holder.Get()) {
  551       DLOG("Mouse Event result(%p): In:%s type:%s, hitTest:%d, result: %d",
  552            owner_, in_element->GetName().c_str(), in_element->GetTagName(),
  553            hittest_, result);
  554     } else {
  555       DLOG("Mouse Event result(%p): hitTest:%d, result: %d",
  556            owner_, hittest_, result);
  557     }
  558 #endif
  559 
  560     return result;
  561   }
  562 
  563   EventResult OnMouseEvent(const MouseEvent &event) {
  564     Event::Type type = event.GetType();
  565     double opacity;
  566 
  567     // Main views don't handle the mouse event if the pixel under the mouse
  568     // pointer is fully transparent and there is no element grabbing the mouse.
  569     // Options views and details views don't have this feature because they
  570     // look opaque.
  571     if (view_host_ &&
  572         view_host_->GetType() == ViewHostInterface::VIEW_HOST_MAIN &&
  573         type != Event::EVENT_MOUSE_OUT && !grabmouse_element_.Get() &&
  574         enable_cache_ && canvas_cache_ && canvas_cache_->GetPointValue(
  575             event.GetX(), event.GetY(), NULL, &opacity) && opacity == 0) {
  576       // Send out fake mouse out event if the pixel is fully transparent and
  577       // the mouse is over the view.
  578       if (mouse_over_) {
  579         MouseEvent new_event(Event::EVENT_MOUSE_OUT,
  580                              event.GetX(), event.GetY(), 0, 0,
  581                              MouseEvent::BUTTON_NONE, MouseEvent::MOD_NONE);
  582         OnMouseEvent(new_event);
  583       }
  584       hittest_ = HT_TRANSPARENT;
  585       return EVENT_RESULT_UNHANDLED;
  586     }
  587 
  588     // If the mouse is already out of the view, don't handle the mouse out
  589     // event again.
  590     if (type == Event::EVENT_MOUSE_OUT && !mouse_over_) {
  591       return EVENT_RESULT_UNHANDLED;
  592     }
  593 
  594     // If the mouse is already over the view, don't handle the mouse over
  595     // event again.
  596     if (type == Event::EVENT_MOUSE_OVER && mouse_over_) {
  597       return EVENT_RESULT_UNHANDLED;
  598     }
  599 
  600     // Send fake mouse over event if the pixel is not fully transparent and the
  601     // mouse over state is not set yet.
  602     if (type != Event::EVENT_MOUSE_OVER && type != Event::EVENT_MOUSE_OUT &&
  603         !mouse_over_) {
  604       MouseEvent new_event(Event::EVENT_MOUSE_OVER,
  605                            event.GetX(), event.GetY(), 0, 0,
  606                            MouseEvent::BUTTON_NONE, MouseEvent::MOD_NONE);
  607       OnMouseEvent(new_event);
  608     }
  609 
  610     // Send event to view first.
  611     ScriptableEvent scriptable_event(&event, NULL, NULL);
  612 
  613     bool old_interactive = false;
  614     if (gadget_ && type != Event::EVENT_MOUSE_MOVE &&
  615         type != Event::EVENT_MOUSE_OVER && type != Event::EVENT_MOUSE_OUT)
  616       old_interactive = gadget_->SetInUserInteraction(true);
  617 
  618 #if defined(_DEBUG) && defined(EVENT_VERBOSE_DEBUG)
  619     if (type != Event::EVENT_MOUSE_MOVE)
  620       DLOG("%s(View): x:%g y:%g dx:%d dy:%d b:%d m:%d",
  621            scriptable_event.GetName(), event.GetX(), event.GetY(),
  622            event.GetWheelDeltaX(), event.GetWheelDeltaY(),
  623            event.GetButton(), event.GetModifier());
  624 #endif
  625     switch (type) {
  626       case Event::EVENT_MOUSE_MOVE:
  627         // Put the high volume events near top.
  628         FireEvent(&scriptable_event, onmousemove_event_);
  629         break;
  630       case Event::EVENT_MOUSE_DOWN:
  631         FireEvent(&scriptable_event, onmousedown_event_);
  632         break;
  633       case Event::EVENT_MOUSE_UP:
  634         FireEvent(&scriptable_event, onmouseup_event_);
  635         break;
  636       case Event::EVENT_MOUSE_CLICK:
  637         FireEvent(&scriptable_event, onclick_event_);
  638         break;
  639       case Event::EVENT_MOUSE_DBLCLICK:
  640         FireEvent(&scriptable_event, ondblclick_event_);
  641         break;
  642       case Event::EVENT_MOUSE_RCLICK:
  643         FireEvent(&scriptable_event, onrclick_event_);
  644         break;
  645       case Event::EVENT_MOUSE_RDBLCLICK:
  646         FireEvent(&scriptable_event, onrdblclick_event_);
  647         break;
  648       case Event::EVENT_MOUSE_OUT:
  649         mouse_over_ = false;
  650         FireEvent(&scriptable_event, onmouseout_event_);
  651         break;
  652       case Event::EVENT_MOUSE_OVER:
  653         mouse_over_ = true;
  654         FireEvent(&scriptable_event, onmouseover_event_);
  655         break;
  656       case Event::EVENT_MOUSE_WHEEL:
  657         // 5.8 API added onmousewheel for view.
  658         FireEvent(&scriptable_event, onmousewheel_event_);
  659         break;
  660       default:
  661         ASSERT(false);
  662     }
  663 
  664     EventResult result = scriptable_event.GetReturnValue();
  665     if (result != EVENT_RESULT_CANCELED) {
  666       if (type == Event::EVENT_MOUSE_OVER) {
  667         // Translate the mouse over event to a mouse move event, to make sure
  668         // that the correct mouseover element will be set.
  669         MouseEvent new_event(Event::EVENT_MOUSE_MOVE,
  670                              event.GetX(), event.GetY(), 0, 0,
  671                              MouseEvent::BUTTON_NONE, MouseEvent::MOD_NONE);
  672         result = SendMouseEventToChildren(new_event);
  673       } else {
  674         result = SendMouseEventToChildren(event);
  675       }
  676     }
  677 
  678     if (mouse_over_ && result == EVENT_RESULT_UNHANDLED &&
  679         event.GetType() == Event::EVENT_MOUSE_RCLICK &&
  680         event.GetButton() == MouseEvent::BUTTON_RIGHT) {
  681       // Handle ShowContextMenu event.
  682       if (view_host_->ShowContextMenu(MouseEvent::BUTTON_RIGHT))
  683         result = EVENT_RESULT_HANDLED;
  684     }
  685 
  686     if (gadget_)
  687       gadget_->SetInUserInteraction(old_interactive);
  688     return result;
  689   }
  690 
  691   void SetFocusToFirstElement() {
  692     if (children_.GetCount()) {
  693       BasicElement *first = children_.GetItemByIndex(0);
  694       if (!first->IsReallyEnabled() || !first->IsTabStop())
  695         first = GetNextFocusElement(first);
  696       SetFocus(first);
  697     }
  698   }
  699 
  700   void SetFocusToLastElement() {
  701     size_t count = children_.GetCount();
  702     if (count) {
  703       BasicElement *last = children_.GetItemByIndex(count - 1);
  704       if (!last->IsReallyEnabled() || !last->IsTabStop())
  705         last = GetPreviousFocusElement(last);
  706       SetFocus(last);
  707     }
  708   }
  709 
  710   void MoveFocusForward() {
  711     BasicElement *current = focused_element_.Get();
  712     if (current) {
  713       // Try children first.
  714       BasicElement *next = GetFirstFocusInSubTrees(current);
  715       if (!next)
  716         next = GetNextFocusElement(current);
  717       if (next && next != current)
  718         SetFocus(next);
  719       // Otherwise leave the focus unchanged.
  720     } else {
  721       SetFocusToFirstElement();
  722     }
  723   }
  724 
  725   void MoveFocusBackward() {
  726     BasicElement *current = focused_element_.Get();
  727     if (current) {
  728       BasicElement *previous = GetPreviousFocusElement(current);
  729       if (previous && previous != current)
  730         SetFocus(previous);
  731       // Otherwise leave the focus unchanged.
  732     } else {
  733       SetFocusToLastElement();
  734     }
  735   }
  736 
  737   // Note: this method doesn't search in descendants.
  738   BasicElement *GetNextFocusElement(BasicElement *current) {
  739     // Try previous siblings first.
  740     BasicElement *parent = current->GetParentElement();
  741     Elements *elements = parent ? parent->GetChildren() : &children_;
  742     size_t index = current->GetIndex();
  743     if (index != kInvalidIndex) {
  744       for (size_t i = index + 1; i < elements->GetCount(); i++) {
  745         BasicElement *result = GetFirstFocusInTree(elements->GetItemByIndex(i));
  746         if (result)
  747           return result;
  748       }
  749     }
  750     // All next siblings and their children are not focusable, up to the parent.
  751     if (parent)
  752       return GetNextFocusElement(parent);
  753 
  754     // Now at the top level, wrap back to the first element.
  755     ASSERT(index != kInvalidIndex); // Otherwise it should have a parent.
  756     for (size_t i = 0; i <= index; i++) {
  757       BasicElement *result = GetFirstFocusInTree(children_.GetItemByIndex(i));
  758       if (result)
  759         return result;
  760     }
  761     return NULL;
  762   }
  763 
  764   BasicElement *GetPreviousFocusElement(BasicElement *current) {
  765     // Try previous siblings first.
  766     BasicElement *parent = current->GetParentElement();
  767     Elements *elements = parent ? parent->GetChildren() : &children_;
  768     size_t index = current->GetIndex();
  769     if (index != kInvalidIndex) {
  770       for (size_t i = index; i > 0; i--) {
  771         BasicElement *result = GetLastFocusInTree(
  772             elements->GetItemByIndex(i - 1));
  773         if (result)
  774           return result;
  775       }
  776     }
  777     // All previous siblings and their children are not focusable, up to the
  778     // parent.
  779     if (parent)
  780       return GetPreviousFocusElement(parent);
  781 
  782     // Now at the top level, wrap back to the last element.
  783     ASSERT(index != kInvalidIndex); // Otherwise it should have a parent.
  784     for (size_t i = children_.GetCount(); i > index; i--) {
  785       BasicElement *result =
  786           GetLastFocusInTree(children_.GetItemByIndex(i - 1));
  787       if (result)
  788         return result;
  789     }
  790     return NULL;
  791   }
  792 
  793   BasicElement *GetFirstFocusInTree(BasicElement *current) {
  794     return current->IsReallyEnabled() && current->IsTabStop() ?
  795            current : GetFirstFocusInSubTrees(current);
  796   }
  797 
  798   BasicElement *GetFirstFocusInSubTrees(BasicElement *current) {
  799     if (current->IsVisible()) {
  800       Elements *children = current->GetChildren();
  801       if (children) {
  802         size_t childcount = children->GetCount();
  803         for (size_t i = 0; i < childcount; i++) {
  804           BasicElement *result =
  805               GetFirstFocusInTree(children->GetItemByIndex(i));
  806           if (result)
  807             return result;
  808         }
  809       }
  810     }
  811     return NULL;
  812   }
  813 
  814   BasicElement *GetLastFocusInTree(BasicElement *current) {
  815     BasicElement *result = GetLastFocusInSubTrees(current);
  816     if (result)
  817       return result;
  818     return current->IsReallyEnabled() && current->IsTabStop() ? current : NULL;
  819   }
  820 
  821   BasicElement *GetLastFocusInSubTrees(BasicElement *current) {
  822     if (current->IsVisible()) {
  823       Elements *children = current->GetChildren();
  824       if (children) {
  825         for (size_t i = children->GetCount(); i > 0; i--) {
  826           BasicElement *result =
  827               GetLastFocusInTree(children->GetItemByIndex(i - 1));
  828           if (result)
  829             return result;
  830         }
  831       }
  832     }
  833     return NULL;
  834   }
  835 
  836   EventResult OnKeyEvent(const KeyboardEvent &event) {
  837     ScriptableEvent scriptable_event(&event, NULL, NULL);
  838 #if defined(_DEBUG) && defined(EVENT_VERBOSE_DEBUG)
  839     DLOG("%s(View): %d %d", scriptable_event.GetName(),
  840          event.GetKeyCode(), event.GetModifier());
  841 #endif
  842 
  843     bool old_interactive =
  844         gadget_ ? gadget_->SetInUserInteraction(true) : false;
  845 
  846     BasicElement *old_focused_element = focused_element_.Get();
  847 
  848     switch (event.GetType()) {
  849       case Event::EVENT_KEY_DOWN:
  850         FireEvent(&scriptable_event, onkeydown_event_);
  851         break;
  852       case Event::EVENT_KEY_UP:
  853         FireEvent(&scriptable_event, onkeyup_event_);
  854         break;
  855       case Event::EVENT_KEY_PRESS:
  856         FireEvent(&scriptable_event, onkeypress_event_);
  857         break;
  858       default:
  859         ASSERT(false);
  860     }
  861 
  862     EventResult result = scriptable_event.GetReturnValue();
  863     if (result != EVENT_RESULT_CANCELED &&
  864         focused_element_.Get()) {
  865       if (!focused_element_.Get()->IsReallyEnabled()) {
  866         focused_element_.Get()->OnOtherEvent(
  867             SimpleEvent(Event::EVENT_FOCUS_OUT));
  868         focused_element_.Reset(NULL);
  869       } else {
  870         result = focused_element_.Get()->OnKeyEvent(event);
  871         if (result != EVENT_RESULT_CANCELED) {
  872           // From API 5.8, tab keys are not sent to elements, but move focus.
  873           if (event.GetType() == Event::EVENT_KEY_DOWN &&
  874               event.GetKeyCode() == KeyboardEvent::KEY_TAB &&
  875               // Only move focus when focus was not moved by the view's and
  876               // the focused element's event handler.
  877               old_focused_element == focused_element_.Get()) {
  878             if (event.GetModifier() & Event::MOD_SHIFT)
  879               MoveFocusBackward();
  880             else
  881               MoveFocusForward();
  882             result = EVENT_RESULT_HANDLED;
  883           }
  884         }
  885       }
  886     }
  887 
  888     if (gadget_)
  889       gadget_->SetInUserInteraction(old_interactive);
  890     return result;
  891   }
  892 
  893   EventResult OnDragEvent(const DragEvent &event) {
  894     Event::Type type = event.GetType();
  895     if (type == Event::EVENT_DRAG_OUT || type == Event::EVENT_DRAG_DROP) {
  896       bool old_interactive = false;
  897       if (gadget_ && type == Event::EVENT_DRAG_DROP)
  898         old_interactive = gadget_->SetInUserInteraction(old_interactive);
  899 
  900       EventResult result = EVENT_RESULT_UNHANDLED;
  901       // Send the event and clear the dragover state.
  902       if (dragover_element_.Get()) {
  903         // If the element rejects the drop, send a EVENT_DRAG_OUT
  904         // on EVENT_DRAG_DROP.
  905         if (dragover_result_ != EVENT_RESULT_HANDLED)
  906           type = Event::EVENT_DRAG_OUT;
  907         DragEvent new_event(type, event.GetX(), event.GetY());
  908         new_event.SetDragFiles(event.GetDragFiles());
  909         new_event.SetDragUrls(event.GetDragUrls());
  910         new_event.SetDragText(event.GetDragText());
  911         MapChildPositionEvent(event, dragover_element_.Get(), &new_event);
  912         BasicElement *temp;
  913         result = dragover_element_.Get()->OnDragEvent(new_event, true, &temp);
  914         dragover_element_.Reset(NULL);
  915         dragover_result_ = EVENT_RESULT_UNHANDLED;
  916       }
  917 
  918       if (gadget_ && type == Event::EVENT_DRAG_DROP)
  919         gadget_->SetInUserInteraction(old_interactive);
  920       return result;
  921     }
  922 
  923     ASSERT(type == Event::EVENT_DRAG_MOTION);
  924     // Dispatch the event to children normally.
  925     BasicElement *fired_element = NULL;
  926     children_.OnDragEvent(event, &fired_element);
  927     if (fired_element != dragover_element_.Get()) {
  928       dragover_result_ = EVENT_RESULT_UNHANDLED;
  929       BasicElement *old_dragover_element = dragover_element_.Get();
  930       // Store it early to prevent crash if fired_element is removed in
  931       // the dragout handler.
  932       dragover_element_.Reset(fired_element);
  933 
  934       if (old_dragover_element) {
  935         DragEvent dragout_event(Event::EVENT_DRAG_OUT,
  936                                 event.GetX(), event.GetY());
  937         dragout_event.SetDragFiles(event.GetDragFiles());
  938         dragout_event.SetDragUrls(event.GetDragUrls());
  939         dragout_event.SetDragText(event.GetDragText());
  940         MapChildPositionEvent(event, old_dragover_element, &dragout_event);
  941         BasicElement *temp;
  942         old_dragover_element->OnDragEvent(dragout_event, true, &temp);
  943       }
  944 
  945       if (dragover_element_.Get()) {
  946         // The visible state may change during event handling.
  947         if (!dragover_element_.Get()->IsReallyVisible()) {
  948           dragover_element_.Reset(NULL);
  949         } else {
  950           DragEvent dragover_event(Event::EVENT_DRAG_OVER,
  951                                    event.GetX(), event.GetY());
  952           dragover_event.SetDragFiles(event.GetDragFiles());
  953           dragover_event.SetDragUrls(event.GetDragUrls());
  954           dragover_event.SetDragText(event.GetDragText());
  955           MapChildPositionEvent(event, dragover_element_.Get(),
  956                                 &dragover_event);
  957           BasicElement *temp;
  958           dragover_result_ = dragover_element_.Get()->OnDragEvent(
  959               dragover_event, true, &temp);
  960         }
  961       }
  962     }
  963 
  964     // Because gadget elements has no handler for EVENT_DRAG_MOTION, the
  965     // last return result of EVENT_DRAG_OVER should be used as the return result
  966     // of EVENT_DRAG_MOTION.
  967     return dragover_result_;
  968   }
  969 
  970   EventResult OnOtherEvent(const Event &event) {
  971     ScriptableEvent scriptable_event(&event, NULL, NULL);
  972 #if defined(_DEBUG) && defined(EVENT_VERBOSE_DEBUG)
  973     DLOG("%s(View)", scriptable_event.GetName());
  974 #endif
  975     switch (event.GetType()) {
  976       case Event::EVENT_FOCUS_IN:
  977         view_focused_ = true;
  978         // Restore focus to the original focused element if it is still there.
  979         if (focused_element_.Get() &&
  980             (!focused_element_.Get()->IsReallyEnabled() ||
  981              focused_element_.Get()->OnOtherEvent(SimpleEvent(
  982                  Event::EVENT_FOCUS_IN)) == EVENT_RESULT_CANCELED)) {
  983           focused_element_.Reset(NULL);
  984         }
  985         break;
  986       case Event::EVENT_FOCUS_OUT:
  987         view_focused_ = false;
  988         if (focused_element_.Get()) {
  989           focused_element_.Get()->OnOtherEvent(SimpleEvent(
  990               Event::EVENT_FOCUS_OUT));
  991           // Don't clear focused_element_ so that when the focus come back
  992           // to this view, we can restore the focus to the element.
  993         }
  994         break;
  995       case Event::EVENT_CANCEL:
  996         FireEvent(&scriptable_event, oncancel_event_);
  997         break;
  998       case Event::EVENT_CLOSE:
  999         FireEvent(&scriptable_event, onclose_event_);
 1000         break;
 1001       case Event::EVENT_DOCK:
 1002         FireEvent(&scriptable_event, ondock_event_);
 1003         break;
 1004       case Event::EVENT_MINIMIZE:
 1005         FireEvent(&scriptable_event, onminimize_event_);
 1006         break;
 1007       case Event::EVENT_OK:
 1008         FireEvent(&scriptable_event, onok_event_);
 1009         break;
 1010       case Event::EVENT_OPEN:
 1011         SetFocusToFirstElement();
 1012         FireEvent(&scriptable_event, onopen_event_);
 1013         break;
 1014       case Event::EVENT_POPIN:
 1015         FireEvent(&scriptable_event, onpopin_event_);
 1016         break;
 1017       case Event::EVENT_POPOUT:
 1018         FireEvent(&scriptable_event, onpopout_event_);
 1019         break;
 1020       case Event::EVENT_RESTORE:
 1021         FireEvent(&scriptable_event, onrestore_event_);
 1022         break;
 1023       case Event::EVENT_SIZE:
 1024         FireEvent(&scriptable_event, onsize_event_);
 1025         break;
 1026       case Event::EVENT_SIZING:
 1027         FireEvent(&scriptable_event, onsizing_event_);
 1028         break;
 1029       case Event::EVENT_UNDOCK:
 1030         FireEvent(&scriptable_event, onundock_event_);
 1031         break;
 1032       case Event::EVENT_THEME_CHANGED:
 1033         MarkRedraw();
 1034         owner_->QueueDraw();
 1035         theme_changed_ = true;
 1036         break;
 1037       default:
 1038         ASSERT(false);
 1039     }
 1040     return scriptable_event.GetReturnValue();
 1041   }
 1042 
 1043   void SetSize(double width, double height) {
 1044     ScopedLogContext log_context(gadget_);
 1045     if (width != width_ || height != height_) {
 1046       // Invalidate the canvas cache.
 1047       if (canvas_cache_) {
 1048         canvas_cache_->Destroy();
 1049         canvas_cache_ = NULL;
 1050       }
 1051 
 1052       // Store default width and height if the size has not been set before.
 1053       if (width_ == 0)
 1054         default_width_ = width;
 1055       if (height_ == 0)
 1056         default_height_ = height;
 1057 
 1058       width_ = width;
 1059       height_ = height;
 1060 
 1061       // In some case, QueueResize() may not cause redraw,
 1062       // so do layout here to make sure the layout is correct.
 1063       children_.Layout();
 1064 
 1065       SimpleEvent event(Event::EVENT_SIZE);
 1066       ScriptableEvent scriptable_event(&event, NULL, NULL);
 1067       FireEvent(&scriptable_event, onsize_event_);
 1068 
 1069       if (view_host_)
 1070         view_host_->QueueResize();
 1071     }
 1072   }
 1073 
 1074   void ResizeBy(double width, double height) {
 1075     SetSize(width_ + width, height_ + height);
 1076   }
 1077 
 1078   double GetWidth() {
 1079     return width_;
 1080   }
 1081 
 1082   double GetHeight() {
 1083     return height_;
 1084   }
 1085 
 1086   void SetResizeBorder(const std::string &value) {
 1087     resize_border_specified_ = false;
 1088     StringVector values;
 1089     SplitStringList(value, " ", &values);
 1090     double double_values[4];
 1091     for (size_t i = 0; i < values.size(); ++i) {
 1092       if (!Variant(values[i]).ConvertToDouble(double_values + i)) {
 1093         LOG("Invalid resize border value: %s", value.c_str());
 1094         return;
 1095       }
 1096       if (double_values[i] < 0)
 1097         double_values[i] = 0;
 1098     }
 1099 
 1100     if (values.size() == 4) {
 1101       resize_border_left_ = double_values[0];
 1102       resize_border_top_ = double_values[1];
 1103       resize_border_right_ = double_values[2];
 1104       resize_border_bottom_ = double_values[3];
 1105     } else if (values.size() == 2) {
 1106       resize_border_left_ = double_values[0];
 1107       resize_border_right_ = double_values[0];
 1108       resize_border_top_ = double_values[1];
 1109       resize_border_bottom_ = double_values[1];
 1110     } else if (values.size() == 1) {
 1111       resize_border_left_ = double_values[0];
 1112       resize_border_top_ = double_values[0];
 1113       resize_border_right_ = double_values[0];
 1114       resize_border_bottom_ = double_values[0];
 1115     } else {
 1116       LOG("Invalid resize border value: %s", value.c_str());
 1117       return;
 1118     }
 1119 
 1120     resize_border_specified_ = true;
 1121     if (view_host_)
 1122       view_host_->QueueResize();
 1123   }
 1124 
 1125   std::string GetResizeBorder() {
 1126     if (!resize_border_specified_) {
 1127       return "";
 1128     } else if (resize_border_left_ == resize_border_top_ &&
 1129                resize_border_top_ == resize_border_right_ &&
 1130                resize_border_right_ == resize_border_bottom_) {
 1131       return StringPrintf("%.0f", resize_border_left_);
 1132     } else if (resize_border_left_ == resize_border_right_ &&
 1133                resize_border_top_ == resize_border_bottom_) {
 1134       return StringPrintf("%.0f %.0f", resize_border_left_, resize_border_top_);
 1135     } else {
 1136       return StringPrintf("%.0f %.0f %.0f %.0f",
 1137                           resize_border_left_, resize_border_top_,
 1138                           resize_border_right_, resize_border_bottom_);
 1139     }
 1140   }
 1141 
 1142   void MarkRedraw() {
 1143     need_redraw_ = true;
 1144     children_.MarkRedraw();
 1145   }
 1146 
 1147   void Layout() {
 1148     // Any QueueDraw() called during Layout() will be ignored, because
 1149     // draw_queued_ is true.
 1150     draw_queued_ = true;
 1151     children_.Layout();
 1152 
 1153     // Let posted events be processed after Layout() and before actual Draw().
 1154     // This can prevent some flickers, for example, onsize of labels.
 1155     // If Event isn't enabled then postpone these events.
 1156     if (events_enabled_) {
 1157       FirePostedSizeEvents();
 1158     }
 1159 
 1160     if (theme_changed_) {
 1161       SimpleEvent event(Event::EVENT_THEME_CHANGED);
 1162       ScriptableEvent scriptable_event(&event, NULL, NULL);
 1163       FireEvent(&scriptable_event, onthemechanged_event_);
 1164       theme_changed_ = false;
 1165     }
 1166     draw_queued_ = false;
 1167 
 1168     Rectangle boundary(0, 0, width_, height_);
 1169     if (!need_redraw_) {
 1170       if (popup_element_.Get()) {
 1171         popup_element_.Get()->AggregateClipRegion(boundary, &clip_region_);
 1172       }
 1173       children_.AggregateClipRegion(boundary, &clip_region_);
 1174     } else {
 1175       // Clear clip region if the whole view needs redrawing, so that view host
 1176       // will draw the whole view correctly.
 1177       clip_region_.Clear();
 1178       clip_region_.AddRectangle(boundary);
 1179       if (popup_element_.Get()) {
 1180         popup_element_.Get()->AggregateClipRegion(Rectangle(), NULL);
 1181       }
 1182       children_.AggregateClipRegion(Rectangle(), NULL);
 1183     }
 1184 
 1185     if (!clip_region_.IsEmpty()) {
 1186       content_changed_ = true;
 1187       if (on_add_rectangle_to_clip_region_.HasActiveConnections()) {
 1188         size_t count = clip_region_.GetRectangleCount();
 1189         for (size_t i = 0; i < count; ++i) {
 1190           Rectangle r = clip_region_.GetRectangle(i);
 1191           on_add_rectangle_to_clip_region_(r.x, r.y, r.w, r.h);
 1192         }
 1193       }
 1194     }
 1195   }
 1196 
 1197   void Draw(CanvasInterface *canvas) {
 1198 #if defined(_DEBUG) && defined(VIEW_VERBOSE_DEBUG)
 1199     DLOG("host(%p) draw view(%p) on canvas %p with size: %f x %f",
 1200          view_host_, owner_, canvas, canvas->GetWidth(), canvas->GetHeight());
 1201     draw_count_ = 0;
 1202     uint64_t start = main_loop_->GetCurrentTime();
 1203 #endif
 1204 
 1205     // no draw queued, so the draw request is initiated from host.
 1206     // And because the canvas cache_ is valid, just need to paint the canvas
 1207     // cache to the dest canvas.
 1208     if (!content_changed_ && canvas_cache_ && !need_redraw_) {
 1209 #if defined(_DEBUG) && defined(VIEW_VERBOSE_DEBUG)
 1210       DLOG("Draw View(%p) from canvas cache.", owner_);
 1211 #endif
 1212       canvas->DrawCanvas(0, 0, canvas_cache_);
 1213       return;
 1214 #if defined(_DEBUG) && defined(VIEW_VERBOSE_DEBUG)
 1215     } else {
 1216       DLOG("Redraw whole view: content changed: %d, "
 1217            "canvas cache: %p, need redraw:%d",
 1218            content_changed_, canvas_cache_, need_redraw_);
 1219 #endif
 1220     }
 1221 
 1222     if (popup_element_.Get() && !popup_element_.Get()->IsReallyVisible())
 1223       SetPopupElement(NULL);
 1224 
 1225 #if defined(_DEBUG) && defined(VIEW_VERBOSE_DEBUG)
 1226     clip_region_.PrintLog();
 1227 #endif
 1228 
 1229     bool reset_clip_region = false;
 1230     if (enable_cache_ && !canvas_cache_ && graphics_) {
 1231       canvas_cache_ = graphics_->NewCanvas(width_, height_);
 1232       // If need_redraw_ was false, then clip region needs resetting.
 1233       reset_clip_region = !need_redraw_;
 1234       need_redraw_ = true;
 1235     }
 1236 
 1237     if (reset_clip_region) {
 1238       // Add whole view into clip region, so that all elements will be redrawn
 1239       // correctly.
 1240       clip_region_.Clear();
 1241       clip_region_.AddRectangle(Rectangle(0, 0, width_, height_));
 1242       if (on_add_rectangle_to_clip_region_.HasActiveConnections()) {
 1243         on_add_rectangle_to_clip_region_(0, 0, width_, height_);
 1244       }
 1245     }
 1246 
 1247     CanvasInterface *target;
 1248     if (canvas_cache_) {
 1249       target = canvas_cache_;
 1250       target->PushState();
 1251       target->IntersectGeneralClipRegion(clip_region_);
 1252       target->ClearRect(0, 0, width_, height_);
 1253     } else {
 1254       target = canvas;
 1255       target->PushState();
 1256     }
 1257 
 1258     BasicElement *popup = popup_element_.Get();
 1259     double popup_rotation = 0;
 1260     if (popup) {
 1261       BasicElement *e = popup;
 1262       for (; e != NULL; e = e->GetParentElement())
 1263         popup_rotation += e->GetRotation();
 1264     }
 1265 
 1266     // No need to draw children if there is a popup element and it's fully
 1267     // opaque and the clip region is inside its extents.
 1268     // If the popup element has non-horizontal/vertical orientation,
 1269     // then the region of the popup element may not cover the whole clip
 1270     // region. In this case it's not safe to skip drawing other children.
 1271     if (!(canvas_cache_ && clip_region_enabled_ && popup &&
 1272           popup->IsFullyOpaque() && fmod(popup_rotation, 90) == 0 &&
 1273           clip_region_.IsInside(popup->GetExtentsInView()))) {
 1274       children_.Draw(target);
 1275     }
 1276 
 1277     if (popup && owner_->IsElementInClipRegion(popup)) {
 1278       double pin_x = popup->GetPixelPinX();
 1279       double pin_y = popup->GetPixelPinY();
 1280       double abs_pin_x = 0;
 1281       double abs_pin_y = 0;
 1282       popup->SelfCoordToViewCoord(pin_x, pin_y, &abs_pin_x, &abs_pin_y);
 1283       target->TranslateCoordinates(abs_pin_x, abs_pin_y);
 1284       target->RotateCoordinates(DegreesToRadians(popup_rotation));
 1285       target->TranslateCoordinates(-pin_x, -pin_y);
 1286       popup->Draw(target);
 1287     }
 1288 
 1289     target->PopState();
 1290 
 1291     if (target == canvas_cache_)
 1292       canvas->DrawCanvas(0, 0, canvas_cache_);
 1293 
 1294 #ifdef _DEBUG
 1295     if (owner_->GetDebugMode() & DEBUG_CLIP_REGION)
 1296       DrawClipRegionBox(clip_region_, canvas);
 1297 #endif
 1298 
 1299     clip_region_.Clear();
 1300     need_redraw_ = false;
 1301     content_changed_ = false;
 1302 
 1303 #if defined(_DEBUG) && defined(VIEW_VERBOSE_DEBUG)
 1304     uint64_t end = main_loop_->GetCurrentTime();
 1305     if (end > 0 && start > 0) {
 1306       accum_draw_time_ += (end - start);
 1307       ++view_draw_count_;
 1308       DLOG("Draw count: %d, time: %ju, average %lf",
 1309            draw_count_, end - start,
 1310            double(accum_draw_time_)/double(view_draw_count_));
 1311     }
 1312 #endif
 1313   }
 1314 
 1315 #ifdef _DEBUG
 1316   static bool DrawRectOnCanvasCallback(double x, double y, double w, double h,
 1317                                        CanvasInterface *canvas) {
 1318     static int color_index = 1;
 1319     Color c(color_index & 1, (color_index >> 1) & 1, (color_index >> 2) & 1);
 1320     canvas->DrawLine(x, y, x + w, y, 1, c);
 1321     canvas->DrawLine(x + w, y, x + w, y + h, 1, c);
 1322     canvas->DrawLine(x + w, y + h, x, y + h, 1, c);
 1323     canvas->DrawLine(x, y + h, x, y, 1, c);
 1324     color_index = (color_index >= 4 ? 1 : (color_index << 1));
 1325     return true;
 1326   }
 1327 
 1328   void DrawClipRegionBox(const ClipRegion &region, CanvasInterface *canvas) {
 1329     region.EnumerateRectangles(NewSlot(DrawRectOnCanvasCallback, canvas));
 1330   }
 1331 #endif
 1332 
 1333   bool OnAddContextMenuItems(MenuInterface *menu) {
 1334     bool result = true;
 1335     // Let the element handle context menu first, so that the element can
 1336     // override view's menu.
 1337     if (mouseover_element_.Get()) {
 1338       if (mouseover_element_.Get()->IsReallyEnabled())
 1339         result = mouseover_element_.Get()->OnAddContextMenuItems(menu);
 1340       else
 1341         mouseover_element_.Reset(NULL);
 1342     }
 1343     if (!result)
 1344       return false;
 1345 
 1346     ContextMenuEvent event(new ScriptableMenu(gadget_, menu));
 1347     ScriptableEvent scriptable_event(&event, NULL, NULL);
 1348     FireEvent(&scriptable_event, oncontextmenu_event_);
 1349     if (scriptable_event.GetReturnValue() == EVENT_RESULT_CANCELED)
 1350       return false;
 1351 
 1352     // If the view is main and the mouse over element doesn't have special menu
 1353     // items, then add gadget's menu items.
 1354     if (!view_host_) return false;
 1355     if (gadget_ && view_host_->GetType() == ViewHostInterface::VIEW_HOST_MAIN)
 1356       gadget_->OnAddCustomMenuItems(menu);
 1357 
 1358     return result;
 1359   }
 1360 
 1361   bool OnSizing(double *width, double *height) {
 1362     ASSERT(width);
 1363     ASSERT(height);
 1364 
 1365     SizingEvent event(*width, *height);
 1366     ScriptableEvent scriptable_event(&event, NULL, &event);
 1367 
 1368     FireEvent(&scriptable_event, onsizing_event_);
 1369     bool result = (scriptable_event.GetReturnValue() != EVENT_RESULT_CANCELED);
 1370 
 1371 #if defined(_DEBUG) && defined(EVENT_VERBOSE_DEBUG)
 1372     DLOG("onsizing View %s, request: %lf x %lf, actual: %lf x %lf",
 1373          (result ? "accepted" : "cancelled"),
 1374          *width, *height, event.GetWidth(), event.GetHeight());
 1375 #endif
 1376 
 1377     if (result) {
 1378       *width = event.GetWidth();
 1379       *height = event.GetHeight();
 1380     }
 1381 
 1382     return result;
 1383   }
 1384 
 1385   void FireEventSlot(ScriptableEvent *event, const Slot *slot) {
 1386     ASSERT(event);
 1387     ASSERT(slot);
 1388     event->SetReturnValue(EVENT_RESULT_HANDLED);
 1389     event_stack_.push_back(event);
 1390     slot->Call(NULL, 0, NULL);
 1391     event_stack_.pop_back();
 1392   }
 1393 
 1394   void FireEvent(ScriptableEvent *event, const EventSignal &event_signal) {
 1395     if (events_enabled_ && event_signal.HasActiveConnections()) {
 1396       SignalSlot slot(&event_signal);
 1397       FireEventSlot(event, &slot);
 1398     }
 1399   }
 1400 
 1401   void FirePostedSizeEvents() {
 1402     // Make a copy of posted_size_events_, because it may change during the
 1403     // following loop.
 1404     PostedSizeEvents posted_events_copy;
 1405     std::swap(posted_size_events_, posted_events_copy);
 1406     for (PostedSizeEvents::iterator it = posted_events_copy.begin();
 1407          it != posted_events_copy.end(); ++it) {
 1408       // Test if the event is still valid. If srcElement has been deleted,
 1409       // it->first->GetSrcElement() should return NULL.
 1410       if (it->first->GetSrcElement())
 1411         FireEvent(it->first, *it->second);
 1412 
 1413       delete it->first->GetEvent();
 1414       delete it->first;
 1415     }
 1416     posted_events_copy.clear();
 1417   }
 1418 
 1419   void PostElementSizeEvent(BasicElement *element, const EventSignal &signal) {
 1420     ASSERT(element);
 1421     // Search if the size event has been posted for the element.
 1422     for (PostedSizeEvents::const_iterator it = posted_size_events_.begin();
 1423          it != posted_size_events_.end(); ++it) {
 1424       if (it->first->GetSrcElement() == element) {
 1425         // The size event already posted for the element.
 1426         return;
 1427       }
 1428     }
 1429 
 1430     Event *event = new SimpleEvent(Event::EVENT_SIZE);
 1431     ScriptableEvent *script_event = new ScriptableEvent(event, element, NULL);
 1432     posted_size_events_.push_back(std::make_pair(script_event, &signal));
 1433   }
 1434 
 1435   ScriptableEvent *GetEvent() {
 1436     return event_stack_.empty() ? NULL : *(event_stack_.end() - 1);
 1437   }
 1438 
 1439   BasicElement *GetElementByName(const char *name) {
 1440     ElementsMap::iterator it = all_elements_.find(name);
 1441     return it == all_elements_.end() ? NULL : it->second;
 1442   }
 1443 
 1444   bool OnElementAdd(BasicElement *element) {
 1445     ASSERT(element);
 1446     if (element->IsInstanceOf(ContentAreaElement::CLASS_ID)) {
 1447       if (content_area_element_.Get()) {
 1448         LOG("Only one contentarea element is allowed in a view");
 1449         return false;
 1450       }
 1451       content_area_element_.Reset(down_cast<ContentAreaElement *>(element));
 1452     }
 1453 
 1454     std::string name = element->GetName();
 1455     if (!name.empty() &&
 1456         // Don't overwrite the existing element with the same name.
 1457         all_elements_.find(name) == all_elements_.end())
 1458       all_elements_[name] = element;
 1459     return true;
 1460   }
 1461 
 1462   // All references to this element should be cleared here.
 1463   void OnElementRemove(BasicElement *element) {
 1464     ASSERT(element);
 1465     owner_->AddElementToClipRegion(element, NULL);
 1466 
 1467     // Clears tooltip immediately.
 1468     if (element == tooltip_element_.Get() && view_host_)
 1469       view_host_->ShowTooltip("");
 1470 
 1471     std::string name = element->GetName();
 1472     if (!name.empty()) {
 1473       ElementsMap::iterator it = all_elements_.find(name);
 1474       if (it != all_elements_.end() && it->second == element)
 1475         all_elements_.erase(it);
 1476     }
 1477   }
 1478 
 1479   void SetFocus(BasicElement *element) {
 1480     if (element != focused_element_.Get() &&
 1481         (!element || element->IsReallyEnabled())) {
 1482       ElementHolder element_holder(element);
 1483       // Remove the current focus first.
 1484       if (!focused_element_.Get() ||
 1485           focused_element_.Get()->OnOtherEvent(SimpleEvent(
 1486               Event::EVENT_FOCUS_OUT)) != EVENT_RESULT_CANCELED) {
 1487         ElementHolder old_focused_element(focused_element_.Get());
 1488         focused_element_.Reset(element_holder.Get());
 1489         // Only fire onfocusin event when the view is focused.
 1490         if (view_focused_ && focused_element_.Get()) {
 1491           // The enabled or visible state may changed, so check again.
 1492           if (!focused_element_.Get()->IsReallyEnabled() ||
 1493               focused_element_.Get()->OnOtherEvent(SimpleEvent(
 1494                   Event::EVENT_FOCUS_IN)) == EVENT_RESULT_CANCELED) {
 1495             // If the EVENT_FOCUS_IN is canceled, set focus back to the old
 1496             // focused element.
 1497             focused_element_.Reset(old_focused_element.Get());
 1498             if (focused_element_.Get() &&
 1499                 focused_element_.Get()->OnOtherEvent(SimpleEvent(
 1500                     Event::EVENT_FOCUS_IN)) == EVENT_RESULT_CANCELED) {
 1501               focused_element_.Reset(NULL);
 1502             }
 1503           }
 1504         }
 1505       }
 1506     }
 1507   }
 1508 
 1509   void SetPopupElement(BasicElement *element) {
 1510     if (popup_element_.Get()) {
 1511       // To make sure the area covered by popup element can be redrawn
 1512       // correctly.
 1513       owner_->AddElementToClipRegion(popup_element_.Get(), NULL);
 1514       popup_element_.Get()->OnPopupOff();
 1515     }
 1516     popup_element_.Reset(element);
 1517     if (element) {
 1518       element->QueueDraw();
 1519     }
 1520   }
 1521 
 1522   int BeginAnimation(Slot *slot, int start_value, int end_value,
 1523                      int duration) {
 1524     if (!slot) {
 1525       DLOG("Invalid slot for animation.");
 1526       return 0;
 1527     }
 1528 
 1529     if (duration < 0) {
 1530       DLOG("Invalid duration %d for animation.", duration);
 1531       delete slot;
 1532       return 0;
 1533     }
 1534 
 1535     uint64_t current_time = main_loop_->GetCurrentTime();
 1536     TimerWatchCallback *watch =
 1537         new TimerWatchCallback(this, slot, start_value, end_value,
 1538                                duration, current_time, true);
 1539     int id = main_loop_->AddTimeoutWatch(kAnimationInterval, watch);
 1540     if (id > 0) {
 1541       watch->SetWatchId(id);
 1542     } else {
 1543       DLOG("Failed to add animation timer.");
 1544       delete watch;
 1545     }
 1546     return id;
 1547   }
 1548 
 1549   int SetTimeout(Slot *slot, int timeout) {
 1550     if (!slot) {
 1551       LOG("Invalid slot for timeout.");
 1552       return 0;
 1553     }
 1554 
 1555     if (timeout < 0) {
 1556       DLOG("Invalid timeout %d.", timeout);
 1557       delete slot;
 1558       return 0;
 1559     }
 1560 
 1561     if (timeout < kMinTimeout)
 1562       timeout = kMinTimeout;
 1563 
 1564     TimerWatchCallback *watch =
 1565         new TimerWatchCallback(this, slot, 0, 0, 0, 0, true);
 1566     int id = main_loop_->AddTimeoutWatch(timeout, watch);
 1567     if (id > 0) {
 1568       watch->SetWatchId(id);
 1569     } else {
 1570       DLOG("Failed to add timeout timer.");
 1571       delete watch;
 1572     }
 1573     return id;
 1574   }
 1575 
 1576   int SetInterval(Slot *slot, int interval) {
 1577     if (!slot) {
 1578       LOG("Invalid slot for interval.");
 1579       return 0;
 1580     }
 1581 
 1582     if (interval < 0) {
 1583       DLOG("Invalid interval %d.", interval);
 1584       delete slot;
 1585       return 0;
 1586     }
 1587 
 1588     if (interval < kMinInterval)
 1589       interval = kMinInterval;
 1590 
 1591     TimerWatchCallback *watch =
 1592         new TimerWatchCallback(this, slot, 0, 0, -1, 0, true);
 1593     int id = main_loop_->AddTimeoutWatch(interval, watch);
 1594     if (id > 0) {
 1595       watch->SetWatchId(id);
 1596     } else {
 1597       DLOG("Failed to add interval timer.");
 1598       delete watch;
 1599     }
 1600     return id;
 1601   }
 1602 
 1603   void RemoveTimer(int token) {
 1604     if (token > 0)
 1605       main_loop_->RemoveWatch(token);
 1606   }
 1607 
 1608   ImageInterface *LoadImage(const Variant &src, bool is_mask) {
 1609     if (!graphics_) return NULL;
 1610 
 1611     switch (src.type()) {
 1612       case Variant::TYPE_STRING: {
 1613         const char *filename = VariantValue<const char*>()(src);
 1614         FileManagerInterface *fm = owner_->GetFileManager();
 1615         return image_cache_.LoadImage(graphics_, fm, filename, is_mask);
 1616       }
 1617       case Variant::TYPE_SCRIPTABLE: {
 1618         const ScriptableBinaryData *binary =
 1619             VariantValue<const ScriptableBinaryData *>()(src);
 1620         return binary ? graphics_->NewImage("", binary->data(), is_mask) : NULL;
 1621       }
 1622       case Variant::TYPE_VOID:
 1623         return NULL;
 1624       default:
 1625         LOG("Unsupported type of image src: '%s'", src.Print().c_str());
 1626         DLOG("src=%s", src.Print().c_str());
 1627         return NULL;
 1628     }
 1629   }
 1630 
 1631   ImageInterface *LoadImageFromGlobal(const char *name, bool is_mask) {
 1632     return image_cache_.LoadImage(graphics_, NULL, name, is_mask);
 1633   }
 1634 
 1635   Texture *LoadTexture(const Variant &src) {
 1636     Color color;
 1637     double opacity;
 1638     if (src.type() == Variant::TYPE_STRING) {
 1639       const char *name = VariantValue<const char *>()(src);
 1640       if (name && !strchr(name, '.') &&
 1641           Color::FromString(name, &color, &opacity))
 1642         return new Texture(color, opacity);
 1643     }
 1644 
 1645     ImageInterface *image = LoadImage(src, false);
 1646     return image ? new Texture(image) : NULL;
 1647   }
 1648 
 1649   void OnOptionChanged(const char *name) {
 1650     ScopedLogContext log_context(gadget_);
 1651     OptionChangedEvent event(name);
 1652     ScriptableEvent scriptable_event(&event, NULL, NULL);
 1653     FireEvent(&scriptable_event, onoptionchanged_event_);
 1654   }
 1655 
 1656  public: // member variables
 1657   double width_;
 1658   double height_;
 1659   double default_width_;
 1660   double default_height_;
 1661 
 1662   double resize_border_left_;
 1663   double resize_border_top_;
 1664   double resize_border_right_;
 1665   double resize_border_bottom_;
 1666 
 1667   View *owner_;
 1668   Gadget *gadget_;
 1669   ElementFactory *element_factory_;
 1670   MainLoopInterface *main_loop_;
 1671   ViewHostInterface *view_host_;
 1672   ScriptContextInterface *script_context_;
 1673   Connection *onoptionchanged_connection_;
 1674   CanvasInterface *canvas_cache_;
 1675   GraphicsInterface *graphics_;
 1676   ScriptableInterface *scriptable_view_;
 1677 
 1678   EventSignal oncancel_event_;
 1679   EventSignal onclick_event_;
 1680   EventSignal onclose_event_;
 1681   EventSignal ondblclick_event_;
 1682   EventSignal onrclick_event_;
 1683   EventSignal onrdblclick_event_;
 1684   EventSignal ondock_event_;
 1685   EventSignal onkeydown_event_;
 1686   EventSignal onkeypress_event_;
 1687   EventSignal onkeyup_event_;
 1688   EventSignal onminimize_event_;
 1689   EventSignal onmousedown_event_;
 1690   EventSignal onmousemove_event_;
 1691   EventSignal onmouseout_event_;
 1692   EventSignal onmouseover_event_;
 1693   EventSignal onmouseup_event_;
 1694   EventSignal onmousewheel_event_;
 1695   EventSignal onok_event_;
 1696   EventSignal onopen_event_;
 1697   EventSignal onoptionchanged_event_;
 1698   EventSignal onpopin_event_;
 1699   EventSignal onpopout_event_;
 1700   EventSignal onrestore_event_;
 1701   EventSignal onsize_event_;
 1702   EventSignal onsizing_event_;
 1703   EventSignal onundock_event_;
 1704   EventSignal oncontextmenu_event_;
 1705   EventSignal onthemechanged_event_;
 1706 
 1707   Signal0<void> on_destroy_signal_;
 1708   Signal4<void, double, double, double, double> on_add_rectangle_to_clip_region_;
 1709 
 1710   ImageCache image_cache_;
 1711 
 1712   // Note: though other things are case-insenstive, this map is case-sensitive,
 1713   // to keep compatible with the Windows version.
 1714   typedef LightMap<std::string, BasicElement *> ElementsMap;
 1715   // Put all_elements_ here to make it the last member to be destructed,
 1716   // because destruction of children_ needs it.
 1717   ElementsMap all_elements_;
 1718 
 1719   ClipRegion clip_region_;
 1720 
 1721   Elements children_;
 1722 
 1723   ElementHolder focused_element_;
 1724   ElementHolder mouseover_element_;
 1725   ElementHolder grabmouse_element_;
 1726   ElementHolder dragover_element_;
 1727   ElementHolder tooltip_element_;
 1728   ElementHolder popup_element_;
 1729   ScriptableHolder<ContentAreaElement> content_area_element_;
 1730 
 1731   typedef std::vector<std::pair<ScriptableEvent *, const EventSignal *> >
 1732       PostedSizeEvents;
 1733   PostedSizeEvents posted_size_events_;
 1734   std::vector<ScriptableEvent *> event_stack_;
 1735 
 1736   std::string caption_;
 1737 
 1738 #ifdef _DEBUG
 1739   int draw_count_;
 1740   int view_draw_count_;
 1741   uint64_t accum_draw_time_;
 1742 #endif
 1743 
 1744   HitTest hittest_              : 6;
 1745   HitTest last_hittest_         : 6;
 1746   CursorType last_cursor_type_  : 4;
 1747   ResizableMode resizable_      : 2;
 1748   EventResult dragover_result_  : 2;
 1749 
 1750   bool clip_region_enabled_     : 1;
 1751   bool enable_cache_            : 1;
 1752   bool show_caption_always_     : 1;
 1753   bool draw_queued_             : 1;
 1754   bool events_enabled_          : 1;
 1755   bool need_redraw_             : 1;
 1756   bool theme_changed_           : 1;
 1757   bool resize_border_specified_ : 1;
 1758   bool mouse_over_              : 1;
 1759   bool view_focused_            : 1;
 1760   bool safe_to_destroy_         : 1;
 1761   bool content_changed_         : 1;
 1762 
 1763   static const int kAnimationInterval = 40;
 1764   static const int kMinTimeout = 10;
 1765   static const int kMinInterval = 10;
 1766   static const uint64_t kMinTimeBetweenTimerCall = 5;
 1767 };
 1768 
 1769 View::View(ViewHostInterface *view_host,
 1770            Gadget *gadget,
 1771            ElementFactory *element_factory,
 1772            ScriptContextInterface *script_context)
 1773     : impl_(new Impl(this, view_host, gadget, element_factory, script_context)) {
 1774   // Make sure that the view is initialized when attaching to the ViewHost.
 1775   if (view_host) {
 1776     if (!impl_->graphics_)
 1777       impl_->graphics_ = view_host->NewGraphics();
 1778     view_host->SetView(this);
 1779   }
 1780 }
 1781 
 1782 View::~View() {
 1783   GraphicsInterface *tmp = impl_->graphics_;
 1784   delete impl_;
 1785   delete tmp;
 1786   impl_ = NULL;
 1787 }
 1788 
 1789 Gadget *View::GetGadget() const {
 1790   return impl_->gadget_;
 1791 }
 1792 
 1793 ScriptContextInterface *View::GetScriptContext() const {
 1794   return impl_->script_context_;
 1795 }
 1796 
 1797 FileManagerInterface *View::GetFileManager() const {
 1798   Gadget *gadget = GetGadget();
 1799   return gadget ? gadget->GetFileManager() : NULL;
 1800 }
 1801 
 1802 void View::Layout() {
 1803   impl_->Layout();
 1804 }
 1805 
 1806 GraphicsInterface *View::GetGraphics() const {
 1807   return impl_->graphics_;
 1808 }
 1809 
 1810 void View::RegisterProperties(RegisterableInterface *obj) const {
 1811   impl_->RegisterProperties(obj);
 1812 }
 1813 
 1814 void View::SetScriptable(ScriptableInterface *obj) {
 1815   impl_->scriptable_view_ = obj;
 1816   if (obj)
 1817     RegisterProperties(obj->GetRegisterable());
 1818 }
 1819 
 1820 ScriptableInterface *View::GetScriptable() const {
 1821   return impl_->scriptable_view_;
 1822 }
 1823 
 1824 bool View::IsSafeToDestroy() const {
 1825   return impl_->event_stack_.empty() && impl_->safe_to_destroy_;
 1826 }
 1827 
 1828 void View::SetWidth(double width) {
 1829   SetSize(width, GetHeight());
 1830 }
 1831 
 1832 void View::SetHeight(double height) {
 1833   SetSize(GetWidth(), height);
 1834 }
 1835 
 1836 void View::SetSize(double width, double height) {
 1837   impl_->SetSize(width, height);
 1838 }
 1839 
 1840 double View::GetWidth() const {
 1841   return impl_->width_;
 1842 }
 1843 
 1844 double View::GetHeight() const {
 1845   return impl_->height_;
 1846 }
 1847 
 1848 void View::GetDefaultSize(double *width, double *height) const {
 1849   if (width) *width = impl_->default_width_;
 1850   if (height) *height = impl_->default_height_;
 1851 }
 1852 
 1853 void View::SetResizable(ViewInterface::ResizableMode resizable) {
 1854   if (impl_->resizable_ != resizable) {
 1855     impl_->resizable_ = resizable;
 1856 
 1857     if (!impl_->resize_border_specified_ && resizable == RESIZABLE_TRUE) {
 1858       SetResizeBorder(8, 8, 8, 8);
 1859     }
 1860 
 1861     if (impl_->view_host_)
 1862       impl_->view_host_->SetResizable(resizable);
 1863   }
 1864 }
 1865 
 1866 ViewInterface::ResizableMode View::GetResizable() const {
 1867   return impl_->resizable_;
 1868 }
 1869 
 1870 void View::SetCaption(const std::string &caption) {
 1871   impl_->caption_ = caption;
 1872   if (impl_->view_host_)
 1873     impl_->view_host_->SetCaption(caption);
 1874 }
 1875 
 1876 std::string View::GetCaption() const {
 1877   return impl_->caption_;
 1878 }
 1879 
 1880 void View::SetShowCaptionAlways(bool show_always) {
 1881   impl_->show_caption_always_ = show_always;
 1882   if (impl_->view_host_)
 1883     impl_->view_host_->SetShowCaptionAlways(show_always);
 1884 }
 1885 
 1886 bool View::GetShowCaptionAlways() const {
 1887   return impl_->show_caption_always_;
 1888 }
 1889 
 1890 void View::SetResizeBorder(double left, double top,
 1891                            double right, double bottom) {
 1892   impl_->resize_border_specified_ = true;
 1893   impl_->resize_border_left_ = (left > 0 ? left : 0);
 1894   impl_->resize_border_top_ = (top > 0 ? top : 0);
 1895   impl_->resize_border_right_ = (right > 0 ? right : 0);
 1896   impl_->resize_border_bottom_ = (bottom > 0 ? bottom : 0);
 1897   if (impl_->view_host_)
 1898     impl_->view_host_->QueueResize();
 1899 }
 1900 
 1901 bool View::GetResizeBorder(double *left, double *top,
 1902                            double *right, double *bottom) const {
 1903   if (left)
 1904     *left = impl_->resize_border_left_;
 1905   if (top)
 1906     *top = impl_->resize_border_top_;
 1907   if (right)
 1908     *right = impl_->resize_border_right_;
 1909   if (bottom)
 1910     *bottom = impl_->resize_border_bottom_;
 1911   return impl_->resize_border_specified_;
 1912 }
 1913 
 1914 void View::MarkRedraw() {
 1915   impl_->MarkRedraw();
 1916 }
 1917 
 1918 void View::Draw(CanvasInterface *canvas) {
 1919   ScopedLogContext log_context(impl_->gadget_);
 1920   impl_->Draw(canvas);
 1921 }
 1922 
 1923 const ClipRegion *View::GetClipRegion() const {
 1924   return &impl_->clip_region_;
 1925 }
 1926 
 1927 EventResult View::OnMouseEvent(const MouseEvent &event) {
 1928   ScopedLogContext log_context(impl_->gadget_);
 1929   return impl_->OnMouseEvent(event);
 1930 }
 1931 
 1932 EventResult View::OnKeyEvent(const KeyboardEvent &event) {
 1933   ScopedLogContext log_context(impl_->gadget_);
 1934   return impl_->OnKeyEvent(event);
 1935 }
 1936 
 1937 EventResult View::OnDragEvent(const DragEvent &event) {
 1938   ScopedLogContext log_context(impl_->gadget_);
 1939   return impl_->OnDragEvent(event);
 1940 }
 1941 
 1942 EventResult View::OnOtherEvent(const Event &event) {
 1943   ScopedLogContext log_context(impl_->gadget_);
 1944   return impl_->OnOtherEvent(event);
 1945 }
 1946 
 1947 ViewInterface::HitTest View::GetHitTest() const {
 1948   return impl_->hittest_;
 1949 }
 1950 
 1951 bool View::OnAddContextMenuItems(MenuInterface *menu) {
 1952   ScopedLogContext log_context(impl_->gadget_);
 1953   return impl_->OnAddContextMenuItems(menu);
 1954 }
 1955 
 1956 bool View::OnSizing(double *width, double *height) {
 1957   ScopedLogContext log_context(impl_->gadget_);
 1958   return impl_->OnSizing(width, height);
 1959 }
 1960 
 1961 void View::FireEvent(ScriptableEvent *event, const EventSignal &event_signal) {
 1962   impl_->FireEvent(event, event_signal);
 1963 }
 1964 
 1965 void View::PostElementSizeEvent(BasicElement *element,
 1966                                 const EventSignal &signal) {
 1967   impl_->PostElementSizeEvent(element, signal);
 1968 }
 1969 
 1970 ScriptableEvent *View::GetEvent() const {
 1971   return impl_->GetEvent();
 1972 }
 1973 
 1974 void View::EnableEvents(bool enable_events) {
 1975   impl_->events_enabled_ = enable_events;
 1976 }
 1977 
 1978 void View::EnableCanvasCache(bool enable_cache) {
 1979   impl_->enable_cache_ = enable_cache;
 1980   if (impl_->canvas_cache_ && !enable_cache) {
 1981     impl_->canvas_cache_->Destroy();
 1982     impl_->canvas_cache_ = NULL;
 1983     QueueDraw();
 1984   }
 1985 }
 1986 
 1987 ElementFactory *View::GetElementFactory() const {
 1988   return impl_->element_factory_;
 1989 }
 1990 
 1991 Elements *View::GetChildren() const {
 1992   return &impl_->children_;
 1993 }
 1994 
 1995 BasicElement *View::GetElementByName(const char *name) const {
 1996   return impl_->GetElementByName(name);
 1997 }
 1998 
 1999 bool View::OnElementAdd(BasicElement *element) {
 2000   return impl_->OnElementAdd(element);
 2001 }
 2002 
 2003 void View::OnElementRemove(BasicElement *element) {
 2004   impl_->OnElementRemove(element);
 2005 }
 2006 
 2007 void View::SetFocus(BasicElement *element) {
 2008   impl_->SetFocus(element);
 2009 }
 2010 
 2011 void View::SetPopupElement(BasicElement *element) {
 2012   impl_->SetPopupElement(element);
 2013 }
 2014 
 2015 BasicElement *View::GetPopupElement() const {
 2016   return impl_->popup_element_.Get();
 2017 }
 2018 
 2019 BasicElement *View::GetFocusedElement() const {
 2020   return impl_->focused_element_.Get();
 2021 }
 2022 
 2023 BasicElement *View::GetMouseOverElement() const {
 2024   return impl_->mouseover_element_.Get();
 2025 }
 2026 
 2027 ContentAreaElement *View::GetContentAreaElement() const {
 2028   return impl_->content_area_element_.Get();
 2029 }
 2030 
 2031 bool View::IsElementInClipRegion(const BasicElement *element) const {
 2032   return !impl_->clip_region_enabled_ ||
 2033       impl_->clip_region_.Overlaps(element->GetExtentsInView());
 2034 }
 2035 
 2036 
 2037 void View::AddElementToClipRegion(BasicElement *element,
 2038                                   const Rectangle *rect) {
 2039   Rectangle element_rect = rect ? element->GetRectExtentsInView(*rect) :
 2040       element->GetExtentsInView();
 2041   element_rect.Integerize(true);
 2042   impl_->clip_region_.AddRectangle(element_rect);
 2043 }
 2044 
 2045 void View::EnableClipRegion(bool enable) {
 2046   impl_->clip_region_enabled_ = enable;
 2047 }
 2048 
 2049 bool View::IsClipRegionEnabled() const {
 2050   return impl_->clip_region_enabled_;
 2051 }
 2052 
 2053 void View::AddRectangleToClipRegion(const Rectangle &rect) {
 2054   if (!impl_->enable_cache_) {
 2055     Rectangle view_rect(0, 0, impl_->width_, impl_->height_);
 2056     if (view_rect.Intersect(rect)) {
 2057       view_rect.Integerize(true);
 2058       impl_->clip_region_.AddRectangle(view_rect);
 2059       if (impl_->on_add_rectangle_to_clip_region_.HasActiveConnections()) {
 2060         impl_->on_add_rectangle_to_clip_region_(
 2061             view_rect.x, view_rect.y, view_rect.w, view_rect.h);
 2062       }
 2063     }
 2064   }
 2065 }
 2066 
 2067 void View::IncreaseDrawCount() {
 2068 #ifdef _DEBUG
 2069   impl_->draw_count_++;
 2070 #endif
 2071 }
 2072 
 2073 int View::BeginAnimation(Slot0<void> *slot,
 2074                          int start_value,
 2075                          int end_value,
 2076                          int duration) {
 2077   return impl_->BeginAnimation(slot, start_value, end_value, duration);
 2078 }
 2079 
 2080 void View::CancelAnimation(int token) {
 2081   impl_->RemoveTimer(token);
 2082 }
 2083 
 2084 int View::SetTimeout(Slot0<void> *slot, int timeout) {
 2085   return impl_->SetTimeout(slot, timeout);
 2086 }
 2087 
 2088 void View::ClearTimeout(int token) {
 2089   impl_->RemoveTimer(token);
 2090 }
 2091 
 2092 int View::SetInterval(Slot0<void> *slot, int interval) {
 2093   return impl_->SetInterval(slot, interval);
 2094 }
 2095 
 2096 void View::ClearInterval(int token) {
 2097   impl_->RemoveTimer(token);
 2098 }
 2099 
 2100 ImageInterface *View::LoadImage(const Variant &src, bool is_mask) const {
 2101   return impl_->LoadImage(src, is_mask);
 2102 }
 2103 
 2104 ImageInterface *
 2105 View::LoadImageFromGlobal(const char *name, bool is_mask) const {
 2106   return impl_->LoadImageFromGlobal(name, is_mask);
 2107 }
 2108 
 2109 Texture *View::LoadTexture(const Variant &src) const {
 2110   return impl_->LoadTexture(src);
 2111 }
 2112 
 2113 void *View::GetNativeWidget() const {
 2114   return impl_->view_host_ ? impl_->view_host_->GetNativeWidget() : NULL;
 2115 }
 2116 
 2117 // Note! view should not change between different kinds of view hosts,
 2118 // since the graphics compatibility issue
 2119 ViewHostInterface *View::SwitchViewHost(ViewHostInterface *new_host) {
 2120   ViewHostInterface *old_host = impl_->view_host_;
 2121   old_host->SetView(NULL);
 2122   if (impl_->canvas_cache_) {
 2123     impl_->canvas_cache_->Destroy();
 2124     impl_->canvas_cache_ = NULL;
 2125   }
 2126   impl_->view_host_ = new_host;
 2127   if (new_host) {
 2128     if (!impl_->graphics_)
 2129       impl_->graphics_ = new_host->NewGraphics();
 2130     new_host->SetView(this);
 2131     MarkRedraw();
 2132     new_host->QueueDraw();
 2133   }
 2134   return old_host;
 2135 }
 2136 
 2137 ViewHostInterface *View::GetViewHost() const {
 2138   return impl_->view_host_;
 2139 }
 2140 
 2141 void View::ViewCoordToNativeWidgetCoord(double x, double y, double *widget_x,
 2142                                         double *widget_y) const {
 2143   if (impl_->view_host_)
 2144     impl_->view_host_->ViewCoordToNativeWidgetCoord(x, y, widget_x, widget_y);
 2145 }
 2146 
 2147 void View::NativeWidgetCoordToViewCoord(double x, double y,
 2148                                         double *view_x, double *view_y) const {
 2149   if (impl_->view_host_)
 2150     impl_->view_host_->NativeWidgetCoordToViewCoord(x, y, view_x, view_y);
 2151 }
 2152 
 2153 void View::QueueDraw() {
 2154   if (!impl_->draw_queued_ && impl_->view_host_) {
 2155     impl_->draw_queued_ = true;
 2156     impl_->view_host_->QueueDraw();
 2157   }
 2158 }
 2159 
 2160 int View::GetDebugMode() const {
 2161   return impl_->view_host_ ? impl_->view_host_->GetDebugMode() : DEBUG_DISABLED;
 2162 }
 2163 
 2164 bool View::OpenURL(const char *url) const {
 2165   return impl_->gadget_ ? impl_->gadget_->OpenURL(url) : false;
 2166 }
 2167 
 2168 void View::Alert(const char *message) const {
 2169   if (impl_->view_host_) {
 2170     impl_->safe_to_destroy_ = false;
 2171     bool old_interaction =
 2172       impl_->gadget_ ? impl_->gadget_->SetInUserInteraction(true) : false;
 2173     impl_->view_host_->Alert(this, message);
 2174     if (impl_->gadget_)
 2175       impl_->gadget_->SetInUserInteraction(old_interaction);
 2176     impl_->safe_to_destroy_ = true;
 2177   }
 2178 }
 2179 
 2180 ViewHostInterface::ConfirmResponse View::Confirm(const char *message,
 2181                                                  bool cancel_button) const {
 2182   ViewHostInterface::ConfirmResponse result =
 2183     cancel_button ? ViewHostInterface::CONFIRM_CANCEL :
 2184                     ViewHostInterface::CONFIRM_NO;
 2185   if (impl_->view_host_) {
 2186     impl_->safe_to_destroy_ = false;
 2187     bool old_interaction =
 2188       impl_->gadget_ ? impl_->gadget_->SetInUserInteraction(true) : false;
 2189     result = impl_->view_host_->Confirm(this, message, cancel_button);
 2190     if (impl_->gadget_)
 2191       impl_->gadget_->SetInUserInteraction(old_interaction);
 2192     impl_->safe_to_destroy_ = true;
 2193   }
 2194   return result;
 2195 }
 2196 
 2197 std::string View::Prompt(const char *message,
 2198                          const char *default_result) const {
 2199   std::string result;
 2200   if (impl_->view_host_) {
 2201     impl_->safe_to_destroy_ = false;
 2202     bool old_interaction =
 2203       impl_->gadget_ ? impl_->gadget_->SetInUserInteraction(true) : false;
 2204     result = impl_->view_host_->Prompt(this, message, default_result);
 2205     if (impl_->gadget_)
 2206       impl_->gadget_->SetInUserInteraction(old_interaction);
 2207     impl_->safe_to_destroy_ = true;
 2208   }
 2209   return result;
 2210 }
 2211 
 2212 uint64_t View::GetCurrentTime() const {
 2213   return impl_->main_loop_->GetCurrentTime();
 2214 }
 2215 
 2216 void View::ShowElementTooltip(BasicElement *element) {
 2217   ASSERT(element);
 2218   ASSERT(element->GetView() == this);
 2219   impl_->tooltip_element_.Reset(element);
 2220   if (impl_->view_host_)
 2221     impl_->view_host_->ShowTooltip(element->GetTooltip());
 2222 }
 2223 
 2224 void View::ShowElementTooltipAtPosition(BasicElement *element,
 2225                                         double x, double y) {
 2226   ASSERT(element);
 2227   ASSERT(element->GetView() == this);
 2228   impl_->tooltip_element_.Reset(element);
 2229   if (impl_->view_host_) {
 2230     element->SelfCoordToViewCoord(x, y, &x, &y);
 2231     impl_->view_host_->ShowTooltipAtPosition(element->GetTooltip(), x, y);
 2232   }
 2233 }
 2234 
 2235 void View::SetCursor(ViewInterface::CursorType type) {
 2236   if (impl_->view_host_ && (impl_->last_cursor_type_ != type ||
 2237                             impl_->last_hittest_ != impl_->hittest_)) {
 2238     impl_->last_cursor_type_ = type;
 2239     impl_->last_hittest_ = impl_->hittest_;
 2240     impl_->view_host_->SetCursor(type);
 2241   }
 2242 }
 2243 
 2244 bool View::ShowView(bool modal, int flags, Slot1<bool, int> *feedback_handler) {
 2245   return impl_->view_host_ ?
 2246          impl_->view_host_->ShowView(modal, flags, feedback_handler) :
 2247          false;
 2248 }
 2249 
 2250 void View::CloseView() {
 2251   if (impl_->view_host_)
 2252     impl_->view_host_->CloseView();
 2253 }
 2254 
 2255 int View::GetDefaultFontSize() const {
 2256   return impl_->gadget_ ?
 2257          impl_->gadget_->GetDefaultFontSize() : kDefaultFontSize;
 2258 }
 2259 
 2260 bool View::IsFocused() const {
 2261   return impl_->view_focused_;
 2262 }
 2263 
 2264 Connection *View::ConnectOnCancelEvent(Slot0<void> *handler) {
 2265   return impl_->oncancel_event_.Connect(handler);
 2266 }
 2267 Connection *View::ConnectOnClickEvent(Slot0<void> *handler) {
 2268   return impl_->onclick_event_.Connect(handler);
 2269 }
 2270 Connection *View::ConnectOnCloseEvent(Slot0<void> *handler) {
 2271   return impl_->onclose_event_.Connect(handler);
 2272 }
 2273 Connection *View::ConnectOnDblClickEvent(Slot0<void> *handler) {
 2274   return impl_->ondblclick_event_.Connect(handler);
 2275 }
 2276 Connection *View::ConnectOnRClickEvent(Slot0<void> *handler) {
 2277   return impl_->onrclick_event_.Connect(handler);
 2278 }
 2279 Connection *View::ConnectOnRDblClickCancelEvent(Slot0<void> *handler) {
 2280   return impl_->onrdblclick_event_.Connect(handler);
 2281 }
 2282 Connection *View::ConnectOnDockEvent(Slot0<void> *handler) {
 2283   return impl_->ondock_event_.Connect(handler);
 2284 }
 2285 Connection *View::ConnectOnKeyDownEvent(Slot0<void> *handler) {
 2286   return impl_->onkeydown_event_.Connect(handler);
 2287 }
 2288 Connection *View::ConnectOnPressEvent(Slot0<void> *handler) {
 2289   return impl_->onkeypress_event_.Connect(handler);
 2290 }
 2291 Connection *View::ConnectOnKeyUpEvent(Slot0<void> *handler) {
 2292   return impl_->onkeyup_event_.Connect(handler);
 2293 }
 2294 Connection *View::ConnectOnMinimizeEvent(Slot0<void> *handler) {
 2295   return impl_->onminimize_event_.Connect(handler);
 2296 }
 2297 Connection *View::ConnectOnMouseDownEvent(Slot0<void> *handler) {
 2298   return impl_->onmousedown_event_.Connect(handler);
 2299 }
 2300 Connection *View::ConnectOnMouseMoveEvent(Slot0<void> *handler) {
 2301   return impl_->onmousemove_event_.Connect(handler);
 2302 }
 2303 Connection *View::ConnectOnMouseOverEvent(Slot0<void> *handler) {
 2304   return impl_->onmouseover_event_.Connect(handler);
 2305 }
 2306 Connection *View::ConnectOnMouseOutEvent(Slot0<void> *handler) {
 2307   return impl_->onmouseout_event_.Connect(handler);
 2308 }
 2309 Connection *View::ConnectOnMouseUpEvent(Slot0<void> *handler) {
 2310   return impl_->onmouseup_event_.Connect(handler);
 2311 }
 2312 Connection *View::ConnectOnMouseWheelEvent(Slot0<void> *handler) {
 2313   return impl_->onmousewheel_event_.Connect(handler);
 2314 }
 2315 Connection *View::ConnectOnOkEvent(Slot0<void> *handler) {
 2316   return impl_->onok_event_.Connect(handler);
 2317 }
 2318 Connection *View::ConnectOnOpenEvent(Slot0<void> *handler) {
 2319   return impl_->onopen_event_.Connect(handler);
 2320 }
 2321 Connection *View::ConnectOnOptionChangedEvent(Slot0<void> *handler) {
 2322   return impl_->onoptionchanged_event_.Connect(handler);
 2323 }
 2324 Connection *View::ConnectOnPopInEvent(Slot0<void> *handler) {
 2325   return impl_->onpopin_event_.Connect(handler);
 2326 }
 2327 Connection *View::ConnectOnPopOutEvent(Slot0<void> *handler) {
 2328   return impl_->onpopout_event_.Connect(handler);
 2329 }
 2330 Connection *View::ConnectOnRestoreEvent(Slot0<void> *handler) {
 2331   return impl_->onrestore_event_.Connect(handler);
 2332 }
 2333 Connection *View::ConnectOnSizeEvent(Slot0<void> *handler) {
 2334   return impl_->onsize_event_.Connect(handler);
 2335 }
 2336 Connection *View::ConnectOnSizingEvent(Slot0<void> *handler) {
 2337   return impl_->onsizing_event_.Connect(handler);
 2338 }
 2339 Connection *View::ConnectOnUndockEvent(Slot0<void> *handler) {
 2340   return impl_->onundock_event_.Connect(handler);
 2341 }
 2342 Connection *View::ConnectOnContextMenuEvent(Slot0<void> *handler) {
 2343   return impl_->oncontextmenu_event_.Connect(handler);
 2344 }
 2345 Connection *View::ConnectOnThemeChangedEvent(Slot0<void> *handler) {
 2346   return impl_->onthemechanged_event_.Connect(handler);
 2347 }
 2348 Connection *View::ConnectOnAddRectangleToClipRegion(
 2349     Slot4<void, double, double, double, double> *handler) {
 2350   return impl_->on_add_rectangle_to_clip_region_.Connect(handler);
 2351 }
 2352 
 2353 } // namespace ggadget