2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #import "KWQExceptions.h"
29 #import "KWQFoundationExtras.h"
30 #import "KWQKHTMLPart.h"
31 #import "KWQLogging.h"
33 #import "KWQWindowWidget.h"
34 #import "WebCoreBridge.h"
35 #import "WebCoreFrameView.h"
36 #import "WebCoreView.h"
38 #import "render_canvas.h"
39 #import "render_replaced.h"
40 #import "render_style.h"
42 using khtml::RenderWidget;
45 A QWidget roughly corresponds to an NSView. In Qt a QFrame and QMainWindow inherit
46 from a QWidget. In Cocoa a NSWindow does not inherit from NSView. We
47 emulate most QWidgets using NSViews.
50 class KWQWidgetPrivate
58 bool mustStayInWindow;
59 bool removeFromSuperviewSoon;
62 QWidget::QWidget() : data(new KWQWidgetPrivate)
64 static QStyle defaultStyle;
65 data->style = &defaultStyle;
68 data->mustStayInWindow = false;
69 data->removeFromSuperviewSoon = false;
72 QWidget::QWidget(NSView *view) : data(new KWQWidgetPrivate)
74 static QStyle defaultStyle;
75 data->style = &defaultStyle;
76 data->view = KWQRetain(view);
78 data->mustStayInWindow = false;
79 data->removeFromSuperviewSoon = false;
85 KWQRelease(data->view);
86 KWQ_UNBLOCK_EXCEPTIONS;
91 QSize QWidget::sizeHint() const
93 // May be overriden by subclasses.
97 void QWidget::resize(int w, int h)
99 setFrameGeometry(QRect(pos().x(), pos().y(), w, h));
102 void QWidget::setActiveWindow()
104 KWQ_BLOCK_EXCEPTIONS;
105 [KWQKHTMLPart::bridgeForWidget(this) focusWindow];
106 KWQ_UNBLOCK_EXCEPTIONS;
109 void QWidget::setEnabled(bool enabled)
111 id view = data->view;
112 KWQ_BLOCK_EXCEPTIONS;
113 if ([view respondsToSelector:@selector(setEnabled:)]) {
114 [view setEnabled:enabled];
116 KWQ_UNBLOCK_EXCEPTIONS;
119 bool QWidget::isEnabled() const
121 id view = data->view;
123 KWQ_BLOCK_EXCEPTIONS;
124 if ([view respondsToSelector:@selector(isEnabled)]) {
125 return [view isEnabled];
127 KWQ_UNBLOCK_EXCEPTIONS;
132 long QWidget::winId() const
137 int QWidget::x() const
139 return frameGeometry().topLeft().x();
142 int QWidget::y() const
144 return frameGeometry().topLeft().y();
147 int QWidget::width() const
149 return frameGeometry().size().width();
152 int QWidget::height() const
154 return frameGeometry().size().height();
157 QSize QWidget::size() const
159 return frameGeometry().size();
162 void QWidget::resize(const QSize &s)
164 resize(s.width(), s.height());
167 QPoint QWidget::pos() const
169 return frameGeometry().topLeft();
172 void QWidget::move(int x, int y)
174 setFrameGeometry(QRect(x, y, width(), height()));
177 void QWidget::move(const QPoint &p)
182 QRect QWidget::frameGeometry() const
186 KWQ_BLOCK_EXCEPTIONS;
187 rect = QRect([getOuterView() frame]);
188 KWQ_UNBLOCK_EXCEPTIONS;
193 int QWidget::baselinePosition(int height) const
198 bool QWidget::hasFocus() const
200 NSView *view = [getView() _webcore_effectiveFirstResponder];
202 KWQ_BLOCK_EXCEPTIONS;
203 NSView *firstResponder = [KWQKHTMLPart::bridgeForWidget(this) firstResponder];
205 if (!firstResponder) {
208 if (firstResponder == view) {
212 // Some widgets, like text fields, secure text fields, text areas, and selects
213 // (when displayed using a list box) may have a descendent widget that is
214 // first responder. This checksDescendantsForFocus() check, turned on for the
215 // four widget types listed, enables the additional check which makes this
216 // function work correctly for the above-mentioned widget types.
217 if (checksDescendantsForFocus() &&
218 [firstResponder isKindOfClass:[NSView class]] &&
219 [(NSView *)firstResponder isDescendantOf:view]) {
220 // Return true when the first responder is a subview of this widget's view
223 KWQ_UNBLOCK_EXCEPTIONS;
228 void QWidget::setFocus()
234 NSView *view = [getView() _webcore_effectiveFirstResponder];
236 KWQ_BLOCK_EXCEPTIONS;
237 if ([view acceptsFirstResponder]) {
238 [KWQKHTMLPart::bridgeForWidget(this) makeFirstResponder:view];
240 KWQ_UNBLOCK_EXCEPTIONS;
243 void QWidget::clearFocus()
249 KWQKHTMLPart::clearDocumentFocus(this);
252 bool QWidget::checksDescendantsForFocus() const
257 QWidget::FocusPolicy QWidget::focusPolicy() const
259 // This provides support for controlling the widgets that take
260 // part in tab navigation. Widgets must:
261 // 1. not be hidden by css
263 // 3. accept first responder
265 RenderWidget *widget = const_cast<RenderWidget *>
266 (static_cast<const RenderWidget *>(eventFilterObject()));
267 if (widget->style()->visibility() != khtml::VISIBLE)
273 KWQ_BLOCK_EXCEPTIONS;
274 if (![getView() acceptsFirstResponder])
276 KWQ_UNBLOCK_EXCEPTIONS;
281 const QPalette& QWidget::palette() const
286 void QWidget::setPalette(const QPalette &palette)
291 QStyle &QWidget::style() const
296 void QWidget::setStyle(QStyle *style)
298 // According to the Qt implementation
300 Sets the widget's GUI style to \a style. Ownership of the style
301 object is not transferred.
306 QFont QWidget::font() const
311 void QWidget::setFont(const QFont &font)
316 void QWidget::constPolish() const
320 bool QWidget::isVisible() const
322 // FIXME - rewrite interms of top level widget?
324 KWQ_BLOCK_EXCEPTIONS;
325 return [[KWQKHTMLPart::bridgeForWidget(this) window] isVisible];
326 KWQ_UNBLOCK_EXCEPTIONS;
331 void QWidget::setCursor(const QCursor &cur)
333 KWQ_BLOCK_EXCEPTIONS;
334 id view = data->view;
336 if ([view respondsToSelector:@selector(setDocumentCursor:)]) {
337 [view setDocumentCursor:cur.handle()];
340 view = [view superview];
342 KWQ_UNBLOCK_EXCEPTIONS;
345 QCursor QWidget::cursor()
347 KWQ_BLOCK_EXCEPTIONS;
350 id view = data->view;
352 if ([view respondsToSelector:@selector(documentCursor)]) {
353 cursor = QCursor([view documentCursor]);
356 view = [view superview];
360 KWQ_UNBLOCK_EXCEPTIONS;
365 void QWidget::unsetCursor()
367 setCursor(QCursor());
370 bool QWidget::event(QEvent *)
377 if (!data || data->visible)
380 data->visible = true;
382 KWQ_BLOCK_EXCEPTIONS;
383 [getOuterView() setHidden: NO];
384 KWQ_UNBLOCK_EXCEPTIONS;
389 if (!data || !data->visible)
392 data->visible = false;
394 KWQ_BLOCK_EXCEPTIONS;
395 [getOuterView() setHidden: YES];
396 KWQ_UNBLOCK_EXCEPTIONS;
399 void QWidget::setFrameGeometry(const QRect &rect)
401 KWQ_BLOCK_EXCEPTIONS;
402 NSView *v = getOuterView();
404 if (!NSEqualRects(f, [v frame])) {
406 [v setNeedsDisplay: NO];
408 KWQ_UNBLOCK_EXCEPTIONS;
411 QPoint QWidget::mapFromGlobal(const QPoint &p) const
415 KWQ_BLOCK_EXCEPTIONS;
416 bp = [[KWQKHTMLPart::bridgeForWidget(this) window] convertScreenToBase:[data->view convertPoint:p toView:nil]];
417 KWQ_UNBLOCK_EXCEPTIONS;
422 NSView *QWidget::getView() const
427 void QWidget::setView(NSView *view)
429 KWQ_BLOCK_EXCEPTIONS;
431 KWQRelease(data->view);
433 KWQ_UNBLOCK_EXCEPTIONS;
436 NSView *QWidget::getOuterView() const
438 // A QScrollView is a widget normally used to represent a frame.
439 // If this widget's view is a WebCoreFrameView the we resize its containing view, a WebFrameView.
440 // The scroll view contained by the WebFrameView will be autosized.
442 NSView *view = data->view;
445 if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
446 view = [view superview];
453 void QWidget::lockDrawingFocus()
455 KWQ_BLOCK_EXCEPTIONS;
456 [getView() lockFocus];
457 KWQ_UNBLOCK_EXCEPTIONS;
460 void QWidget::unlockDrawingFocus()
462 KWQ_BLOCK_EXCEPTIONS;
463 [getView() unlockFocus];
464 KWQ_UNBLOCK_EXCEPTIONS;
467 void QWidget::disableFlushDrawing()
469 // It's OK to use the real window here, because if the view's not
470 // in the view hierarchy, then we don't actually want to affect
472 KWQ_BLOCK_EXCEPTIONS;
473 [[getView() window] disableFlushWindow];
474 KWQ_UNBLOCK_EXCEPTIONS;
477 void QWidget::enableFlushDrawing()
479 // It's OK to use the real window here, because if the view's not
480 // in the view hierarchy, then we don't actually want to affect
482 KWQ_BLOCK_EXCEPTIONS;
483 NSWindow *window = [getView() window];
484 [window enableFlushWindow];
485 [window flushWindow];
486 KWQ_UNBLOCK_EXCEPTIONS;
489 void QWidget::setDrawingAlpha(float alpha)
491 KWQ_BLOCK_EXCEPTIONS;
492 CGContextSetAlpha((CGContextRef)[[NSGraphicsContext currentContext] graphicsPort], alpha);
493 KWQ_UNBLOCK_EXCEPTIONS;
496 void QWidget::paint(QPainter *p, const QRect &r)
498 if (p->paintingDisabled()) {
501 NSView *view = getOuterView();
502 // KWQTextArea and KWQTextField both rely on the fact that we use this particular
503 // NSView display method. If you change this, be sure to update them as well.
504 KWQ_BLOCK_EXCEPTIONS;
505 [view displayRectIgnoringOpacity:[view convertRect:r fromView:[view superview]]];
506 KWQ_UNBLOCK_EXCEPTIONS;
509 void QWidget::sendConsumedMouseUp()
511 khtml::RenderWidget *widget = const_cast<khtml::RenderWidget *>
512 (static_cast<const khtml::RenderWidget *>(eventFilterObject()));
514 KWQ_BLOCK_EXCEPTIONS;
515 widget->sendConsumedMouseUp(QPoint([[NSApp currentEvent] locationInWindow]),
516 // FIXME: should send real state and button
518 KWQ_UNBLOCK_EXCEPTIONS;
521 void QWidget::setIsSelected(bool isSelected)
523 [KWQKHTMLPart::bridgeForWidget(this) setIsSelected:isSelected forView:getView()];
526 void QWidget::addToSuperview(NSView *superview)
528 KWQ_BLOCK_EXCEPTIONS;
531 NSView *subview = getOuterView();
532 ASSERT(![superview isDescendantOf:subview]);
533 if ([subview superview] != superview)
534 [superview addSubview:subview];
535 data->removeFromSuperviewSoon = false;
537 KWQ_UNBLOCK_EXCEPTIONS;
540 void QWidget::removeFromSuperview()
542 if (data->mustStayInWindow)
543 data->removeFromSuperviewSoon = true;
545 KWQ_BLOCK_EXCEPTIONS;
546 [getOuterView() removeFromSuperview];
547 KWQ_UNBLOCK_EXCEPTIONS;
548 data->removeFromSuperviewSoon = false;
552 void QWidget::beforeMouseDown(NSView *view)
554 ASSERT([view conformsToProtocol:@protocol(KWQWidgetHolder)]);
555 QWidget *widget = [(NSView <KWQWidgetHolder> *)view widget];
557 ASSERT(view == widget->getOuterView());
558 ASSERT(!widget->data->mustStayInWindow);
559 widget->data->mustStayInWindow = true;
563 void QWidget::afterMouseDown(NSView *view)
565 ASSERT([view conformsToProtocol:@protocol(KWQWidgetHolder)]);
566 QWidget *widget = [(NSView <KWQWidgetHolder> *)view widget];
568 KWQ_BLOCK_EXCEPTIONS;
569 [view removeFromSuperview];
570 KWQ_UNBLOCK_EXCEPTIONS;
572 ASSERT(widget->data->mustStayInWindow);
573 widget->data->mustStayInWindow = false;
574 if (widget->data->removeFromSuperviewSoon)
575 widget->removeFromSuperview();