1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 // This code strongly inspired by Miguel / Federico's Gnome Canvas demo code.
22 #include <sal/config.h>
24 #include <basegfx/polygon/b2dpolygon.hxx>
25 #include <basegfx/polygon/b2dpolygontools.hxx>
26 #include <basegfx/utils/canvastools.hxx>
27 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
28 #include <com/sun/star/rendering/CompositeOperation.hpp>
29 #include <com/sun/star/rendering/PathCapType.hpp>
30 #include <com/sun/star/rendering/PathJoinType.hpp>
31 #include <com/sun/star/rendering/RenderState.hpp>
32 #include <com/sun/star/rendering/ViewState.hpp>
33 #include <com/sun/star/rendering/XBitmap.hpp>
34 #include <com/sun/star/rendering/XCanvas.hpp>
35 #include <com/sun/star/rendering/XGraphicDevice.hpp>
36 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
37 #include <com/sun/star/uno/XComponentContext.hpp>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/random.hxx>
40 #include <cppuhelper/bootstrap.hxx>
41 #include <o3tl/safeint.hxx>
43 #include <vcl/canvastools.hxx>
44 #include <vcl/svapp.hxx>
45 #include <vcl/vclmain.hxx>
46 #include <vcl/wrkwin.hxx>
48 using namespace ::com::sun::star
;
50 static void PrintHelp()
52 fprintf( stdout
, "canvasdemo - Exercise the new canvas impl\n" );
57 class TestWindow
: public WorkWindow
60 TestWindow() : WorkWindow(nullptr, WB_APP
| WB_STDWORK
)
62 SetText("Canvas test");
63 SetSizePixel( Size( 600, 450 ) );
67 virtual ~TestWindow() override
{}
68 virtual void MouseButtonUp( const MouseEvent
& /*rMEvt*/ ) override
70 //TODO: do something cool
73 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
;
81 rendering::ViewState maViewState
;
82 rendering::RenderState maRenderState
;
83 uno::Sequence
< double > maColorBlack
;
84 uno::Sequence
< double > maColorRed
;
85 uno::Reference
< rendering::XCanvas
> mxCanvas
;
86 uno::Reference
< rendering::XCanvasFont
> mxDefaultFont
;
87 uno::Reference
< rendering::XGraphicDevice
> mxDevice
;
89 DemoRenderer( uno::Reference
< rendering::XGraphicDevice
> xDevice
,
90 uno::Reference
< rendering::XCanvas
> xCanvas
,
93 maColorBlack( vcl::unotools::colorToStdColorSpaceSequence( COL_BLACK
) ),
94 maColorRed( vcl::unotools::colorToStdColorSpaceSequence( COL_RED
) ),
96 mxDevice(std::move( xDevice
))
99 geometry::AffineMatrix2D
aUnit( 1,0, 0,
101 maViewState
.AffineTransform
= aUnit
;
102 maRenderState
.AffineTransform
= aUnit
;
103 maRenderState
.DeviceColor
= maColorBlack
;
105 //I can't figure out what the compositeoperation stuff does
106 //it doesn't seem to do anything in either VCL or cairocanvas
107 //I was hoping that CLEAR would clear the canvas before we paint,
108 //but nothing changes
109 maRenderState
.CompositeOperation
= rendering::CompositeOperation::OVER
;
111 maBox
.setWidth(aSize
.Width() / 3);
112 maBox
.setHeight(aSize
.Height() / 3);
114 lang::Locale aLocale
;
115 rendering::FontInfo aFontInfo
;
116 aFontInfo
.FamilyName
= "Swiss";
117 aFontInfo
.StyleName
= "SansSerif";
118 geometry::Matrix2D
aFontMatrix( 1, 0,
120 rendering::FontRequest
aFontRequest( aFontInfo
, 12.0, 0.0, aLocale
);
121 uno::Sequence
< beans::PropertyValue
> aExtraFontProperties
;
122 mxDefaultFont
= xCanvas
->createFont( aFontRequest
, aExtraFontProperties
, aFontMatrix
);
123 if( !mxDefaultFont
.is() )
124 fprintf( stderr
, "Failed to create font\n" );
129 tools::Long d
, dIncr
= maSize
.Width() / 3;
130 for ( d
= 0; d
<= maSize
.Width(); d
+= dIncr
)
131 mxCanvas
->drawLine( geometry::RealPoint2D( d
, 0 ),
132 geometry::RealPoint2D( d
, maSize
.Height() ),
133 maViewState
, maRenderState
);
134 dIncr
= maSize
.Height() / 3;
135 for ( d
= 0; d
<= maSize
.Height(); d
+= dIncr
)
136 mxCanvas
->drawLine( geometry::RealPoint2D( 0, d
),
137 geometry::RealPoint2D( maSize
.Width(), d
),
138 maViewState
, maRenderState
);
141 void drawStringAt( OString aString
, double x
, double y
)
143 rendering::StringContext aText
;
144 aText
.Text
= OStringToOUString( aString
, RTL_TEXTENCODING_UTF8
);
145 aText
.StartPosition
= 0;
146 aText
.Length
= aString
.getLength();
147 rendering::RenderState
aRenderState( maRenderState
);
148 aRenderState
.AffineTransform
.m02
+= x
;
149 aRenderState
.AffineTransform
.m12
+= y
;
151 mxCanvas
->drawText( aText
, mxDefaultFont
, maViewState
, aRenderState
, 0);
154 void drawRect( tools::Rectangle rRect
, const uno::Sequence
< double > &aColor
, int /*nWidth*/ )
156 uno::Sequence
< uno::Sequence
< geometry::RealPoint2D
> > aPolys
159 { o3tl::narrowing
<double>(rRect
.Left()), o3tl::narrowing
<double>(rRect
.Top()) },
160 { o3tl::narrowing
<double>(rRect
.Left()), o3tl::narrowing
<double>(rRect
.Bottom()) },
161 { o3tl::narrowing
<double>(rRect
.Right()), o3tl::narrowing
<double>(rRect
.Bottom()) },
162 { o3tl::narrowing
<double>(rRect
.Right()), o3tl::narrowing
<double>(rRect
.Top()) }
165 auto xPoly
= mxDevice
->createCompatibleLinePolyPolygon( aPolys
);
166 xPoly
->setClosed( 0, true );
168 rendering::RenderState
aRenderState( maRenderState
);
169 aRenderState
.DeviceColor
= aColor
;
170 mxCanvas
->drawPolyPolygon( xPoly
, maViewState
, aRenderState
);
173 void translate( double x
, double y
)
175 maRenderState
.AffineTransform
.m02
+= x
;
176 maRenderState
.AffineTransform
.m12
+= y
;
179 void drawPolishDiamond( double center_x
, double center_y
)
181 const int VERTICES
= 10;
182 const double RADIUS
= 60.0;
185 rendering::RenderState maOldRenderState
= maRenderState
; // push
186 translate( center_x
, center_y
);
188 for (i
= 0; i
< VERTICES
; i
++)
190 double a
= 2.0 * M_PI
* i
/ VERTICES
;
191 geometry::RealPoint2D
aSrc( RADIUS
* cos (a
), RADIUS
* sin (a
) );
193 for (j
= i
+ 1; j
< VERTICES
; j
++)
195 a
= 2.0 * M_PI
* j
/ VERTICES
;
197 // FIXME: set cap_style to 'ROUND'
198 mxCanvas
->drawLine( aSrc
,
199 geometry::RealPoint2D( RADIUS
* cos (a
),
201 maViewState
, maRenderState
);
205 maRenderState
= maOldRenderState
; // pop
208 void drawHilbert( double anchor_x
, double anchor_y
)
210 const double SCALE
=7.0;
211 const char hilbert
[] = "urdrrulurulldluuruluurdrurddldrrruluurdrurddldrddlulldrdldrrurd";
212 int nLength
= std::size( hilbert
);
214 uno::Sequence
< geometry::RealPoint2D
> aPoints( nLength
);
215 auto pPoints
= aPoints
.getArray();
216 uno::Reference
< rendering::XLinePolyPolygon2D
> xPoly
;
218 pPoints
[0] = geometry::RealPoint2D( anchor_x
, anchor_y
);
219 for (int i
= 0; i
< nLength
; i
++ )
224 pPoints
[i
+1] = geometry::RealPoint2D( aPoints
[i
].X
,
225 aPoints
[i
].Y
- SCALE
);
228 pPoints
[i
+1] = geometry::RealPoint2D( aPoints
[i
].X
,
229 aPoints
[i
].Y
+ SCALE
);
232 pPoints
[i
+1] = geometry::RealPoint2D( aPoints
[i
].X
- SCALE
,
236 pPoints
[i
+1] = geometry::RealPoint2D( aPoints
[i
].X
+ SCALE
,
242 uno::Sequence
< uno::Sequence
< geometry::RealPoint2D
> > aPolys
{ aPoints
};
244 xPoly
= mxDevice
->createCompatibleLinePolyPolygon( aPolys
);
245 xPoly
->setClosed( 0, false );
247 rendering::RenderState
aRenderState( maRenderState
);
248 aRenderState
.DeviceColor
= maColorRed
;
249 // aRenderState.DeviceColor[3] = 0.5;
250 rendering::StrokeAttributes aStrokeAttrs
;
251 aStrokeAttrs
.StrokeWidth
= 4.0;
252 aStrokeAttrs
.MiterLimit
= 2.0; // ?
253 aStrokeAttrs
.StartCapType
= rendering::PathCapType::BUTT
;
254 aStrokeAttrs
.EndCapType
= rendering::PathCapType::BUTT
;
255 aStrokeAttrs
.JoinType
= rendering::PathJoinType::MITER
;
256 //fprintf( stderr, "FIXME: stroking a tools::PolyPolygon doesn't show up\n" );
258 mxCanvas
->strokePolyPolygon( xPoly
, maViewState
, aRenderState
, aStrokeAttrs
);
259 // FIXME: do this instead:
260 //mxCanvas->drawPolyPolygon( xPoly, maViewState, aRenderState );
263 void drawTitle( OString aTitle
)
265 // FIXME: text anchoring to be done
266 double nStringWidth
= aTitle
.getLength() * 8.0;
267 drawStringAt ( aTitle
, (maBox
.Width() - nStringWidth
) / 2, 15 );
270 void drawRectangles()
272 rendering::RenderState maOldRenderState
= maRenderState
; // push
274 drawTitle( OString( "Rectangles" ) );
276 drawRect( tools::Rectangle( 20, 30, 70, 60 ), maColorRed
, 8 );
277 // color mediumseagreen, stipple fill, outline black
278 drawRect( tools::Rectangle( 90, 40, 180, 100 ), maColorBlack
, 4 );
279 // color steelblue, filled, no outline
280 drawRect( tools::Rectangle( 10, 80, 80, 140 ), maColorBlack
, 1 );
282 maRenderState
= maOldRenderState
; // pop
287 rendering::RenderState maOldRenderState
= maRenderState
; // push
288 translate( maBox
.Width(), 0.0 );
290 drawTitle( OString( "Ellipses" ) );
292 const basegfx::B2DPoint
aCenter( maBox
.Width()*.5,
294 const basegfx::B2DPoint
aRadii( maBox
.Width()*.3,
296 const basegfx::B2DPolygon
& rEllipse(
297 basegfx::utils::createPolygonFromEllipse( aCenter
,
301 uno::Reference
< rendering::XPolyPolygon2D
> xPoly(
302 basegfx::unotools::xPolyPolygonFromB2DPolygon(mxDevice
,
305 rendering::StrokeAttributes aStrokeAttrs
;
306 aStrokeAttrs
.StrokeWidth
= 4.0;
307 aStrokeAttrs
.MiterLimit
= 2.0; // ?
308 aStrokeAttrs
.StartCapType
= rendering::PathCapType::BUTT
;
309 aStrokeAttrs
.EndCapType
= rendering::PathCapType::BUTT
;
310 aStrokeAttrs
.JoinType
= rendering::PathJoinType::MITER
;
311 mxCanvas
->strokePolyPolygon( xPoly
, maViewState
, maRenderState
, aStrokeAttrs
);
313 maRenderState
= maOldRenderState
; // pop
318 rendering::RenderState maOldRenderState
= maRenderState
; // push
319 translate( maBox
.Width() * 2.0, 0.0 );
321 drawTitle( OString( "Text" ) );
324 maBox
.Height() * .5 );
325 drawTitle( OString( "This is lame" ) );
327 maRenderState
= maOldRenderState
; // pop
332 rendering::RenderState maOldRenderState
= maRenderState
; // push
333 translate( 0.0, maBox
.Height() );
335 drawTitle( OString( "Images" ) );
337 uno::Reference
< rendering::XBitmap
> xBitmap(mxCanvas
, uno::UNO_QUERY
);
342 translate( maBox
.Width()*0.1, maBox
.Height()*0.2 );
343 maRenderState
.AffineTransform
.m00
*= 4.0/15;
344 maRenderState
.AffineTransform
.m11
*= 3.0/15;
346 mxCanvas
->drawBitmap(xBitmap
, maViewState
, maRenderState
);
348 // uno::Reference< rendering::XBitmap > xBitmap2( xBitmap->getScaledBitmap(geometry::RealSize2D(48, 48), false) );
349 // mxCanvas->drawBitmap(xBitmap2, maViewState, maRenderState); //yes, but where?
351 //called CanvasHelper::getScaledBitmap, we return NULL, TODO
352 //Exception 'BitmapEx vclcanvas::tools::bitmapExFromXBitmap(const css::uno::Reference<css::rendering::XBitmap>&),
353 //bitmapExFromXBitmap(): could not extract BitmapEx' thrown
356 //Exception 'BitmapEx vclcanvas::tools::bitmapExFromXBitmap(const css::uno::Reference<css::rendering::XBitmap>&),
357 //bitmapExFromXBitmap(): could not extract bitmap' thrown
358 // Thorsten says that this is a bug, and Thorsten never lies.
360 maRenderState
= maOldRenderState
; // pop
365 rendering::RenderState maOldRenderState
= maRenderState
; // push
366 translate( maBox
.Width(), maBox
.Height() );
368 drawTitle( OString( "Lines" ) );
370 drawPolishDiamond( 70.0, 80.0 );
371 drawHilbert( 140.0, 140.0 );
373 maRenderState
= maOldRenderState
; // pop
378 rendering::RenderState maOldRenderState
= maRenderState
; // push
379 translate( maBox
.Width() * 2.0, maBox
.Height() );
381 drawTitle( OString( "Curves" ) );
383 translate( maBox
.Width() * .5, maBox
.Height() * .5 );
385 const double r
= 30.0;
386 const int num_curves
= 3;
389 uno::Sequence
< geometry::RealBezierSegment2D
> aBeziers (num_curves
);
390 auto pBeziers
= aBeziers
.getArray();
391 uno::Reference
< rendering::XBezierPolyPolygon2D
> xPoly
;
393 for (int i
= 0; i
< num_curves
; i
++)
394 pBeziers
[i
]= geometry::RealBezierSegment2D( r
* cos(i
*2*M_PI
/num_curves
), //Px
395 r
* sin(i
*2*M_PI
/num_curves
), //py
396 r
* 2 * cos((i
*2*M_PI
+ 2*M_PI
)/num_curves
), //C1x
397 r
* 2 * sin((i
*2*M_PI
+ 2*M_PI
)/num_curves
), //C1y
398 r
* 2 * cos((i
*2*M_PI
+ 2*M_PI
)/num_curves
), //C2x
399 r
* 2 * sin((i
*2*M_PI
+ 2*M_PI
)/num_curves
)); //C2y
400 uno::Sequence
< uno::Sequence
< geometry::RealBezierSegment2D
> > aPolys
{ aBeziers
};
401 xPoly
= mxDevice
->createCompatibleBezierPolyPolygon(aPolys
);
402 xPoly
->setClosed( 0, true );
403 //uno::Reference< rendering::XBezierPolyPolygon2D> xPP( xPoly, uno::UNO_QUERY );
404 //compiles, but totally screws up. I think it is interpreting the bezier as a line
406 rendering::StrokeAttributes aStrokeAttrs
;
407 aStrokeAttrs
.StrokeWidth
= 4.0;
408 aStrokeAttrs
.MiterLimit
= 2.0; // ?
409 aStrokeAttrs
.StartCapType
= rendering::PathCapType::BUTT
;
410 aStrokeAttrs
.EndCapType
= rendering::PathCapType::BUTT
;
411 aStrokeAttrs
.JoinType
= rendering::PathJoinType::MITER
;
412 mxCanvas
->strokePolyPolygon( xPoly
, maViewState
, maRenderState
, aStrokeAttrs
);
413 //you can't draw a BezierPolyPolygon2D with this, even though it is derived from it
414 //mxCanvas->drawPolyPolygon( xPoly, maViewState, maRenderState );
416 maRenderState
= maOldRenderState
; // pop
421 return comphelper::rng::uniform_real_distribution(0, 100);
426 rendering::RenderState maOldRenderState
= maRenderState
; // push
427 translate( 0.0, maBox
.Height() * 2.0 );
429 drawTitle( OString( "Arcs" ) );
433 //This stuff doesn't belong here, but probably in curves
434 //This stuff doesn't work in VCL b/c vcl doesn't do beziers
435 //Hah! Every time the window redraws, we do this
441 for (int i
= 0; i
< 1; i
++)
451 double c1x
= gimmerand();
452 double c1y
= gimmerand();
453 double c2x
= gimmerand();
454 double c2y
= gimmerand();
455 maRenderState
.DeviceColor
= maColorRed
;
456 mxCanvas
->drawLine(geometry::RealPoint2D(ax
, ay
), geometry::RealPoint2D(c1x
, c1y
), maViewState
, maRenderState
);
457 mxCanvas
->drawLine(geometry::RealPoint2D(c1x
, c1y
), geometry::RealPoint2D(c2x
, c2y
), maViewState
, maRenderState
);
458 mxCanvas
->drawLine(geometry::RealPoint2D(bx
, by
), geometry::RealPoint2D(c2x
, c2y
), maViewState
, maRenderState
);
460 geometry::RealBezierSegment2D
aBezierSegment(
468 geometry::RealPoint2D
aEndPoint(bx
, by
);
469 maRenderState
.DeviceColor
= maColorBlack
;
470 mxCanvas
->drawBezier(
473 maViewState
, maRenderState
);
475 maRenderState
= maOldRenderState
; // pop
479 void drawRegularPolygon(double centerx
, double centery
, int sides
, double r
)
482 uno::Sequence
< geometry::RealPoint2D
> aPoints (sides
);
483 auto pPoints
= aPoints
.getArray();
484 uno::Reference
< rendering::XLinePolyPolygon2D
> xPoly
;
486 for (int i
= 0; i
< sides
; i
++)
488 pPoints
[i
]= geometry::RealPoint2D( centerx
+ r
* cos(i
*2 * M_PI
/sides
),
489 centery
+ r
* sin(i
*2 * M_PI
/sides
));
491 uno::Sequence
< uno::Sequence
< geometry::RealPoint2D
> > aPolys
{ aPoints
};
492 xPoly
= mxDevice
->createCompatibleLinePolyPolygon( aPolys
);
493 xPoly
->setClosed( 0, true );
494 rendering::RenderState
aRenderState( maRenderState
);
495 aRenderState
.DeviceColor
= maColorRed
;
496 mxCanvas
->drawPolyPolygon( xPoly
, maViewState
, aRenderState
);
497 mxCanvas
->fillPolyPolygon( xPoly
,
504 rendering::RenderState maOldRenderState
= maRenderState
; // push
505 translate( maBox
.Width() * 1.0, maBox
.Height() * 2.0 );
507 drawTitle( OString( "Polygons" ) );
510 for (int i
= 1; i
<= 4; i
++)
512 drawRegularPolygon(35*i
, 35, sides
, 15);
516 maRenderState
= maOldRenderState
; // pop
519 void drawWidgets() // FIXME: prolly makes no sense
521 rendering::RenderState maOldRenderState
= maRenderState
; // push
522 translate( maBox
.Width() * 2.0, maBox
.Height() * 2.0 );
524 drawTitle( OString( "Widgets" ) );
526 maRenderState
= maOldRenderState
; // pop
532 void TestWindow::Paint(vcl::RenderContext
&, const tools::Rectangle
&)
536 uno::Reference
< rendering::XCanvas
> xVDevCanvas( GetOutDev()->GetCanvas(),
537 uno::UNO_SET_THROW
);
538 uno::Reference
< rendering::XGraphicDevice
> xVDevDevice( xVDevCanvas
->getDevice(),
539 uno::UNO_SET_THROW
);
540 DemoRenderer
aVDevRenderer( xVDevDevice
, xVDevCanvas
, GetSizePixel());
541 xVDevCanvas
->clear();
542 aVDevRenderer
.drawGrid();
543 aVDevRenderer
.drawRectangles();
544 aVDevRenderer
.drawEllipses();
545 aVDevRenderer
.drawText();
546 aVDevRenderer
.drawLines();
547 aVDevRenderer
.drawCurves();
548 aVDevRenderer
.drawArcs();
549 aVDevRenderer
.drawPolygons();
551 uno::Reference
< rendering::XCanvas
> xCanvas( GetOutDev()->GetSpriteCanvas(),
552 uno::UNO_QUERY_THROW
);
553 uno::Reference
< rendering::XGraphicDevice
> xDevice( xCanvas
->getDevice(),
554 uno::UNO_SET_THROW
);
556 DemoRenderer
aRenderer( xDevice
, xCanvas
, GetSizePixel() );
558 aRenderer
.drawGrid();
559 aRenderer
.drawRectangles();
560 aRenderer
.drawEllipses();
561 aRenderer
.drawText();
562 aRenderer
.drawLines();
563 aRenderer
.drawCurves();
564 aRenderer
.drawArcs();
565 aRenderer
.drawPolygons();
566 aRenderer
.drawWidgets();
567 aRenderer
.drawImages();
569 // check whether virdev actually contained something
570 uno::Reference
< rendering::XBitmap
> xBitmap(xVDevCanvas
, uno::UNO_QUERY
);
574 aRenderer
.maRenderState
.AffineTransform
.m02
+= 100;
575 aRenderer
.maRenderState
.AffineTransform
.m12
+= 100;
576 xCanvas
->drawBitmap(xBitmap
, aRenderer
.maViewState
, aRenderer
.maRenderState
);
578 uno::Reference
< rendering::XSpriteCanvas
> xSpriteCanvas( xCanvas
,
580 if( xSpriteCanvas
.is() )
581 xSpriteCanvas
->updateScreen( true ); // without
586 catch (const uno::Exception
&e
)
588 fprintf( stderr
, "Exception '%s' thrown\n" ,
589 OUStringToOString( e
.Message
, RTL_TEXTENCODING_UTF8
).getStr() );
595 class DemoApp
: public Application
598 virtual int Main() override
;
599 virtual void Exception(ExceptionCategory nCategory
) override
;
602 void Init() override
;
603 void DeInit() override
;
612 for( unsigned int i
= 0; i
< GetCommandLineParamCount(); i
++ )
614 OUString aParam
= GetCommandLineParam( i
);
616 if( aParam
== "--help" || aParam
== "-h" )
626 ScopedVclPtr
<TestWindow
> aWindow
= VclPtr
<TestWindow
>::Create();
629 Application::Execute();
633 void DemoApp::Exception( ExceptionCategory
)
641 uno::Reference
<uno::XComponentContext
> xComponentContext
642 = ::cppu::defaultBootstrap_InitialComponentContext();
643 uno::Reference
<lang::XMultiServiceFactory
> xMSF
;
644 xMSF
.set(xComponentContext
->getServiceManager(), uno::UNO_QUERY
);
646 Application::Abort("Bootstrap failure - no service manager");
648 ::comphelper::setProcessServiceFactory(xMSF
);
650 catch (const uno::Exception
&e
)
652 Application::Abort("Bootstrap exception " + e
.Message
);
656 void DemoApp::DeInit()
658 uno::Reference
< lang::XComponent
>(
659 comphelper::getProcessComponentContext(),
660 uno::UNO_QUERY_THROW
)-> dispose();
661 ::comphelper::setProcessServiceFactory(nullptr);
664 void vclmain::createApplication()
670 // - bouncing clip-rectangle mode - bounce a clip-rect around the window...
671 // - complete all of pre-existing canvas bits
672 // - affine transform tweakage...
674 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */