/* * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "Widget.h" #import "BlockExceptions.h" #import "Cursor.h" #import "Document.h" #import "Font.h" #import "Frame.h" #import "GraphicsContext.h" #import "Page.h" #import "PlatformMouseEvent.h" #import "WebCoreFrameBridge.h" #import "WebCoreFrameView.h" #import "WebCoreView.h" #import "WidgetClient.h" #import namespace WebCore { class WidgetPrivate { public: RetainPtr view; WidgetClient* client; bool visible; bool mustStayInWindow; bool removeFromSuperviewSoon; }; static void safeRemoveFromSuperview(NSView *view) { // If the the view is the first responder, then set the window's first responder to nil so // we don't leave the window pointing to a view that's no longer in it. NSWindow *window = [view window]; NSResponder *firstResponder = [window firstResponder]; if ([firstResponder isKindOfClass:[NSView class]] && [(NSView *)firstResponder isDescendantOf:view]) [window makeFirstResponder:nil]; [view removeFromSuperview]; } Widget::Widget() : data(new WidgetPrivate) { data->view = nil; data->client = 0; data->visible = true; data->mustStayInWindow = false; data->removeFromSuperviewSoon = false; } Widget::Widget(NSView* view) : data(new WidgetPrivate) { data->view = view; data->client = 0; data->visible = true; data->mustStayInWindow = false; data->removeFromSuperviewSoon = false; } Widget::~Widget() { delete data; } void Widget::setEnabled(bool enabled) { id view = data->view.get(); BEGIN_BLOCK_OBJC_EXCEPTIONS; if ([view respondsToSelector:@selector(setEnabled:)]) { [view setEnabled:enabled]; } END_BLOCK_OBJC_EXCEPTIONS; } bool Widget::isEnabled() const { id view = data->view.get(); BEGIN_BLOCK_OBJC_EXCEPTIONS; if ([view respondsToSelector:@selector(isEnabled)]) { return [view isEnabled]; } END_BLOCK_OBJC_EXCEPTIONS; return true; } IntRect Widget::frameGeometry() const { BEGIN_BLOCK_OBJC_EXCEPTIONS; return enclosingIntRect([getOuterView() frame]); END_BLOCK_OBJC_EXCEPTIONS; return IntRect(); } // FIXME: Should move this to Chrome; bad layering that this knows about Frame. void Widget::setFocus() { Frame* frame = Frame::frameForWidget(this); if (!frame) return; BEGIN_BLOCK_OBJC_EXCEPTIONS; NSView *view = [getView() _webcore_effectiveFirstResponder]; if (Page* page = frame->page()) page->chrome()->focusNSView(view); END_BLOCK_OBJC_EXCEPTIONS; } void Widget::setCursor(const Cursor& cursor) { BEGIN_BLOCK_OBJC_EXCEPTIONS; for (id view = data->view.get(); view; view = [view superview]) { if ([view respondsToSelector:@selector(setDocumentCursor:)]) { if ([view respondsToSelector:@selector(documentCursor)] && cursor.impl() == [view documentCursor]) break; [view setDocumentCursor:cursor.impl()]; break; } } END_BLOCK_OBJC_EXCEPTIONS; } void Widget::show() { if (!data || data->visible) return; data->visible = true; BEGIN_BLOCK_OBJC_EXCEPTIONS; [getOuterView() setHidden:NO]; END_BLOCK_OBJC_EXCEPTIONS; } void Widget::hide() { if (!data || !data->visible) return; data->visible = false; BEGIN_BLOCK_OBJC_EXCEPTIONS; [getOuterView() setHidden:YES]; END_BLOCK_OBJC_EXCEPTIONS; } void Widget::setFrameGeometry(const IntRect &rect) { BEGIN_BLOCK_OBJC_EXCEPTIONS; NSView *v = getOuterView(); NSRect f = rect; if (!NSEqualRects(f, [v frame])) { [v setFrame:f]; [v setNeedsDisplay: NO]; } END_BLOCK_OBJC_EXCEPTIONS; } NSView* Widget::getView() const { return data->view.get(); } void Widget::setView(NSView* view) { BEGIN_BLOCK_OBJC_EXCEPTIONS; data->view = view; END_BLOCK_OBJC_EXCEPTIONS; } NSView* Widget::getOuterView() const { // If this widget's view is a WebCoreFrameView the we resize its containing view, a WebFrameView. NSView* view = data->view.get(); if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) { view = [view superview]; ASSERT(view); } return view; } void Widget::paint(GraphicsContext* p, const IntRect& r) { if (p->paintingDisabled()) return; NSView *view = getOuterView(); BEGIN_BLOCK_OBJC_EXCEPTIONS; [view displayRectIgnoringOpacity:[view convertRect:r fromView:[view superview]]]; END_BLOCK_OBJC_EXCEPTIONS; } void Widget::invalidate() { BEGIN_BLOCK_OBJC_EXCEPTIONS; [getView() setNeedsDisplay: YES]; END_BLOCK_OBJC_EXCEPTIONS; } void Widget::invalidateRect(const IntRect& r) { BEGIN_BLOCK_OBJC_EXCEPTIONS; [getView() setNeedsDisplayInRect: r]; END_BLOCK_OBJC_EXCEPTIONS; } // FIXME: Should move this to Chrome; bad layering that this knows about Frame. void Widget::setIsSelected(bool isSelected) { if (Frame* frame = Frame::frameForWidget(this)) [frame->bridge() setIsSelected:isSelected forView:getView()]; } void Widget::addToSuperview(NSView *superview) { BEGIN_BLOCK_OBJC_EXCEPTIONS; ASSERT(superview); NSView *subview = getOuterView(); ASSERT(![superview isDescendantOf:subview]); if ([subview superview] != superview) [superview addSubview:subview]; data->removeFromSuperviewSoon = false; END_BLOCK_OBJC_EXCEPTIONS; } void Widget::removeFromSuperview() { if (data->mustStayInWindow) data->removeFromSuperviewSoon = true; else { data->removeFromSuperviewSoon = false; BEGIN_BLOCK_OBJC_EXCEPTIONS; safeRemoveFromSuperview(getOuterView()); END_BLOCK_OBJC_EXCEPTIONS; } } void Widget::beforeMouseDown(NSView *view, Widget* widget) { if (widget) { ASSERT(view == widget->getOuterView()); ASSERT(!widget->data->mustStayInWindow); widget->data->mustStayInWindow = true; } } void Widget::afterMouseDown(NSView *view, Widget* widget) { if (!widget) { BEGIN_BLOCK_OBJC_EXCEPTIONS; safeRemoveFromSuperview(view); END_BLOCK_OBJC_EXCEPTIONS; } else { ASSERT(widget->data->mustStayInWindow); widget->data->mustStayInWindow = false; if (widget->data->removeFromSuperviewSoon) widget->removeFromSuperview(); } } void Widget::setClient(WidgetClient* c) { data->client = c; } WidgetClient* Widget::client() const { return data->client; } void Widget::removeFromParent() { } IntPoint Widget::convertToScreenCoordinate(NSView *view, const IntPoint& point) { NSPoint conversionPoint = { point.x(), point.y() }; conversionPoint = [view convertPoint:conversionPoint toView:nil]; return globalPoint(conversionPoint, [view window]); } }