1/*
2 * Copyright 2007 Zack Rusin <zack@kde.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include "glapplet.h"
21
22#include <QtOpenGL/QGLPixelBuffer>
23#include <QtGui/QPainter>
24#include <QtGui/QImage>
25
26namespace Plasma {
27
28class GLAppletPrivate
29{
30public:
31 GLAppletPrivate()
32 {
33 init();
34 }
35 ~GLAppletPrivate()
36 {
37 delete pbuf;
38 delete dummy;
39 }
40 void init()
41 {
42 dummy = new QGLWidget((QWidget *) 0);
43 QGLFormat format = QGLFormat::defaultFormat();
44 format.setSampleBuffers(true);
45 format.setAlphaBufferSize(8);
46 //dummy size construction
47 pbuf = new QGLPixelBuffer(300, 300, format, dummy);
48 if (pbuf->isValid()) {
49 pbuf->makeCurrent();
50 }
51 }
52 void updateGlSize(const QSize &size)
53 {
54 if (size.width() > pbuf->width() ||
55 size.height() > pbuf->height()) {
56 QGLFormat format = pbuf->format();
57 delete pbuf;
58 pbuf = new QGLPixelBuffer(size, format, dummy);
59 }
60 }
61
62public:
63 QGLPixelBuffer *pbuf;
64 QGLWidget *dummy;
65};
66
67GLApplet::GLApplet(QGraphicsItem *parent,
68 const QString &serviceId,
69 int appletId)
70 : Applet(parent, serviceId, appletId),
71 d(new GLAppletPrivate)
72{
73 if (!d->dummy->isValid() ||
74 !QGLPixelBuffer::hasOpenGLPbuffers() ||
75 !d->pbuf->isValid()) {
76 setFailedToLaunch(true, i18n("This system does not support OpenGL widgets."));
77 }
78}
79
80GLApplet::GLApplet(QObject *parent, const QVariantList &args)
81 : Applet(parent, args),
82 d(new GLAppletPrivate)
83{
84 if (!d->dummy->isValid() ||
85 !QGLPixelBuffer::hasOpenGLPbuffers() ||
86 !d->pbuf->isValid()) {
87 setFailedToLaunch(true, i18n("This system does not support OpenGL widgets."));
88 }
89}
90
91GLApplet::~GLApplet()
92{
93 delete d;
94}
95
96GLuint GLApplet::bindTexture(const QImage &image, GLenum target)
97{
98 Q_ASSERT(d->pbuf);
99 if (!d->dummy->isValid()) {
100 return 0;
101 }
102 return d->dummy->bindTexture(image, target);
103}
104
105void GLApplet::deleteTexture(GLuint textureId)
106{
107 Q_ASSERT(d->pbuf);
108 d->dummy->deleteTexture(textureId);
109}
110
111void GLApplet::paintGLInterface(QPainter *painter,
112 const QStyleOptionGraphicsItem *option)
113{
114 Q_UNUSED(painter)
115 Q_UNUSED(option)
116}
117
118static inline QPainterPath headerPath(const QRectF &r, int roundness,
119 int headerHeight=10)
120{
121 QPainterPath path;
122 int xRnd = roundness;
123 int yRnd = roundness;
124 if (r.width() > r.height()) {
125 xRnd = int(roundness * r.height() / r.width());
126 } else {
127 yRnd = int(roundness * r.width() / r.height());
128 }
129
130 if(xRnd >= 100) { // fix ranges
131 xRnd = 99;
132 }
133 if(yRnd >= 100) {
134 yRnd = 99;
135 }
136 if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
137 path.addRect(r);
138 return path;
139 }
140
141 QRectF rect = r.normalized();
142
143 if (rect.isNull()) {
144 return path;
145 }
146
147 qreal x = rect.x();
148 qreal y = rect.y();
149 qreal w = rect.width();
150 qreal h = rect.height();
151 qreal rxx = w * xRnd / 200;
152 qreal ryy = h * yRnd / 200;
153 // were there overflows?
154 if (rxx < 0) {
155 rxx = w / 200 * xRnd;
156 }
157 if (ryy < 0) {
158 ryy = h / 200 * yRnd;
159 }
160 qreal rxx2 = 2 * rxx;
161 qreal ryy2 = 2 * ryy;
162
163 path.arcMoveTo(x, y, rxx2, ryy2, 90);
164 path.arcTo(x, y, rxx2, ryy2, 90, 90);
165 QPointF pt = path.currentPosition();
166 path.lineTo(x, pt.y() + headerHeight);
167 path.lineTo(x + w, pt.y() + headerHeight);
168 path.lineTo(x + w, pt.y());
169 path.arcTo(x + w - rxx2, y, rxx2, ryy2, 0, 90);
170 path.closeSubpath();
171
172 return path;
173}
174
175void GLApplet::paintInterface(QPainter *painter,
176 const QStyleOptionGraphicsItem *option,
177 const QRect &contentsRect)
178{
179 Q_UNUSED(contentsRect)
180 Q_ASSERT(d->pbuf);
181 if ((!d->dummy->isValid() ||
182 !d->pbuf->isValid())) {
183 if (!hasFailedToLaunch()) {
184 setFailedToLaunch(true, i18n("Your machine does not support OpenGL widgets."));
185 }
186
187 return;
188 }
189 d->pbuf->makeCurrent();
190
191 QMatrix m = painter->worldMatrix();
192 QRect deviceRect = m.mapRect(QRect(QPoint(23, 25), boundingRect().size().toSize()));
193 d->updateGlSize(deviceRect.size());
194
195 // redirect this widget's painting into the pbuffer
196 QPainter p(d->pbuf);
197 paintGLInterface(&p, option);
198
199 // draw the pbuffer contents to the backingstore
200 QImage image = d->pbuf->toImage();
201 painter->drawImage(0, 0, image);
202}
203
204void GLApplet::makeCurrent()
205{
206 if (!d->dummy->isValid() || !d->pbuf->isValid()) {
207 d->dummy->makeCurrent();
208 }
209}
210
211} // Plasma namespace
212
213#include "glapplet.moc"
214