summaryrefslogtreecommitdiff
path: root/vcl/aqua
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/aqua')
-rw-r--r--vcl/aqua/inc/aqua11yfactory.h47
-rw-r--r--vcl/aqua/inc/aqua11yfocustracker.hxx108
-rw-r--r--vcl/aqua/inc/aqua11ylistener.hxx65
-rw-r--r--vcl/aqua/inc/aqua11ywrapper.h119
-rwxr-xr-xvcl/aqua/inc/aquaprintview.h67
-rw-r--r--vcl/aqua/inc/aquavclevents.hxx96
-rw-r--r--vcl/aqua/inc/aquavcltypes.h36
-rw-r--r--vcl/aqua/inc/keyboardfocuslistener.hxx47
-rw-r--r--vcl/aqua/inc/salatsuifontutils.hxx63
-rw-r--r--vcl/aqua/inc/salbmp.h107
-rwxr-xr-xvcl/aqua/inc/salcolorutils.hxx52
-rwxr-xr-xvcl/aqua/inc/salconst.h68
-rw-r--r--vcl/aqua/inc/saldata.hxx138
-rw-r--r--vcl/aqua/inc/salfontutils.hxx66
-rw-r--r--vcl/aqua/inc/salframe.h220
-rwxr-xr-xvcl/aqua/inc/salframeview.h208
-rw-r--r--vcl/aqua/inc/salgdi.h417
-rw-r--r--vcl/aqua/inc/salinst.h202
-rwxr-xr-xvcl/aqua/inc/salmathutils.hxx87
-rw-r--r--vcl/aqua/inc/salmenu.h121
-rwxr-xr-xvcl/aqua/inc/salnativewidgets.h71
-rwxr-xr-xvcl/aqua/inc/salnsmenu.h68
-rwxr-xr-xvcl/aqua/inc/salnstimer.h40
-rw-r--r--vcl/aqua/inc/salobj.h86
-rw-r--r--vcl/aqua/inc/salprn.h171
-rw-r--r--vcl/aqua/inc/salsys.h70
-rw-r--r--vcl/aqua/inc/saltimer.h54
-rw-r--r--vcl/aqua/inc/salvd.h94
-rw-r--r--vcl/aqua/inc/svsys.h35
-rwxr-xr-xvcl/aqua/inc/vclnsapp.h70
-rw-r--r--vcl/aqua/source/a11y/aqua11yactionwrapper.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11yactionwrapper.mm83
-rw-r--r--vcl/aqua/source/a11y/aqua11ycomponentwrapper.h45
-rw-r--r--vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm110
-rw-r--r--vcl/aqua/source/a11y/aqua11yfactory.mm198
-rw-r--r--vcl/aqua/source/a11y/aqua11yfocuslistener.cxx118
-rw-r--r--vcl/aqua/source/a11y/aqua11yfocuslistener.hxx62
-rw-r--r--vcl/aqua/source/a11y/aqua11yfocustracker.cxx278
-rw-r--r--vcl/aqua/source/a11y/aqua11ylistener.cxx158
-rw-r--r--vcl/aqua/source/a11y/aqua11yrolehelper.h42
-rw-r--r--vcl/aqua/source/a11y/aqua11yrolehelper.mm272
-rw-r--r--vcl/aqua/source/a11y/aqua11yselectionwrapper.h43
-rw-r--r--vcl/aqua/source/a11y/aqua11yselectionwrapper.mm91
-rw-r--r--vcl/aqua/source/a11y/aqua11ytablewrapper.h44
-rw-r--r--vcl/aqua/source/a11y/aqua11ytablewrapper.mm211
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm254
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextwrapper.h64
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextwrapper.mm289
-rw-r--r--vcl/aqua/source/a11y/aqua11yutil.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11yutil.mm53
-rw-r--r--vcl/aqua/source/a11y/aqua11yvaluewrapper.h46
-rw-r--r--vcl/aqua/source/a11y/aqua11yvaluewrapper.mm95
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapper.mm1142
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperbutton.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperbutton.mm61
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercheckbox.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm65
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercombobox.h50
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercombobox.mm161
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappergroup.h40
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappergroup.mm57
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperlist.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperlist.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm65
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperrow.h40
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperrow.mm56
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm84
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm49
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappersplitter.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappersplitter.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperstatictext.h40
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm56
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertabgroup.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm50
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertextarea.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertextarea.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertoolbar.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm50
-rw-r--r--vcl/aqua/source/a11y/documentfocuslistener.cxx253
-rw-r--r--vcl/aqua/source/a11y/documentfocuslistener.hxx101
-rw-r--r--vcl/aqua/source/a11y/makefile.mk88
-rw-r--r--vcl/aqua/source/a11y/readme.txt8
-rw-r--r--vcl/aqua/source/app/makefile.mk63
-rw-r--r--vcl/aqua/source/app/saldata.cxx293
-rw-r--r--vcl/aqua/source/app/salinst.cxx1313
-rwxr-xr-xvcl/aqua/source/app/salnstimer.mm56
-rw-r--r--vcl/aqua/source/app/salsys.cxx131
-rw-r--r--vcl/aqua/source/app/saltimer.cxx135
-rwxr-xr-xvcl/aqua/source/app/vclnsapp.mm518
-rw-r--r--vcl/aqua/source/dtrans/DataFlavorMapping.cxx732
-rw-r--r--vcl/aqua/source/dtrans/DataFlavorMapping.hxx143
-rw-r--r--vcl/aqua/source/dtrans/DragActionConversion.cxx92
-rw-r--r--vcl/aqua/source/dtrans/DragActionConversion.hxx46
-rw-r--r--vcl/aqua/source/dtrans/DragSource.cxx363
-rw-r--r--vcl/aqua/source/dtrans/DragSource.hxx140
-rw-r--r--vcl/aqua/source/dtrans/DragSourceContext.cxx74
-rw-r--r--vcl/aqua/source/dtrans/DragSourceContext.hxx72
-rw-r--r--vcl/aqua/source/dtrans/DropTarget.cxx599
-rw-r--r--vcl/aqua/source/dtrans/DropTarget.hxx169
-rw-r--r--vcl/aqua/source/dtrans/HtmlFmtFlt.cxx147
-rw-r--r--vcl/aqua/source/dtrans/HtmlFmtFlt.hxx20
-rw-r--r--vcl/aqua/source/dtrans/OSXTransferable.cxx215
-rw-r--r--vcl/aqua/source/dtrans/OSXTransferable.hxx100
-rw-r--r--vcl/aqua/source/dtrans/PictToBmpFlt.cxx201
-rw-r--r--vcl/aqua/source/dtrans/PictToBmpFlt.hxx37
-rw-r--r--vcl/aqua/source/dtrans/aqua_clipboard.cxx387
-rw-r--r--vcl/aqua/source/dtrans/aqua_clipboard.hxx181
-rw-r--r--vcl/aqua/source/dtrans/aqua_service.cxx108
-rw-r--r--vcl/aqua/source/dtrans/makefile.mk68
-rw-r--r--vcl/aqua/source/dtrans/service_entry.cxx64
-rw-r--r--vcl/aqua/source/dtrans/test_aquacb.cxx208
-rw-r--r--vcl/aqua/source/gdi/aquaprintaccessoryview.mm1241
-rwxr-xr-xvcl/aqua/source/gdi/aquaprintview.mm82
-rw-r--r--vcl/aqua/source/gdi/makefile.mk74
-rwxr-xr-xvcl/aqua/source/gdi/salatslayout.cxx1264
-rw-r--r--vcl/aqua/source/gdi/salatsuifontutils.cxx552
-rw-r--r--vcl/aqua/source/gdi/salbmp.cxx904
-rwxr-xr-xvcl/aqua/source/gdi/salcolorutils.cxx50
-rw-r--r--vcl/aqua/source/gdi/salgdi.cxx2672
-rwxr-xr-xvcl/aqua/source/gdi/salgdiutils.cxx300
-rwxr-xr-xvcl/aqua/source/gdi/salmathutils.cxx163
-rw-r--r--vcl/aqua/source/gdi/salnativewidgets.cxx1527
-rw-r--r--vcl/aqua/source/gdi/salprn.cxx875
-rw-r--r--vcl/aqua/source/gdi/salvd.cxx236
-rw-r--r--vcl/aqua/source/res/MainMenu.nib/classes.nib4
-rw-r--r--vcl/aqua/source/res/MainMenu.nib/info.nib21
-rw-r--r--vcl/aqua/source/res/MainMenu.nib/keyedobjects.nibbin0 -> 3615 bytes
-rw-r--r--vcl/aqua/source/res/cursors/airbrush.pngbin0 -> 253 bytes
-rw-r--r--vcl/aqua/source/res/cursors/ase.pngbin0 -> 214 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asn.pngbin0 -> 212 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asne.pngbin0 -> 240 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asns.pngbin0 -> 234 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asnswe.pngbin0 -> 285 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asnw.pngbin0 -> 246 bytes
-rw-r--r--vcl/aqua/source/res/cursors/ass.pngbin0 -> 222 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asse.pngbin0 -> 243 bytes
-rw-r--r--vcl/aqua/source/res/cursors/assw.pngbin0 -> 236 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asw.pngbin0 -> 212 bytes
-rw-r--r--vcl/aqua/source/res/cursors/aswe.pngbin0 -> 228 bytes
-rw-r--r--vcl/aqua/source/res/cursors/chain.pngbin0 -> 344 bytes
-rw-r--r--vcl/aqua/source/res/cursors/chainnot.pngbin0 -> 390 bytes
-rw-r--r--vcl/aqua/source/res/cursors/chart.pngbin0 -> 270 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copydata.pngbin0 -> 336 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copydlnk.pngbin0 -> 340 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copyf.pngbin0 -> 329 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copyf2.pngbin0 -> 344 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copyflnk.pngbin0 -> 339 bytes
-rw-r--r--vcl/aqua/source/res/cursors/crook.pngbin0 -> 291 bytes
-rw-r--r--vcl/aqua/source/res/cursors/crop.pngbin0 -> 239 bytes
-rw-r--r--vcl/aqua/source/res/cursors/darc.pngbin0 -> 172 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dbezier.pngbin0 -> 185 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dcapt.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dcirccut.pngbin0 -> 185 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dconnect.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dellipse.pngbin0 -> 176 bytes
-rw-r--r--vcl/aqua/source/res/cursors/detectiv.pngbin0 -> 268 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dfree.pngbin0 -> 188 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dline.pngbin0 -> 177 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dpie.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dpolygon.pngbin0 -> 191 bytes
-rw-r--r--vcl/aqua/source/res/cursors/drect.pngbin0 -> 172 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dtext.pngbin0 -> 174 bytes
-rw-r--r--vcl/aqua/source/res/cursors/fill.pngbin0 -> 255 bytes
-rw-r--r--vcl/aqua/source/res/cursors/help.pngbin0 -> 303 bytes
-rw-r--r--vcl/aqua/source/res/cursors/hourglass.pngbin0 -> 246 bytes
-rw-r--r--vcl/aqua/source/res/cursors/hshear.pngbin0 -> 223 bytes
-rw-r--r--vcl/aqua/source/res/cursors/linkdata.pngbin0 -> 348 bytes
-rw-r--r--vcl/aqua/source/res/cursors/linkf.pngbin0 -> 336 bytes
-rw-r--r--vcl/aqua/source/res/cursors/magnify.pngbin0 -> 282 bytes
-rw-r--r--vcl/aqua/source/res/cursors/mirror.pngbin0 -> 304 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movebw.pngbin0 -> 320 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movedata.pngbin0 -> 290 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movedlnk.pngbin0 -> 318 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movef.pngbin0 -> 294 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movef2.pngbin0 -> 314 bytes
-rw-r--r--vcl/aqua/source/res/cursors/moveflnk.pngbin0 -> 307 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movept.pngbin0 -> 275 bytes
-rw-r--r--vcl/aqua/source/res/cursors/neswsize.pngbin0 -> 312 bytes
-rw-r--r--vcl/aqua/source/res/cursors/notallow.pngbin0 -> 297 bytes
-rw-r--r--vcl/aqua/source/res/cursors/nullptr.pngbin0 -> 150 bytes
-rw-r--r--vcl/aqua/source/res/cursors/nwsesize.pngbin0 -> 313 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pen.pngbin0 -> 351 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotcol.pngbin0 -> 293 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotdel.pngbin0 -> 264 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotfld.pngbin0 -> 272 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotrow.pngbin0 -> 295 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pntbrsh.pngbin0 -> 268 bytes
-rw-r--r--vcl/aqua/source/res/cursors/rotate.pngbin0 -> 274 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblsele.pngbin0 -> 174 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblsels.pngbin0 -> 171 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblselse.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblselsw.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblselw.pngbin0 -> 174 bytes
-rw-r--r--vcl/aqua/source/res/cursors/timemove.pngbin0 -> 249 bytes
-rw-r--r--vcl/aqua/source/res/cursors/timesize.pngbin0 -> 241 bytes
-rw-r--r--vcl/aqua/source/res/cursors/vshear.pngbin0 -> 228 bytes
-rw-r--r--vcl/aqua/source/res/cursors/vtext.pngbin0 -> 162 bytes
-rw-r--r--vcl/aqua/source/res/delzip0
-rw-r--r--vcl/aqua/source/res/makefile.mk54
-rw-r--r--vcl/aqua/source/window/makefile.mk63
-rw-r--r--vcl/aqua/source/window/salframe.cxx1636
-rwxr-xr-xvcl/aqua/source/window/salframeview.mm1609
-rw-r--r--vcl/aqua/source/window/salmenu.cxx958
-rwxr-xr-xvcl/aqua/source/window/salnsmenu.mm213
-rw-r--r--vcl/aqua/source/window/salobj.cxx239
211 files changed, 30325 insertions, 0 deletions
diff --git a/vcl/aqua/inc/aqua11yfactory.h b/vcl/aqua/inc/aqua11yfactory.h
new file mode 100644
index 000000000000..1982093f8bba
--- /dev/null
+++ b/vcl/aqua/inc/aqua11yfactory.h
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11FACTORY_H
+#define _SV_AQUA11FACTORY_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+@interface AquaA11yFactory : NSObject
+{
+}
++(void)insertIntoWrapperRepository: (NSView *) viewElement forAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
++(AquaA11yWrapper *)wrapperForAccessible: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessible >) rxAccessible;
++(AquaA11yWrapper *)wrapperForAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
++(AquaA11yWrapper *)wrapperForAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate;
++(AquaA11yWrapper *)wrapperForAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate asRadioGroup:(MacOSBOOL) asRadioGroup;
++(void)removeFromWrapperRepositoryFor: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
++(void)registerView: (NSView *) theView;
++(void)revokeView: (NSView *) theViewt;
+@end
+#endif // _SV_AQUA11FACTORY_H
diff --git a/vcl/aqua/inc/aqua11yfocustracker.hxx b/vcl/aqua/inc/aqua11yfocustracker.hxx
new file mode 100644
index 000000000000..1dbf68c4a5ef
--- /dev/null
+++ b/vcl/aqua/inc/aqua11yfocustracker.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _AQUA11YFOCUSTRACKER_HXX_
+#define _AQUA11YFOCUSTRACKER_HXX_
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#endif
+
+#include "keyboardfocuslistener.hxx"
+
+#include <rtl/instance.hxx>
+
+#include <tools/link.hxx>
+#include <vcl/vclevent.hxx>
+#include <set>
+
+class Window;
+class ToolBox;
+class DocumentFocusListener;
+
+// ------------------------
+// - AquaA11yFocusTracker -
+// ------------------------
+
+class AquaA11yFocusTracker : public rtl::Static< AquaA11yFocusTracker, AquaA11yFocusTracker>
+{
+
+public:
+ AquaA11yFocusTracker();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getFocusedObject() { return m_xFocusedObject; };
+
+ // sets the currently focus object and notifies the FocusEventListener (if any)
+ void setFocusedObject(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible);
+
+ // may evolve to add/remove later
+ void setFocusListener(const rtl::Reference< KeyboardFocusListener >& aFocusListener) { m_aFocusListener = aFocusListener; };
+
+protected:
+
+ // received a WINDOW_GETFOCUS event for this window
+ virtual void window_got_focus(Window *pWindow);
+
+ // received a TOOLBOX_HIGHLIGHT event for this window
+ virtual void toolbox_highlight_on(Window *pWindow);
+
+ // received a TOOLBOX_HIGHLIGHTOFF event for this window
+ virtual void toolbox_highlight_off(Window *pWindow);
+
+ // received a TABPAGE_ACTIVATE event for this window
+ virtual void tabpage_activated(Window *pWindow);
+
+ // received a MENU_HIGHLIGHT event for this window
+ virtual void menu_highlighted(const ::VclMenuEvent *pEvent);
+
+ // toolbox items are widgets in gtk+ and Cocoa
+ virtual void notify_toolbox_item_focus(ToolBox *pToolBox);
+
+ // toolbox item opened a floating window (e.g. color chooser)
+ virtual void toolbox_open_floater(Window *pWindow);
+
+ // callback function for Application::addEventListener
+ static long WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent);
+
+private:
+ // the accessible object that has the keyboard focus (if any)
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > m_xFocusedObject;
+
+ // the listener for focus events
+ rtl::Reference< KeyboardFocusListener > m_aFocusListener;
+
+ // the list of Windows that need deeper (focus) investigation
+ std::set< Window *> m_aDocumentWindowList;
+
+ // the link object needed for Application::addEventListener
+ Link m_aWindowEventLink;
+
+ // the UNO XAccessibilityEventListener for Documents and other non VCL objects
+ const ::com::sun::star::uno::Reference< DocumentFocusListener > m_xDocumentFocusListener;
+};
+
+#endif // _AQUA11YFOCUSTRACKER_HXX_
diff --git a/vcl/aqua/inc/aqua11ylistener.hxx b/vcl/aqua/inc/aqua11ylistener.hxx
new file mode 100644
index 000000000000..461b149e4650
--- /dev/null
+++ b/vcl/aqua/inc/aqua11ylistener.hxx
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _AQUA11YLISTENER_HXX_
+#define _AQUA11YLISTENER_HXX_
+
+#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include "aqua11yfocustracker.hxx"
+#include "aquavcltypes.h"
+#include <set>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+// -------------------------
+// - AquaA11yEventListener -
+// -------------------------
+
+class AquaA11yEventListener :
+ public ::cppu::WeakImplHelper1< ::com::sun::star::accessibility::XAccessibleEventListener >
+{
+
+public:
+ AquaA11yEventListener(id wrapperObject, sal_Int16 role);
+ virtual ~AquaA11yEventListener();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source )
+ throw (::com::sun::star::uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void SAL_CALL notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+private:
+ const id m_wrapperObject;
+ const sal_Int16 m_role;
+ ::com::sun::star::awt::Rectangle m_oldBounds;
+};
+
+#endif // _AQUA11YLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/inc/aqua11ywrapper.h b/vcl/aqua/inc/aqua11ywrapper.h
new file mode 100644
index 000000000000..079dcfe7f112
--- /dev/null
+++ b/vcl/aqua/inc/aqua11ywrapper.h
@@ -0,0 +1,119 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPER_H
+#define _SV_AQUA11WRAPPER_H
+
+#include "aquavcltypes.h"
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
+
+// rAccessibleXYZ as a field in an Objective-C-Class would not call Con-/Destructor, so use a struct instead
+struct ReferenceWrapper
+{
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleAction > rAccessibleAction;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext > rAccessibleContext;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleComponent > rAccessibleComponent;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleExtendedComponent > rAccessibleExtendedComponent;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleSelection > rAccessibleSelection;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleTable > rAccessibleTable;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleText > rAccessibleText;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleEditableText > rAccessibleEditableText;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleValue > rAccessibleValue;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleTextAttributes > rAccessibleTextAttributes;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleMultiLineText > rAccessibleMultiLineText;
+};
+
+@interface AquaA11yWrapper : NSView
+{
+ ReferenceWrapper * mpReferenceWrapper;
+ NSString * mpDefaultFontname;
+ float mDefaultFontsize;
+ MacOSBOOL mActsAsRadioGroup;
+ MacOSBOOL mIsTableCell;
+}
+// NSAccessibility Protocol
+-(id)accessibilityAttributeValue:(NSString *)attribute;
+-(MacOSBOOL)accessibilityIsIgnored;
+-(NSArray *)accessibilityAttributeNames;
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(NSArray *)accessibilityParameterizedAttributeNames;
+-(MacOSBOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute;
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute;
+-(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter;
+-(id)accessibilityFocusedUIElement;
+-(NSString *)accessibilityActionDescription:(NSString *)action;
+-(void)accessibilityPerformAction:(NSString *)action;
+-(NSArray *)accessibilityActionNames;
+-(id)accessibilityHitTest:(NSPoint)point;
+// Attribute values
+-(id)parentAttribute;
+-(id)valueAttribute;
+-(id)titleAttribute;
+-(id)helpAttribute;
+-(id)numberOfCharactersAttribute;
+-(id)selectedTextAttribute;
+-(id)selectedTextRangeAttribute;
+-(id)visibleCharacterRangeAttribute;
+-(id)childrenAttribute;
+-(id)orientationAttribute;
+-(id)windowAttribute;
+// Wrapper-specific
+-(void)setActsAsRadioGroup:(MacOSBOOL)actsAsRadioGroup;
+-(MacOSBOOL)actsAsRadioGroup;
+-(NSView *)viewElementForParent;
+-(id)initWithAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) anAccessibleContext;
+-(void) setDefaults: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
+-(void) dealloc;
+-(void)setDefaultFontname:(NSString *)fontname;
+-(NSString *)defaultFontname;
+-(void)setDefaultFontsize:(float)fontsize;
+-(float)defaultFontsize;
++(void)setPopupMenuOpen:(MacOSBOOL)popupMenuOpen;
+-(::com::sun::star::accessibility::XAccessibleAction *)accessibleAction;
+-(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext;
+-(::com::sun::star::accessibility::XAccessibleComponent *)accessibleComponent;
+-(::com::sun::star::accessibility::XAccessibleExtendedComponent *)accessibleExtendedComponent;
+-(::com::sun::star::accessibility::XAccessibleSelection *)accessibleSelection;
+-(::com::sun::star::accessibility::XAccessibleTable *)accessibleTable;
+-(::com::sun::star::accessibility::XAccessibleText *)accessibleText;
+-(::com::sun::star::accessibility::XAccessibleEditableText *)accessibleEditableText;
+-(::com::sun::star::accessibility::XAccessibleValue *)accessibleValue;
+-(::com::sun::star::accessibility::XAccessibleTextAttributes *)accessibleTextAttributes;
+-(::com::sun::star::accessibility::XAccessibleMultiLineText *)accessibleMultiLineText;
+@end
+
+#endif // _SV_AQUA11WRAPPER_H
diff --git a/vcl/aqua/inc/aquaprintview.h b/vcl/aqua/inc/aquaprintview.h
new file mode 100755
index 000000000000..84d9dd54d6aa
--- /dev/null
+++ b/vcl/aqua/inc/aquaprintview.h
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_AQUAPRINTVIEW_H
+#define _VCL_AQUAPRINTVIEW_H
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "vcl/print.hxx"
+
+class AquaSalInfoPrinter;
+
+struct PrintAccessoryViewState
+{
+ bool bNeedRestart;
+ sal_Int32 nLastPage;
+
+ PrintAccessoryViewState()
+ : bNeedRestart( false ), nLastPage( 0 ) {}
+};
+
+@interface AquaPrintView : NSView
+{
+ vcl::PrinterController* mpController;
+ AquaSalInfoPrinter* mpInfoPrinter;
+}
+-(id)initWithController: (vcl::PrinterController*)pController withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter;
+-(MacOSBOOL)knowsPageRange: (NSRangePointer)range;
+-(NSRect)rectForPage: (int)page;
+-(NSPoint)locationOfPrintRect: (NSRect)aRect;
+-(void)drawRect: (NSRect)rect;
+@end
+
+@interface AquaPrintAccessoryView : NSObject
+{
+}
++(NSObject*)setupPrinterPanel: (NSPrintOperation*)pOp withController: (vcl::PrinterController*)pController withState: (PrintAccessoryViewState*)pState;
+@end
+
+
+#endif
diff --git a/vcl/aqua/inc/aquavclevents.hxx b/vcl/aqua/inc/aquavclevents.hxx
new file mode 100644
index 000000000000..8e03c59d0954
--- /dev/null
+++ b/vcl/aqua/inc/aquavclevents.hxx
@@ -0,0 +1,96 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_AQUAVCLEVENTS_HXX
+#define INCLUDED_AQUAVCLEVENTS_HXX
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <postmac.h>
+
+/* Definition of custom OpenOffice.org events.
+
+ Avoid conflict with Apple defined event class and type
+ definitions by using uppercase letters. Lowercase
+ letter definitions are reserved for Apple!
+ */
+enum {
+ cOOoSalUserEventClass = 'OOUE'
+};
+
+enum {
+ cOOoSalEventUser = 'UEVT',
+ cOOoSalEventTimer = 'EVTT',
+ cOOoSalEventData = 'EVTD',
+ cOOoSalEventParamTypePtr = 'EPPT'
+};
+
+/* Definition of all necessary EventTypeSpec's */
+
+const EventTypeSpec cWindowBoundsChangedEvent = { kEventClassWindow, kEventWindowBoundsChanged };
+const EventTypeSpec cWindowCloseEvent = { kEventClassWindow, kEventWindowClose };
+const EventTypeSpec cOOoSalUserEvent = { cOOoSalUserEventClass, cOOoSalEventUser };
+const EventTypeSpec cOOoSalTimerEvent = { cOOoSalUserEventClass, cOOoSalEventTimer };
+const EventTypeSpec cWindowActivatedEvent[] = { { kEventClassWindow, kEventWindowActivated },
+ { kEventClassWindow, kEventWindowDeactivated } };
+const EventTypeSpec cWindowPaintEvent = { kEventClassWindow, kEventWindowPaint };
+const EventTypeSpec cWindowDrawContentEvent = { kEventClassWindow, kEventWindowDrawContent };
+
+const EventTypeSpec cWindowFocusEvent[] = { { kEventClassWindow, kEventWindowFocusAcquired },
+ { kEventClassWindow, kEventWindowFocusRelinquish } };
+
+const EventTypeSpec cMouseEnterExitEvent[] = { { kEventClassControl, kEventControlTrackingAreaEntered },
+ { kEventClassControl, kEventControlTrackingAreaExited } };
+
+const EventTypeSpec cMouseEvent[] = { { kEventClassMouse, kEventMouseDown },
+ { kEventClassMouse, kEventMouseUp },
+ { kEventClassMouse, kEventMouseMoved },
+ { kEventClassMouse, kEventMouseDragged } };
+const EventTypeSpec cMouseWheelMovedEvent = { kEventClassMouse, kEventMouseWheelMoved };
+const EventTypeSpec cWindowResizeStarted = { kEventClassWindow, kEventWindowResizeStarted };
+const EventTypeSpec cWindowResizeCompleted = { kEventClassWindow, kEventWindowResizeCompleted };
+
+/* Events for native menus */
+const EventTypeSpec cCommandProcessEvent = { kEventClassCommand, kEventCommandProcess };
+const EventTypeSpec cMenuPopulateEvent = { kEventClassMenu, kEventMenuPopulate };
+const EventTypeSpec cMenuClosedEvent = { kEventClassMenu, kEventMenuClosed };
+const EventTypeSpec cMenuTargetItemEvent = { kEventClassMenu, kEventMenuTargetItem };
+
+/* Events for keyboard */
+const EventTypeSpec cKeyboardRawKeyEvents[] = { { kEventClassKeyboard, kEventRawKeyDown},
+ { kEventClassKeyboard, kEventRawKeyUp},
+ { kEventClassKeyboard, kEventRawKeyRepeat},
+ { kEventClassKeyboard, kEventRawKeyModifiersChanged} };
+
+const EventTypeSpec cTextInputEvents[] = { { kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
+ { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
+ { kEventClassTextInput, kEventTextInputOffsetToPos} };
+
+/* Events for scrollbar */
+
+const EventTypeSpec cAppearanceScrollbarVariantChangedEvent = { kEventClassAppearance, kEventAppearanceScrollBarVariantChanged };
+
+#endif // INCLUDED_AQUAVCLEVENTS_HXX
diff --git a/vcl/aqua/inc/aquavcltypes.h b/vcl/aqua/inc/aquavcltypes.h
new file mode 100644
index 000000000000..7346282963d7
--- /dev/null
+++ b/vcl/aqua/inc/aquavcltypes.h
@@ -0,0 +1,36 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _AQUAVCLTYPES_H
+#define _AQUAVCLTYPES_H
+
+#include "premac.h"
+#import <Cocoa/Cocoa.h>
+#import <AppKit/NSEvent.h>
+#include "postmac.h"
+
+#endif _AQUAVCLTYPES_H
diff --git a/vcl/aqua/inc/keyboardfocuslistener.hxx b/vcl/aqua/inc/keyboardfocuslistener.hxx
new file mode 100644
index 000000000000..71eba2f46c02
--- /dev/null
+++ b/vcl/aqua/inc/keyboardfocuslistener.hxx
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _KEYBOARDFOCUSLISTENER_HXX_
+#define _KEYBOARDFOCUSLISTENER_HXX_
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#endif
+
+#include <rtl/ref.hxx>
+
+// -------------------------
+// - KeyboardFocusListener -
+// -------------------------
+
+class KeyboardFocusListener : public rtl::IReference
+{
+public:
+ virtual void SAL_CALL focusedObjectChanged(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible) = 0;
+};
+
+#endif // _KEYBOARDFOCUSLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/inc/salatsuifontutils.hxx b/vcl/aqua/inc/salatsuifontutils.hxx
new file mode 100644
index 000000000000..81e60871ae86
--- /dev/null
+++ b/vcl/aqua/inc/salatsuifontutils.hxx
@@ -0,0 +1,63 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALATSUIFONTUTILS_HXX
+#define _SV_SALATSUIFONTUTILS_HXX
+
+class ImplMacFontData;
+class ImplDevFontList;
+
+#include <premac.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <postmac.h>
+
+#include <map>
+
+/* This class has the responsibility of assembling a list
+ of atsui compatible fonts available on the system and
+ enabling access to that list.
+ */
+class SystemFontList
+{
+public:
+ SystemFontList();
+ ~SystemFontList();
+
+ void AnnounceFonts( ImplDevFontList& ) const;
+ ImplMacFontData* GetFontDataFromId( ATSUFontID ) const;
+
+ ATSUFontFallbacks maFontFallbacks;
+
+private:
+ typedef std::hash_map<ATSUFontID,ImplMacFontData*> MacFontContainer;
+ MacFontContainer maFontContainer;
+
+ void InitGlyphFallbacks();
+};
+
+#endif // _SV_SALATSUIFONTUTILS_HXX
+
diff --git a/vcl/aqua/inc/salbmp.h b/vcl/aqua/inc/salbmp.h
new file mode 100644
index 000000000000..1c427cce0cd5
--- /dev/null
+++ b/vcl/aqua/inc/salbmp.h
@@ -0,0 +1,107 @@
+/*************************************************************************
+*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+#ifndef _SV_SALBMP_H
+#define _SV_SALBMP_H
+
+#include "tools/gen.hxx"
+#include "vcl/sv.h"
+#include "vcl/salbtype.hxx"
+#include "saldata.hxx"
+#include "vcl/salinst.hxx"
+#include "salconst.h"
+#include "vcl/salvd.hxx"
+#include "salcolorutils.hxx"
+#include "vcl/salbmp.hxx"
+#include "salgdi.h"
+#include "basebmp/bitmapdevice.hxx"
+
+// --------------
+// - SalBitmap -
+// --------------
+
+struct BitmapBuffer;
+class BitmapColor;
+class BitmapPalette;
+class AquaSalVirtualDevice;
+class AquaSalGraphics;
+
+class AquaSalBitmap : public SalBitmap
+{
+public:
+ CGContextRef mxGraphicContext;
+ mutable CGImageRef mxCachedImage;
+ BitmapPalette maPalette;
+ basebmp::RawMemorySharedArray maUserBuffer;
+ basebmp::RawMemorySharedArray maContextBuffer;
+ sal_uInt16 mnBits;
+ int mnWidth;
+ int mnHeight;
+ sal_uInt32 mnBytesPerRow;
+
+public:
+ AquaSalBitmap();
+ virtual ~AquaSalBitmap();
+
+public:
+
+ // SalBitmap methods
+ bool Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ bool Create( const SalBitmap& rSalBmp );
+ bool Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics );
+ bool Create( const SalBitmap& rSalBmp, USHORT nNewBitCount );
+
+ void Destroy();
+
+ Size GetSize() const;
+ USHORT GetBitCount() const;
+
+ BitmapBuffer *AcquireBuffer( bool bReadOnly );
+ void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly );
+
+ bool GetSystemData( BitmapSystemData& rData );
+
+private:
+ // quartz helper
+ bool CreateContext();
+ void DestroyContext();
+ bool AllocateUserData();
+
+ void ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight,
+ sal_uInt16 nDestBits, sal_uInt32 nDestBytesPerRow, const BitmapPalette& rDestPalette, sal_uInt8* pDestData,
+ sal_uInt16 nSrcBits, sal_uInt32 nSrcBytesPerRow, const BitmapPalette& rSrcPalette, sal_uInt8* pSrcData );
+
+public:
+ bool Create( CGLayerRef xLayer, int nBitCount, int nX, int nY, int nWidth, int nHeight, bool bMirrorVert = true );
+
+public:
+ CGImageRef CreateWithMask( const AquaSalBitmap& rMask, int nX, int nY, int nWidth, int nHeight ) const;
+ CGImageRef CreateColorMask( int nX, int nY, int nWidth, int nHeight, SalColor nMaskColor ) const;
+ CGImageRef CreateCroppedImage( int nX, int nY, int nWidth, int nHeight ) const;
+};
+
+#endif // _SV_SALBMP_HXX
diff --git a/vcl/aqua/inc/salcolorutils.hxx b/vcl/aqua/inc/salcolorutils.hxx
new file mode 100755
index 000000000000..74ccb69756fd
--- /dev/null
+++ b/vcl/aqua/inc/salcolorutils.hxx
@@ -0,0 +1,52 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALCOLORUTILS_HXX
+#define _SV_SALCOLORUTILS_HXX
+
+#ifndef _LIMITS_H
+ #include <limits.h>
+#endif
+
+#include "premac.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "postmac.h"
+
+#include "vcl/salbtype.hxx"
+#include "vcl/salgtype.hxx"
+#include "salconst.h"
+#include "salmathutils.hxx"
+
+// ------------------------------------------------------------------
+
+SalColor GetSalColor( const float* pQuartzColor );
+
+void SetSalColor( const SalColor& rColor, float* pQuartzColor );
+
+// ------------------------------------------------------------------
+
+#endif // _SV_SALCOLORUTILS_HXX
diff --git a/vcl/aqua/inc/salconst.h b/vcl/aqua/inc/salconst.h
new file mode 100755
index 000000000000..2046ec20a806
--- /dev/null
+++ b/vcl/aqua/inc/salconst.h
@@ -0,0 +1,68 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALCONST_H
+#define _SV_SALCONST_H
+
+// -------------------
+// - Constants -
+// -------------------
+
+static const unsigned short kByteMask = 0xFF;
+
+static const unsigned short kOneByte = 8;
+static const unsigned short kTwoBytes = 16;
+
+static const unsigned short kOneBit = 1;
+static const unsigned short kFiveBits = 5;
+static const unsigned short kEightBits = 8;
+static const unsigned short kTenBits = 10;
+static const unsigned short kElevenBits = 11;
+
+static const unsigned short kBlackAndWhite = 1;
+static const unsigned short kFourBitColor = 4;
+static const unsigned short kEightBitColor = 8;
+static const unsigned short kThousandsColor = 16;
+static const unsigned short kTrueColor = 32;
+
+static const unsigned long k16BitRedColorMask = 0x00007c00;
+static const unsigned long k16BitGreenColorMask = 0x000003e0;
+static const unsigned long k16BitBlueColorMask = 0x0000001f;
+
+static const unsigned long k32BitRedColorMask = 0x00ff0000;
+static const unsigned long k32BitGreenColorMask = 0x0000ff00;
+static const unsigned long k32BitBlueColorMask = 0x000000ff;
+
+static const unsigned short kPixMapCmpSizeOneBit = 1;
+static const unsigned short kPixMapCmpSizeFourBits = 4;
+static const unsigned short kPixMapCmpSizeFiveBits = 5;
+static const unsigned short kPixMapCmpSizeEightBits = 8;
+
+static const long kPixMapHRes = 72;
+static const long kPixMapVRes = 72;
+
+#endif // _SV_SALCONST_H
diff --git a/vcl/aqua/inc/saldata.hxx b/vcl/aqua/inc/saldata.hxx
new file mode 100644
index 000000000000..fb7c8cddd6d4
--- /dev/null
+++ b/vcl/aqua/inc/saldata.hxx
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALDATA_HXX
+#define _SV_SALDATA_HXX
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "com/sun/star/uno/Reference.hxx"
+
+#include "vcl/sv.h"
+#include "vcl/svdata.hxx"
+#include "vcl/salwtype.hxx"
+#include "vcl/ptrstyle.hxx"
+
+#include <list>
+#include <vector>
+#include <map>
+#include <hash_set>
+
+#include <cstdio>
+#include <cstdarg>
+
+#include "apple_remote/RemoteMainController.h"
+
+class AquaSalInstance;
+class SalObject;
+class SalFrame;
+class SalVirtualDevice;
+class SalPrinter;
+class SystemFontList;
+
+// ------------------
+// - Some constants -
+// ------------------
+
+#define SAL_CLIPRECT_COUNT 16
+
+#define VER_TIGER 0x1040
+#define VER_LEOPARD 0x1050
+
+// -----------
+// - SalData -
+// -----------
+
+class AquaSalFrame;
+struct FrameHash : public std::hash<sal_IntPtr>
+{
+ size_t operator()(const AquaSalFrame* frame) const
+ { return std::hash<sal_IntPtr>::operator()( reinterpret_cast<const sal_IntPtr>(frame) ); }
+};
+
+#define INVALID_CURSOR_PTR (NSCursor*)0xdeadbeef
+
+struct SalData
+{
+
+ SALTIMERPROC mpTimerProc; // timer callback proc
+ AquaSalInstance *mpFirstInstance; // pointer of first instance
+ std::list<AquaSalFrame*> maFrames; // pointer of first frame
+ std::hash_set<const AquaSalFrame*,FrameHash> maFrameCheck; // for fast check of frame existance
+ SalObject *mpFirstObject; // pointer of first object window
+ SalVirtualDevice *mpFirstVD; // first VirDev
+ SalPrinter *mpFirstPrinter; // first printing printer
+ SystemFontList *mpFontList;
+ NSStatusItem* mpStatusItem; // one status item that draws all our stati
+ // at the moment this is only one add menu button
+
+ CGColorSpaceRef mxRGBSpace;
+ CGColorSpaceRef mxGraySpace;
+ CGColorSpaceRef mxP50Space;
+ CGPatternRef mxP50Pattern;
+
+ std::vector< NSCursor* > maCursors;
+ std::vector< NSMenuItem* > maFallbackMenu;
+ std::map< NSEvent*, bool > maKeyEventAnswer;
+
+ static oslThreadKey s_aAutoReleaseKey;
+
+ bool mbIsScrollbarDoubleMax; // TODO: support DoubleMin and DoubleBoth too
+ SInt32 mnSystemVersion; // Store System Version
+ MainController* mpMainController; // Apple Remote
+
+ NSObject* mpDockIconClickHandler;
+ long mnDPIX; // #i100617# read DPI only once per office life
+ long mnDPIY; // #i100617# read DPI only once per office life
+
+ com::sun::star::uno::Reference< com::sun::star::uno::XInterface >
+ mxClipboard;
+
+ SalData();
+ ~SalData();
+
+ NSCursor* getCursor( PointerStyle i_eStyle );
+
+ static void ensureThreadAutoreleasePool();
+ static void drainThreadAutoreleasePool();
+
+ static NSStatusItem* getStatusItem();
+};
+
+inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = (void*)pData; }
+inline SalData *GetSalData() { return (SalData*)ImplGetSVData()->mpSalData; }
+inline SalData *GetAppSalData() { return (SalData*)ImplGetAppSVData()->mpSalData; }
+
+// --- Prototypes ---
+
+BOOL ImplSalYieldMutexTryToAcquire();
+void ImplSalYieldMutexAcquire();
+void ImplSalYieldMutexRelease();
+
+#endif // _SV_SALDATA_HXX
diff --git a/vcl/aqua/inc/salfontutils.hxx b/vcl/aqua/inc/salfontutils.hxx
new file mode 100644
index 000000000000..6f9f61efda70
--- /dev/null
+++ b/vcl/aqua/inc/salfontutils.hxx
@@ -0,0 +1,66 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+#ifndef _SV_SALFONTUTILS_HXX
+#define _SV_SALFONTUTILS_HXX
+
+#include "vcl/outfont.hxx"
+
+static const char *kFontWeightThin1 = "Thin";
+static const char *kFontWeightThin2 = "thin";
+
+static const char *kFontWeightLight1 = "Light";
+static const char *kFontWeightLight2 = "light";
+
+static const char *kFontWeightBold1 = "Bold";
+static const char *kFontWeightBold2 = "bold";
+
+static const char *kFontWeightUltra1 = "Ultra";
+static const char *kFontWeightUltra2 = "ultra";
+
+static const char *kFontWeightSemi1 = "Semi";
+static const char *kFontWeightSemi2 = "semi";
+
+static const char *kFontWeightNormal1 = "Normal";
+static const char *kFontWeightNormal2 = "normal";
+
+static const char *kFontWeightMedium1 = "Medium";
+static const char *kFontWeightMedium2 = "medium";
+
+static const char *kFontWeightBlack1 = "Black";
+static const char *kFontWeightBlack2 = "black";
+
+static const char *kFontWeightRoman1 = "Roman";
+static const char *kFontWeightRoman2 = "roman";
+
+static const char *kFontWeightRegular1 = "Regular";
+static const char *kFontWeightRegular2 = "regular";
+
+
+#endif // _SV_SALFONTUTILS_HXX
+
diff --git a/vcl/aqua/inc/salframe.h b/vcl/aqua/inc/salframe.h
new file mode 100644
index 000000000000..c2ded3267f45
--- /dev/null
+++ b/vcl/aqua/inc/salframe.h
@@ -0,0 +1,220 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALFRAME_H
+#define _SV_SALFRAME_H
+
+
+#include "vcl/sv.h"
+#include "vcl/salframe.hxx"
+#include "vcl/sysdata.hxx"
+
+#include "salmenu.h"
+#include "saldata.hxx"
+#include "aquavcltypes.h"
+
+#include <vector>
+#include <utility>
+#include <stdexcept>
+
+#include <boost/shared_ptr.hpp>
+
+class AquaSalGraphics;
+class AquaSalFrame;
+class AquaSalTimer;
+class AquaSalInstance;
+class AquaSalMenu;
+class AquaBlinker;
+
+typedef struct SalFrame::SalPointerState SalPointerState;
+
+// ----------------
+// - AquaSalFrame -
+// ----------------
+
+class AquaSalFrame : public SalFrame
+{
+public:
+ NSWindow* mpWindow; // Cocoa window
+ NSView* mpView; // Cocoa view (actually a custom view, see below
+ NSMenuItem* mpDockMenuEntry; // entry in the dynamic dock menu
+ NSRect maScreenRect; // for mirroring purposes
+ AquaSalGraphics* mpGraphics; // current frame graphics
+ AquaSalFrame* mpParent; // pointer to parent frame
+ SystemEnvData maSysData; // system data
+ int mnMinWidth; // min. client width in pixels
+ int mnMinHeight; // min. client height in pixels
+ int mnMaxWidth; // max. client width in pixels
+ int mnMaxHeight; // max. client height in pixels
+ NSRect maFullScreenRect; // old window size when in FullScreen
+ bool mbGraphics:1; // is Graphics used?
+ bool mbFullScreen:1; // is Window in FullScreen?
+ bool mbShown:1;
+ bool mbInitShow:1;
+ bool mbPositioned:1;
+ bool mbSized:1;
+ bool mbPresentation:1;
+
+ ULONG mnStyle;
+ unsigned int mnStyleMask; // our style mask from NSWindow creation
+
+ ULONG mnLastEventTime;
+ unsigned int mnLastModifierFlags;
+ AquaSalMenu* mpMenu;
+
+ SalExtStyle mnExtStyle; // currently document frames are marked this way
+
+ PointerStyle mePointerStyle; // currently active pointer style
+
+ NSTrackingRectTag mnTrackingRectTag; // used to get enter/leave messages
+
+ CGMutablePathRef mrClippingPath; // used for "shaping"
+ std::vector< CGRect > maClippingRects;
+
+ std::list<AquaBlinker*> maBlinkers;
+
+ Rectangle maInvalidRect;
+
+ ULONG mnICOptions;
+
+ boost::shared_ptr< Timer > mpActivityTimer; // Timer to prevent system sleep during presentation
+public:
+ /** Constructor
+
+ Creates a system window and connects this frame with it.
+
+ @throws std::runtime_error in case window creation fails
+ */
+ AquaSalFrame( SalFrame* pParent, ULONG salFrameStyle );
+
+ virtual ~AquaSalFrame();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL PostEvent( void* pData );
+ virtual void SetTitle( const XubString& rTitle );
+ virtual void SetIcon( USHORT nIcon );
+ virtual void SetRepresentedURL( const rtl::OUString& );
+ virtual void SetMenu( SalMenu* pSalMenu );
+ virtual void DrawMenuBar();
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE );
+ virtual void Enable( BOOL bEnable );
+ virtual void SetMinClientSize( long nWidth, long nHeight );
+ virtual void SetMaxClientSize( long nWidth, long nHeight );
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ virtual void GetClientSize( long& rWidth, long& rHeight );
+ virtual void GetWorkArea( Rectangle& rRect );
+ virtual SalFrame* GetParent() const;
+ virtual void SetWindowState( const SalFrameState* pState );
+ virtual BOOL GetWindowState( SalFrameState* pState );
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay );
+ virtual void StartPresentation( BOOL bStart );
+ virtual void SetAlwaysOnTop( BOOL bOnTop );
+ virtual void ToTop( USHORT nFlags );
+ virtual void SetPointer( PointerStyle ePointerStyle );
+ virtual void CaptureMouse( BOOL bMouse );
+ virtual void SetPointerPos( long nX, long nY );
+ virtual void Flush( void );
+ virtual void Flush( const Rectangle& );
+ virtual void Sync();
+ virtual void SetInputContext( SalInputContext* pContext );
+ virtual void EndExtTextInput( USHORT nFlags );
+ virtual String GetKeyName( USHORT nKeyCode );
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode );
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode );
+ virtual LanguageType GetInputLanguage();
+ virtual SalBitmap* SnapShot();
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Beep( SoundType eSoundType );
+ virtual const SystemEnvData* GetSystemData() const;
+ virtual SalPointerState GetPointerState();
+ virtual void SetParent( SalFrame* pNewParent );
+ virtual bool SetPluginParent( SystemParentData* pNewParent );
+ virtual void SetExtendedFrameStyle( SalExtStyle );
+ virtual void SetBackgroundBitmap( SalBitmap* );
+ virtual void SetScreenNumber(unsigned int);
+
+ // shaped system windows
+ // set clip region to none (-> rectangular windows, normal state)
+ virtual void ResetClipRegion();
+ // start setting the clipregion consisting of nRects rectangles
+ virtual void BeginSetClipRegion( ULONG nRects );
+ // add a rectangle to the clip region
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ // done setting up the clipregion
+ virtual void EndSetClipRegion();
+
+ virtual void SetClientSize( long nWidth, long nHeight );
+
+ void UpdateFrameGeometry();
+
+ // trigger painting of the window
+ void SendPaintEvent( const Rectangle* pRect = NULL );
+
+ static bool isAlive( const AquaSalFrame* pFrame )
+ { return GetSalData()->maFrameCheck.find( pFrame ) != GetSalData()->maFrameCheck.end(); }
+
+ static AquaSalFrame* GetCaptureFrame() { return s_pCaptureFrame; }
+
+ NSWindow* getWindow() const { return mpWindow; }
+ NSView* getView() const { return mpView; }
+ unsigned int getStyleMask() const { return mnStyleMask; }
+
+ void getResolution( long& o_rDPIX, long& o_rDPIY );
+
+ // actually the follwing methods do the same thing: flipping y coordinates
+ // but having two of them makes clearer what the coordinate system
+ // is supposed to be before and after
+ void VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen = true );
+ void CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen = true );
+
+ void VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen = true );
+ void CocoaToVCL( NSPoint& io_Point, bool bRelativeToScreen = true );
+
+ NSCursor* getCurrentCursor() const;
+
+ CGMutablePathRef getClipPath() const { return mrClippingPath; }
+
+ // called by VCL_NSApplication to indicate screen settings have changed
+ void screenParametersChanged();
+
+ private: // methods
+ /** do things on initial show (like centering on parent or on screen)
+ */
+ void initShow();
+
+ void initWindowAndView();
+
+ private: // data
+ static AquaSalFrame* s_pCaptureFrame;
+
+ // make AquaSalFrame non copyable
+ AquaSalFrame( const AquaSalFrame& );
+ AquaSalFrame& operator=(const AquaSalFrame&);
+};
+
+#endif // _SV_SALFRAME_H
diff --git a/vcl/aqua/inc/salframeview.h b/vcl/aqua/inc/salframeview.h
new file mode 100755
index 000000000000..0174c1a68832
--- /dev/null
+++ b/vcl/aqua/inc/salframeview.h
@@ -0,0 +1,208 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_SALFRAMEVIEW_H
+#define _VCL_SALFRAMEVIEW_H
+
+#include "aqua11ywrapper.h"
+
+@interface SalFrameWindow : NSWindow
+{
+ AquaSalFrame* mpFrame;
+ id mDraggingDestinationHandler;
+}
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame;
+-(MacOSBOOL)canBecomeKeyWindow;
+-(void)windowDidBecomeKey: (NSNotification*)pNotification;
+-(void)windowDidResignKey: (NSNotification*)pNotification;
+-(void)windowDidChangeScreen: (NSNotification*)pNotification;
+-(void)windowDidMove: (NSNotification*)pNotification;
+-(void)windowDidResize: (NSNotification*)pNotification;
+-(void)windowDidMiniaturize: (NSNotification*)pNotification;
+-(void)windowDidDeminiaturize: (NSNotification*)pNotification;
+-(MacOSBOOL)windowShouldClose: (NSNotification*)pNotification;
+-(void)dockMenuItemTriggered: (id)sender;
+-(AquaSalFrame*)getSalFrame;
+-(MacOSBOOL)containsMouse;
+-(::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >)accessibleContext;
+
+/* NSDraggingDestination protocol methods
+ */
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+-(void)draggingExited:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender;
+
+-(void)registerDraggingDestinationHandler:(id)theHandler;
+-(void)unregisterDraggingDestinationHandler:(id)theHandler;
+@end
+
+@interface SalFrameView : AquaA11yWrapper <NSTextInput>
+{
+ AquaSalFrame* mpFrame;
+
+ // for NSTextInput
+ NSEvent* mpLastEvent;
+ BOOL mbNeedSpecialKeyHandle;
+ BOOL mbInKeyInput;
+ BOOL mbKeyHandled;
+ NSRange mMarkedRange;
+ NSRange mSelectedRange;
+ id mpMouseEventListener;
+ id mDraggingDestinationHandler;
+ NSEvent* mpLastSuperEvent;
+}
++(void)unsetMouseFrame: (AquaSalFrame*)pFrame;
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame;
+-(MacOSBOOL)acceptsFirstResponder;
+-(MacOSBOOL)acceptsFirstMouse: (NSEvent *)pEvent;
+-(MacOSBOOL)isOpaque;
+-(void)drawRect: (NSRect)aRect;
+-(void)mouseDown: (NSEvent*)pEvent;
+-(void)mouseDragged: (NSEvent*)pEvent;
+-(void)mouseUp: (NSEvent*)pEvent;
+-(void)mouseMoved: (NSEvent*)pEvent;
+-(void)mouseEntered: (NSEvent*)pEvent;
+-(void)mouseExited: (NSEvent*)pEvent;
+-(void)rightMouseDown: (NSEvent*)pEvent;
+-(void)rightMouseDragged: (NSEvent*)pEvent;
+-(void)rightMouseUp: (NSEvent*)pEvent;
+-(void)otherMouseDown: (NSEvent*)pEvent;
+-(void)otherMouseDragged: (NSEvent*)pEvent;
+-(void)otherMouseUp: (NSEvent*)pEvent;
+-(void)scrollWheel: (NSEvent*)pEvent;
+-(void)magnifyWithEvent: (NSEvent*)pEvent;
+-(void)rotateWithEvent: (NSEvent*)pEvent;
+-(void)swipeWithEvent: (NSEvent*)pEvent;
+-(void)keyDown: (NSEvent*)pEvent;
+-(void)flagsChanged: (NSEvent*)pEvent;
+-(void)sendMouseEventToFrame:(NSEvent*)pEvent button:(USHORT)nButton eventtype:(USHORT)nEvent;
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar;
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod;
+-(MacOSBOOL)sendKeyToFrameDirect: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod;
+-(MacOSBOOL)sendSingleCharacter:(NSEvent*)pEvent;
+-(MacOSBOOL)handleKeyDownException:(NSEvent*)pEvent;
+-(void)clearLastEvent;
+/*
+ text action methods
+*/
+-(void)insertText:(id)aString;
+-(void)insertTab: (id)aSender;
+-(void)insertBacktab: (id)aSender;
+-(void)moveLeft: (id)aSender;
+-(void)moveLeftAndModifySelection: (id)aSender;
+-(void)moveBackwardAndModifySelection: (id)aSender;
+-(void)moveRight: (id)aSender;
+-(void)moveRightAndModifySelection: (id)aSender;
+-(void)moveForwardAndModifySelection: (id)aSender;
+-(void)moveUp: (id)aSender;
+-(void)moveDown: (id)aSender;
+-(void)moveWordBackward: (id)aSender;
+-(void)moveWordBackwardAndModifySelection: (id)aSender;
+-(void)moveWordLeftAndModifySelection: (id)aSender;
+-(void)moveWordForward: (id)aSender;
+-(void)moveWordForwardAndModifySelection: (id)aSender;
+-(void)moveWordRightAndModifySelection: (id)aSender;
+-(void)moveToEndOfLine: (id)aSender;
+-(void)moveToRightEndOfLine: (id)aSender;
+-(void)moveToLeftEndOfLine: (id)aSender;
+-(void)moveToEndOfLineAndModifySelection: (id)aSender;
+-(void)moveToRightEndOfLineAndModifySelection: (id)aSender;
+-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender;
+-(void)moveToBeginningOfLine: (id)aSender;
+-(void)moveToBeginningOfLineAndModifySelection: (id)aSender;
+-(void)moveToEndOfParagraph: (id)aSender;
+-(void)moveToEndOfParagraphAndModifySelection: (id)aSender;
+-(void)moveToBeginningOfParagraph: (id)aSender;
+-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender;
+-(void)moveParagraphForward: (id)aSender;
+-(void)moveParagraphForwardAndModifySelection: (id)aSender;
+-(void)moveParagraphBackward: (id)aSender;
+-(void)moveParagraphBackwardAndModifySelection: (id)aSender;
+-(void)moveToEndOfDocument: (id)aSender;
+-(void)scrollToEndOfDocument: (id)aSender;
+-(void)moveToEndOfDocumentAndModifySelection: (id)aSender;
+-(void)moveToBeginningOfDocument: (id)aSender;
+-(void)scrollToBeginningOfDocument: (id)aSender;
+-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender;
+-(void)insertNewline: (id)aSender;
+-(void)deleteBackward: (id)aSender;
+-(void)deleteForward: (id)aSender;
+-(void)cancelOperation: (id)aSender;
+-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender;
+-(void)deleteWordBackward: (id)aSender;
+-(void)deleteWordForward: (id)aSender;
+-(void)deleteToBeginningOfLine: (id)aSender;
+-(void)deleteToEndOfLine: (id)aSender;
+-(void)deleteToBeginningOfParagraph: (id)aSender;
+-(void)deleteToEndOfParagraph: (id)aSender;
+-(void)insertLineBreak: (id)aSender;
+-(void)insertParagraphSeparator: (id)aSender;
+-(void)selectWord: (id)aSender;
+-(void)selectLine: (id)aSender;
+-(void)selectParagraph: (id)aSender;
+-(void)selectAll: (id)aSender;
+-(void)noop: (id)aSender;
+/* set the correct pointer for our view */
+-(void)resetCursorRects;
+-(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext;
+-(id)parentAttribute;
+-(NSView *)viewElementForParent;
+/*
+ Event hook for D&D service.
+
+ A drag operation will be invoked on a NSView using
+ the method 'dragImage'. This method requires the
+ actual mouse event initiating this drag operation.
+ Mouse events can only be received by subclassing
+ NSView and overriding methods like 'mouseDown' etc.
+ hence we implement a event hook here so that the
+ D&D service can register as listener for mouse
+ messages and use the last 'mouseDown' or
+ 'mouseDragged' message to initiate the drag
+ operation.
+*/
+-(void)registerMouseEventListener: (id)theListener;
+-(void)unregisterMouseEventListener: (id)theListener;
+
+/* NSDraggingDestination protocol methods
+ */
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+-(void)draggingExited:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender;
+
+-(void)registerDraggingDestinationHandler:(id)theHandler;
+-(void)unregisterDraggingDestinationHandler:(id)theHandler;
+
+@end
+
+#endif
diff --git a/vcl/aqua/inc/salgdi.h b/vcl/aqua/inc/salgdi.h
new file mode 100644
index 000000000000..8867d1d26078
--- /dev/null
+++ b/vcl/aqua/inc/salgdi.h
@@ -0,0 +1,417 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALGDI_H
+#define _SV_SALGDI_H
+
+#include "premac.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "postmac.h"
+
+#include "vcl/sv.h"
+#include "vcl/outfont.hxx"
+#include "vcl/salgdi.hxx"
+#include "aquavcltypes.h"
+
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+
+#include <vector>
+
+class AquaSalFrame;
+class AquaSalBitmap;
+class ImplDevFontAttributes;
+
+class CGRect;
+
+// mac specific physically available font face
+class ImplMacFontData : public ImplFontData
+{
+public:
+ ImplMacFontData( const ImplDevFontAttributes&, ATSUFontID );
+
+ virtual ~ImplMacFontData();
+
+ virtual ImplFontData* Clone() const;
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ virtual sal_IntPtr GetFontId() const;
+
+ ImplFontCharMap* GetImplFontCharMap() const;
+ bool HasChar( sal_uInt32 cChar ) const;
+
+ void ReadOs2Table() const;
+ void ReadMacCmapEncoding() const;
+ bool HasCJKSupport() const;
+
+private:
+ const ATSUFontID mnFontId;
+ mutable ImplFontCharMap* mpCharMap;
+ mutable bool mbOs2Read; // true if OS2-table related info is valid
+ mutable bool mbHasOs2Table;
+ mutable bool mbCmapEncodingRead; // true if cmap encoding of Mac font is read
+ mutable bool mbHasCJKSupport; // #i78970# CJK fonts need extra leading
+};
+
+// abstracting quartz color instead of having to use an CGFloat[] array
+class RGBAColor
+{
+public:
+ RGBAColor( SalColor );
+ RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ); //NOTUSEDYET
+ const float* AsArray() const { return &mfRed; }
+ bool IsVisible() const { return (mfAlpha > 0); }
+ void SetAlpha( float fAlpha ) { mfAlpha = fAlpha; }
+private:
+ float mfRed, mfGreen, mfBlue, mfAlpha;
+};
+
+// -------------------
+// - AquaSalGraphics -
+// -------------------
+class AquaSalGraphics : public SalGraphics
+{
+ friend class ATSLayout;
+protected:
+ AquaSalFrame* mpFrame;
+ CGLayerRef mxLayer; // Quartz graphics layer
+ CGContextRef mrContext; // Quartz drawing context
+ class XorEmulation* mpXorEmulation;
+ int mnXorMode; // 0: off 1: on 2: invert only
+ int mnWidth;
+ int mnHeight;
+ int mnBitmapDepth; // zero unless bitmap
+ /// device resolution of this graphics
+ long mnRealDPIX;
+ long mnRealDPIY;
+ /// some graphics implementations (e.g. AquaSalInfoPrinter) scale
+ /// everything down by a factor (see SetupPrinterGraphics for details)
+ /// so we have to compensate for it with the inverse factor
+ double mfFakeDPIScale;
+
+ /// path representing current clip region
+ CGMutablePathRef mxClipPath;
+
+ /// Drawing colors
+ /// pen color RGBA
+ RGBAColor maLineColor;
+ /// brush color RGBA
+ RGBAColor maFillColor;
+
+ // Device Font settings
+ const ImplMacFontData* mpMacFontData;
+ /// ATSU style object which carries all font attributes
+ ATSUStyle maATSUStyle;
+ /// text rotation as ATSU angle
+ Fixed mnATSUIRotation;
+ /// workaround to prevent ATSU overflows for huge font sizes
+ float mfFontScale;
+ /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0
+ float mfFontStretch;
+ /// allows text to be rendered without antialiasing
+ bool mbNonAntialiasedText;
+
+ // Graphics types
+
+ /// is this a printer graphics
+ bool mbPrinter;
+ /// is this a virtual device graphics
+ bool mbVirDev;
+ /// is this a window graphics
+ bool mbWindow;
+
+public:
+ AquaSalGraphics();
+ virtual ~AquaSalGraphics();
+
+ bool IsPenVisible() const { return maLineColor.IsVisible(); }
+ bool IsBrushVisible() const { return maFillColor.IsVisible(); }
+
+ void SetWindowGraphics( AquaSalFrame* pFrame );
+ void SetPrinterGraphics( CGContextRef, long nRealDPIX, long nRealDPIY, double fFakeScale );
+ void SetVirDevGraphics( CGLayerRef, CGContextRef, int nBitDepth = 0 );
+
+ void initResolution( NSWindow* );
+ void copyResolution( AquaSalGraphics& );
+ void updateResolution();
+
+ bool IsWindowGraphics() const { return mbWindow; }
+ bool IsPrinterGraphics() const { return mbPrinter; }
+ bool IsVirDevGraphics() const { return mbVirDev; }
+ AquaSalFrame* getGraphicsFrame() const { return mpFrame; }
+ void setGraphicsFrame( AquaSalFrame* pFrame ) { mpFrame = pFrame; }
+
+ void ImplDrawPixel( long nX, long nY, const RGBAColor& ); // helper to draw single pixels
+
+ bool CheckContext();
+ void UpdateWindow( NSRect& ); // delivered in NSView coordinates
+ void RefreshRect( const CGRect& );
+ void RefreshRect( const NSRect& );
+ void RefreshRect(float lX, float lY, float lWidth, float lHeight);
+
+ void SetState();
+ void UnsetState();
+ // InvalidateContext does an UnsetState and sets mrContext to 0
+ void InvalidateContext();
+
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+
+ // draw --> LineColor and FillColor and RasterOp and ClipRegion
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( ULONG nPoly, const ULONG* pPoints, PCONSTSALPOINT* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( ULONG nPoly, const ULONG* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry );
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin );
+
+ // CopyArea --> No RasterOp, but ClipRegion
+ virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
+ long nSrcHeight, USHORT nFlags );
+
+ // CopyBits and DrawBitmap --> RasterOp and ClipRegion
+ // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
+ virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+
+ // invert --> ClipRegion (only Windows or VirDevs)
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags);
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap );
+
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency );
+
+ CGPoint* makeCGptArray(ULONG nPoints, const SalPoint* pPtAry);
+ // native widget rendering methods that require mirroring
+ virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ const Point& aPos, BOOL& rIsInside );
+ virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& aCaption,
+ Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion );
+
+ // get device resolution
+ virtual void GetResolution( long& rDPIX, long& rDPIY );
+ // get the depth of the device
+ virtual USHORT GetBitCount();
+ // get the width of the device
+ virtual long GetGraphicsWidth() const;
+
+ // set the clip region to empty
+ virtual void ResetClipRegion();
+ // begin setting the clip region, add rectangles to the
+ // region with the UnionClipRegion call
+ virtual void BeginSetClipRegion( ULONG nCount );
+ // all rectangles were added and the clip region should be set now
+ virtual void EndSetClipRegion();
+
+ // set the line color to transparent (= don't draw lines)
+ virtual void SetLineColor();
+ // set the line color to a specific color
+ virtual void SetLineColor( SalColor nSalColor );
+ // set the fill color to transparent (= don't fill)
+ virtual void SetFillColor();
+ // set the fill color to a specific color, shapes will be
+ // filled accordingly
+ virtual void SetFillColor( SalColor nSalColor );
+ // enable/disable XOR drawing
+ virtual void SetXORMode( bool bSet, bool bInvertOnly );
+ // set line color for raster operations
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ // set fill color for raster operations
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+ // set the text color to a specific color
+ virtual void SetTextColor( SalColor nSalColor );
+ // set the font
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ // get the current font's etrics
+ virtual void GetFontMetric( ImplFontMetricData* );
+ // get kernign pairs of the current font
+ // return only PairCount if (pKernPairs == NULL)
+ virtual ULONG GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs );
+ // get the repertoire of the current font
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ // graphics must fill supplied font list
+ virtual void GetDevFontList( ImplDevFontList* );
+ // graphics should call ImplAddDevFontSubstitute on supplied
+ // OutputDevice for all its device specific preferred font substitutions
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ // CreateFontSubset: a method to get a subset of glyhps of a font
+ // inside a new valid font file
+ // returns TRUE if creation of subset was successfull
+ // parameters: rToFile: contains a osl file URL to write the subset to
+ // pFont: describes from which font to create a subset
+ // pGlyphIDs: the glyph ids to be extracted
+ // pEncoding: the character code corresponding to each glyph
+ // pWidths: the advance widths of the correspoding glyphs (in PS font units)
+ // nGlyphs: the number of glyphs
+ // rInfo: additional outgoing information
+ // implementation note: encoding 0 with glyph id 0 should be added implicitly
+ // as "undefined character"
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ long* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo // out parameter
+ );
+
+ // GetFontEncodingVector: a method to get the encoding map Unicode
+ // to font encoded character; this is only used for type1 fonts and
+ // may return NULL in case of unknown encoding vector
+ // if ppNonEncoded is set and non encoded characters (that is type1
+ // glyphs with only a name) exist it is set to the corresponding
+ // map for non encoded glyphs; the encoding vector contains -1
+ // as encoding for these cases
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+
+ // GetEmbedFontData: gets the font data for a font marked
+ // embeddable by GetDevFontList or NULL in case of error
+ // parameters: pFont: describes the font in question
+ // pWidths: the widths of all glyphs from char code 0 to 255
+ // pWidths MUST support at least 256 members;
+ // rInfo: additional outgoing information
+ // pDataLen: out parameter, contains the byte length of the returned buffer
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ // frees the font data again
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+
+ virtual void GetGlyphWidths( const ImplFontData*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, basegfx::B2DPolyPolygon& );
+
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+
+ // Query the platform layer for control support
+ virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int /* nFallbacklevel */ ) const;
+
+private:
+ // differences between VCL, Quartz and kHiThemeOrientation coordinate systems
+ // make some graphics seem to be vertically-mirrored from a VCL perspective
+ bool IsFlipped() const { return mbWindow; }
+
+ void ApplyXorContext();
+ void Pattern50Fill();
+ UInt32 getState( ControlState nState );
+ UInt32 getTrackState( ControlState nState );
+};
+
+class XorEmulation
+{
+public:
+ XorEmulation();
+ /*final*/ ~XorEmulation();
+
+ void SetTarget( int nWidth, int nHeight, int nBitmapDepth, CGContextRef, CGLayerRef );
+ bool UpdateTarget();
+ void Enable() { mbIsEnabled = true; }
+ void Disable() { mbIsEnabled = false; }
+ bool IsEnabled() const { return mbIsEnabled; }
+ CGContextRef GetTargetContext() const { return mxTargetContext; }
+ CGContextRef GetMaskContext() const { return (mbIsEnabled ? mxMaskContext : NULL); }
+
+private:
+ CGLayerRef mxTargetLayer;
+ CGContextRef mxTargetContext;
+ CGContextRef mxMaskContext;
+ CGContextRef mxTempContext;
+ ULONG* mpMaskBuffer;
+ ULONG* mpTempBuffer;
+ int mnBufferLongs;
+ bool mbIsEnabled;
+};
+
+
+// --- some trivial inlines
+
+inline void AquaSalGraphics::RefreshRect( const CGRect& rRect )
+{
+ RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height );
+}
+
+inline void AquaSalGraphics::RefreshRect( const NSRect& rRect )
+{
+ RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height );
+}
+
+inline RGBAColor::RGBAColor( SalColor nSalColor )
+: mfRed( SALCOLOR_RED(nSalColor) * (1.0/255))
+, mfGreen( SALCOLOR_GREEN(nSalColor) * (1.0/255))
+, mfBlue( SALCOLOR_BLUE(nSalColor) * (1.0/255))
+, mfAlpha( 1.0 ) // opaque
+{}
+
+inline RGBAColor::RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha )
+: mfRed( fRed )
+, mfGreen( fGreen )
+, mfBlue( fBlue )
+, mfAlpha( fAlpha )
+{}
+
+#endif // _SV_SALGDI_H
diff --git a/vcl/aqua/inc/salinst.h b/vcl/aqua/inc/salinst.h
new file mode 100644
index 000000000000..0bceb99d1d0e
--- /dev/null
+++ b/vcl/aqua/inc/salinst.h
@@ -0,0 +1,202 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALINST_H
+#define _SV_SALINST_H
+
+#include "vcl/sv.h"
+#include "vos/mutex.hxx"
+#include "vos/thread.hxx"
+#include "vcl/salinst.hxx"
+#include "osl/conditn.h"
+
+#include "aquavcltypes.h"
+
+#include <list>
+
+class AquaSalFrame;
+class ApplicationEvent;
+class Image;
+
+// -----------------
+// - SalYieldMutex -
+// -----------------
+
+class SalYieldMutex : public vos::OMutex
+{
+ ULONG mnCount;
+ vos::OThread::TThreadIdentifier mnThreadId;
+
+public:
+ SalYieldMutex();
+ virtual void acquire();
+ virtual void release();
+ virtual sal_Bool tryToAcquire();
+ ULONG GetAcquireCount() const { return mnCount; }
+ vos::OThread::TThreadIdentifier GetThreadId() const { return mnThreadId; }
+};
+
+#define YIELD_GUARD vos::OGuard aGuard( GetSalData()->mpFirstInstance->GetYieldMutex() )
+
+
+// -------------------
+// - SalInstanceData -
+// -------------------
+
+//struct SalInstanceData
+//{
+//public:
+//};
+
+// ------------------
+// - AquaSalInstance -
+// ------------------
+
+class AquaSalInstance : public SalInstance
+{
+ struct SalUserEvent
+ {
+ AquaSalFrame* mpFrame;
+ void* mpData;
+ USHORT mnType;
+
+ SalUserEvent( AquaSalFrame* pFrame, void* pData, USHORT nType ) :
+ mpFrame( pFrame ), mpData( pData ), mnType( nType )
+ {}
+ };
+
+public:
+ SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex
+ rtl::OUString maDefaultPrinter;
+ vos::OThread::TThreadIdentifier maMainThread;
+ bool mbWaitingYield;
+ int mnActivePrintJobs;
+ std::list< SalUserEvent > maUserEvents;
+ oslMutex maUserEventListMutex;
+ oslCondition maWaitingYieldCond;
+
+ typedef std::list<const ApplicationEvent*> AppEventList;
+ static AppEventList aAppEventList;
+
+public:
+ AquaSalInstance();
+ virtual ~AquaSalInstance();
+
+ virtual SalSystem* CreateSystem();
+ virtual void DestroySystem(SalSystem*);
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle );
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+ virtual void DestroyFrame( SalFrame* pFrame );
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+ virtual void DestroyObject( SalObject* pObject );
+ virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData );
+ virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice );
+
+ virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData );
+ virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter );
+ virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter );
+ virtual void DestroyPrinter( SalPrinter* pPrinter );
+ virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList );
+ virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo );
+ virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo );
+ virtual String GetDefaultPrinter();
+ virtual SalTimer* CreateSalTimer();
+ virtual SalI18NImeStatus* CreateI18NImeStatus();
+ virtual SalSystem* CreateSalSystem();
+ virtual SalBitmap* CreateSalBitmap();
+ virtual vos::IMutex* GetYieldMutex();
+ virtual ULONG ReleaseYieldMutex();
+ virtual void AcquireYieldMutex( ULONG nCount );
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual bool AnyInput( USHORT nType );
+ virtual SalMenu* CreateMenu( BOOL bMenuBar );
+ virtual void DestroyMenu( SalMenu* );
+ virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData );
+ virtual void DestroyMenuItem( SalMenuItem* );
+ virtual SalSession* CreateSalSession();
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+ virtual void SetEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) );
+ virtual void SetErrorEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) );
+
+ // dtrans implementation
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface >
+ CreateClipboard( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& i_rArguments );
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDragSource();
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDropTarget();
+
+ static void handleAppDefinedEvent( NSEvent* pEvent );
+
+ // check whether a particular string is passed on the command line
+ // this is needed to avoid duplicate open events through a) command line and b) NSApp's openFile
+ static bool isOnCommandLine( const rtl::OUString& );
+
+ void wakeupYield();
+
+ public:
+ friend class AquaSalFrame;
+
+ void PostUserEvent( AquaSalFrame* pFrame, USHORT nType, void* pData );
+ void delayedSettingsChanged( bool bInvalidate );
+
+ bool isNSAppThread() const;
+
+ void startedPrintJob() { mnActivePrintJobs++; }
+ void endedPrintJob() { mnActivePrintJobs--; }
+
+ // event subtypes for NSApplicationDefined events
+ static const short AppExecuteSVMain = 0x7fff;
+ static const short AppEndLoopEvent = 1;
+ static const short AppStartTimerEvent = 10;
+ static const short AppleRemoteEvent = 15;
+ static const short YieldWakeupEvent = 20;
+
+ static NSMenu* GetDynamicDockMenu();
+};
+
+// helper class: inverted solar guard
+class YieldMutexReleaser
+{
+ ULONG mnCount;
+ public:
+ YieldMutexReleaser();
+ ~YieldMutexReleaser();
+};
+
+// helper class
+rtl::OUString GetOUString( CFStringRef );
+rtl::OUString GetOUString( NSString* );
+CFStringRef CreateCFString( const rtl::OUString& );
+NSString* CreateNSString( const rtl::OUString& );
+
+CGImageRef CreateCGImage( const Image& );
+NSImage* CreateNSImage( const Image& );
+
+#endif // _SV_SALINST_H
diff --git a/vcl/aqua/inc/salmathutils.hxx b/vcl/aqua/inc/salmathutils.hxx
new file mode 100755
index 000000000000..6106dc328740
--- /dev/null
+++ b/vcl/aqua/inc/salmathutils.hxx
@@ -0,0 +1,87 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALMATHUTILS_HXX
+#define _SV_SALMATHUTILS_HXX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ------------------------------------------------------------------
+//
+// Structures
+//
+// ------------------------------------------------------------------
+
+// LRectCoor is an abreviation for rectangular coordinates
+// represented as long integers
+
+struct LRectCoor
+{
+ long x;
+ long y;
+ long z;
+};
+
+// ------------------------------------------------------------------
+//
+// Type Definitions
+//
+// ------------------------------------------------------------------
+
+// LRectCoorVec is an abreviation for vectors in rectangular
+// coordinates represented as long integers
+
+typedef struct LRectCoor LRectCoor;
+typedef LRectCoor *LRectCoorVector;
+typedef LRectCoorVector *LRectCoorTensor;
+
+// ------------------------------------------------------------------
+//
+// Function Headers
+//
+// ------------------------------------------------------------------
+
+void CSwap ( char &rX, char &rY );
+void UCSwap ( unsigned char &rX, unsigned char &rY );
+void SSwap ( short &rX, short &rY );
+void USSwap ( unsigned short &rX, unsigned short &rY );
+void LSwap ( long &rX, long &rY );
+void ULSwap ( unsigned long &rX, unsigned long &rY );
+
+// ------------------------------------------------------------------
+
+unsigned long Euclidian2Norm ( const LRectCoorVector pVec );
+
+// ------------------------------------------------------------------
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SV_SALMATHUTILS_HXX
diff --git a/vcl/aqua/inc/salmenu.h b/vcl/aqua/inc/salmenu.h
new file mode 100644
index 000000000000..100e8c22972c
--- /dev/null
+++ b/vcl/aqua/inc/salmenu.h
@@ -0,0 +1,121 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALMENU_H
+#define _SV_SALMENU_H
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "vcl/sv.h"
+#include "vcl/salmenu.hxx"
+
+#include <vector>
+
+class AquaSalFrame;
+class AquaSalMenuItem;
+
+class AquaSalMenu : public SalMenu
+{
+ std::vector< AquaSalMenuItem* > maItems;
+
+public: // for OOStatusView
+ struct MenuBarButtonEntry
+ {
+ SalMenuButtonItem maButton;
+ NSImage* mpNSImage; // cached image
+ NSString* mpToolTipString;
+
+ MenuBarButtonEntry() : mpNSImage( nil ), mpToolTipString( nil ) {}
+ MenuBarButtonEntry( const SalMenuButtonItem& i_rItem )
+ : maButton( i_rItem), mpNSImage( nil ), mpToolTipString( nil ) {}
+ };
+private:
+ std::vector< MenuBarButtonEntry > maButtons;
+
+ MenuBarButtonEntry* findButtonItem( USHORT i_nItemId );
+ void releaseButtonEntry( MenuBarButtonEntry& i_rEntry );
+ static void statusLayout();
+public:
+ AquaSalMenu( bool bMenuBar );
+ virtual ~AquaSalMenu();
+
+ virtual BOOL VisibleMenuBar(); // must return TRUE to actually DISPLAY native menu bars
+ // otherwise only menu messages are processed (eg, OLE on Windows)
+
+ virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos );
+ virtual void RemoveItem( unsigned nPos );
+ virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos );
+ virtual void SetFrame( const SalFrame* pFrame );
+ virtual void CheckItem( unsigned nPos, BOOL bCheck );
+ virtual void EnableItem( unsigned nPos, BOOL bEnable );
+ virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText );
+ virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage);
+ virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName );
+ virtual void GetSystemMenuData( SystemMenuData* pData );
+ virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, ULONG nFlags);
+ virtual bool AddMenuBarButton( const SalMenuButtonItem& );
+ virtual void RemoveMenuBarButton( USHORT nId );
+ virtual Rectangle GetMenuBarButtonRectPixel( USHORT i_nItemId, SalFrame* i_pReferenceFrame );
+
+ int getItemIndexByPos( USHORT nPos ) const;
+ const AquaSalFrame* getFrame() const;
+
+ void setMainMenu();
+ static void unsetMainMenu();
+ static void setDefaultMenu();
+ static void enableMainMenu( bool bEnable );
+ static void addFallbackMenuItem( NSMenuItem* NewItem );
+ static void removeFallbackMenuItem( NSMenuItem* pOldItem );
+
+ const std::vector< MenuBarButtonEntry >& getButtons() const { return maButtons; }
+
+ bool mbMenuBar; // true - Menubar, false - Menu
+ NSMenu* mpMenu; // The Carbon reference to this menu
+ Menu* mpVCLMenu; // the corresponding vcl Menu object
+ const AquaSalFrame* mpFrame; // the frame to dispatch the menu events to
+ AquaSalMenu* mpParentSalMenu; // the parent menu that contains us (and perhaps has a frame)
+
+ static const AquaSalMenu* pCurrentMenuBar;
+
+};
+
+class AquaSalMenuItem : public SalMenuItem
+{
+public:
+ AquaSalMenuItem( const SalItemParams* );
+ virtual ~AquaSalMenuItem();
+
+ USHORT mnId; // Item ID
+ Menu* mpVCLMenu; // VCL Menu into which this MenuItem is inserted
+ AquaSalMenu* mpParentMenu; // The menu in which this menu item is inserted
+ AquaSalMenu* mpSubMenu; // Sub menu of this item (if defined)
+ NSMenuItem* mpMenuItem; // The NSMenuItem
+};
+
+#endif // _SV_SALMENU_H
diff --git a/vcl/aqua/inc/salnativewidgets.h b/vcl/aqua/inc/salnativewidgets.h
new file mode 100755
index 000000000000..11d4ea5c1c62
--- /dev/null
+++ b/vcl/aqua/inc/salnativewidgets.h
@@ -0,0 +1,71 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_NATIVEWIDGETS_H
+#define _SV_NATIVEWIDGETS_H
+
+// since 10.4 ... no metrics are returned, and we have to fix the values
+#define BUTTON_WIDTH 16
+#define BUTTON_HEIGHT 17
+
+//standard height of the AHIG
+//tabs
+#define TAB_HEIGHT_NORMAL 20
+#define TAB_HEIGHT_SMALL 17
+#define TAB_HEIGHT_MINI 15
+
+#define TAB_TEXT_OFFSET 12
+#define VCL_TAB_TEXT_OFFSET 2
+
+//listboxes, comboboxes (they have the same dimensions)
+#define COMBOBOX_HEIGHT_NORMAL 20
+#define DROPDOWN_BUTTON_WIDTH 20
+
+//text edit
+#define TEXT_EDIT_HEIGHT_NORMAL 22
+
+//spin box
+#define SPIN_BUTTON_SPACE 2
+#define SPIN_BUTTON_WIDTH 13
+#define SPIN_UPPER_BUTTON_HEIGHT 11
+#define SPIN_LOWER_BUTTON_HEIGHT 10
+#define SPIN_TWO_BUTTONS_HEIGHT 21
+
+// progress bar
+#define INTRO_PROGRESS_HEIGHT 9
+
+// for some controls, like spinbuttons + spinboxes, or listboxes
+// we need it to adjust text position beside radio and check buttons
+
+#define TEXT_SEPARATOR 3
+
+// extra border for focus ring
+#define FOCUS_RING_WIDTH 4
+
+#define CLIP_FUZZ 1
+
+#endif // _SV_NATIVEWIDGETS_H
diff --git a/vcl/aqua/inc/salnsmenu.h b/vcl/aqua/inc/salnsmenu.h
new file mode 100755
index 000000000000..e9b2cbe922b8
--- /dev/null
+++ b/vcl/aqua/inc/salnsmenu.h
@@ -0,0 +1,68 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_SALNSMENU_H
+#define _VCL_SALNSMENU_H
+
+class AquaSalMenu;
+class AquaSalMenuItem;
+
+@interface OOStatusItemView : NSView
+{
+}
+-(void)drawRect: (NSRect)aRect;
+-(void)layout;
+-(void)mouseUp: (NSEvent *)pEvent;
+@end
+
+@interface SalNSMenu : NSMenu
+{
+ /* Caution: SalNSMenu instances occasionally are binary copied
+ in AquaSalMenu::ShowNativePopupMenu. If any members are added,
+ please take this into account !
+ */
+ AquaSalMenu* mpMenu;
+}
+-(id)initWithMenu: (AquaSalMenu*)pMenu;
+-(void)menuNeedsUpdate: (NSMenu*)pMenu;
+-(void)setSalMenu: (AquaSalMenu*)pMenu;
+@end
+
+@interface SalNSMenuItem : NSMenuItem
+{
+ /* Caution: SalNSMenuItem instances occasionally are binary copied
+ in AquaSalMenu::ShowNativePopupMenu. If any members are added,
+ please take this into account !
+ */
+ AquaSalMenuItem* mpMenuItem;
+}
+-(id)initWithMenuItem: (AquaSalMenuItem*)pMenuItem;
+-(void)menuItemTriggered: (id)aSender;
+@end
+
+
+#endif
diff --git a/vcl/aqua/inc/salnstimer.h b/vcl/aqua/inc/salnstimer.h
new file mode 100755
index 000000000000..e29fef43b6b4
--- /dev/null
+++ b/vcl/aqua/inc/salnstimer.h
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef _VCL_SALNSTIMER_H
+#define _VCL_SALNSTIMER_H
+
+#include "premac.h"
+#include "Cocoa/Cocoa.h"
+#include "postmac.h"
+
+@interface TimerCallbackCaller : NSObject
+{
+}
+-(void)timerElapsed:(NSTimer*)pTimer;
+@end
+
+#endif
diff --git a/vcl/aqua/inc/salobj.h b/vcl/aqua/inc/salobj.h
new file mode 100644
index 000000000000..0041b22c16a0
--- /dev/null
+++ b/vcl/aqua/inc/salobj.h
@@ -0,0 +1,86 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALOBJ_H
+#define _SV_SALOBJ_H
+
+#include "vcl/sv.h"
+#include "vcl/sysdata.hxx"
+#include "vcl/salobj.hxx"
+
+class AquaSalFrame;
+class AquaSalObject;
+
+
+// -----------------
+// - SalObjectData -
+// -----------------
+
+struct SalObjectData
+{
+};
+
+class AquaSalObject : public SalObject
+{
+public:
+ AquaSalFrame* mpFrame; // parent frame
+ NSClipView* mpClipView;
+ SystemEnvData maSysData;
+
+ long mnClipX;
+ long mnClipY;
+ long mnClipWidth;
+ long mnClipHeight;
+ bool mbClip;
+
+ long mnX;
+ long mnY;
+ long mnWidth;
+ long mnHeight;
+
+
+ void setClippedPosSize();
+
+
+ AquaSalObject( AquaSalFrame* pFrame );
+ virtual ~AquaSalObject();
+
+ virtual void ResetClipRegion();
+ virtual USHORT GetClipRegionType();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight );
+ virtual void Show( BOOL bVisible );
+ virtual void Enable( BOOL nEnable );
+ virtual void GrabFocus();
+ virtual void SetBackground();
+ virtual void SetBackground( SalColor nSalColor );
+ virtual const SystemEnvData* GetSystemData() const;
+};
+
+#endif // _SV_SALOBJ_H
diff --git a/vcl/aqua/inc/salprn.h b/vcl/aqua/inc/salprn.h
new file mode 100644
index 000000000000..6bcafa2ee2e3
--- /dev/null
+++ b/vcl/aqua/inc/salprn.h
@@ -0,0 +1,171 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALPRN_H
+#define _SV_SALPRN_H
+
+#include "vcl/sv.h"
+#include "aquavcltypes.h"
+#include "vcl/salprn.hxx"
+
+#include <boost/shared_array.hpp>
+
+
+// ---------------------
+// - AquaSalInfoPrinter -
+// ---------------------
+
+class AquaSalGraphics;
+
+class AquaSalInfoPrinter : public SalInfoPrinter
+{
+ /// Printer graphics
+ AquaSalGraphics* mpGraphics;
+ /// is Graphics used
+ bool mbGraphics;
+ /// job active ?
+ bool mbJob;
+
+ /// cocoa printer object
+ NSPrinter* mpPrinter;
+ /// cocoa print info object
+ NSPrintInfo* mpPrintInfo;
+
+ /// FIXME: get real printer context for infoprinter if possible
+ /// fake context for info printer
+ /// graphics context for Quartz 2D
+ CGContextRef mrContext;
+ /// memory for graphics bitmap context for querying metrics
+ boost::shared_array< sal_uInt8 > maContextMemory;
+
+ // since changes to NSPrintInfo during a job are ignored
+ // we have to care for some settings ourselves
+ // currently we do this for orientation;
+ // really needed however is a solution for paper formats
+ Orientation mePageOrientation;
+
+ int mnStartPageOffsetX;
+ int mnStartPageOffsetY;
+ sal_Int32 mnCurPageRangeStart;
+ sal_Int32 mnCurPageRangeCount;
+
+ public:
+ AquaSalInfoPrinter( const SalPrinterQueueInfo& pInfo );
+ virtual ~AquaSalInfoPrinter();
+
+ void SetupPrinterGraphics( CGContextRef i_xContext ) const;
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* i_pGraphics );
+ virtual BOOL Setup( SalFrame* i_pFrame, ImplJobSetup* i_pSetupData );
+ virtual BOOL SetPrinterData( ImplJobSetup* pSetupData );
+ virtual BOOL SetData( ULONG i_nFlags, ImplJobSetup* i_pSetupData );
+ virtual void GetPageInfo( const ImplJobSetup* i_pSetupData,
+ long& o_rOutWidth, long& o_rOutHeight,
+ long& o_rPageOffX, long& o_rPageOffY,
+ long& o_rPageWidth, long& o_rPageHeight );
+ virtual ULONG GetCapabilities( const ImplJobSetup* i_pSetupData, USHORT i_nType );
+ virtual ULONG GetPaperBinCount( const ImplJobSetup* i_pSetupData );
+ virtual String GetPaperBinName( const ImplJobSetup* i_pSetupData, ULONG i_nPaperBin );
+ virtual void InitPaperFormats( const ImplJobSetup* i_pSetupData );
+ virtual int GetLandscapeAngle( const ImplJobSetup* i_pSetupData );
+
+ // the artificial separation between InfoPrinter and Printer
+ // is not really useful for us
+ // so let's make AquaSalPrinter just a forwarder to AquaSalInfoPrinter
+ // and concentrate the real work in one class
+ // implement pull model print system
+ BOOL StartJob( const String* i_pFileName,
+ const String& rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rController );
+ BOOL EndJob();
+ BOOL AbortJob();
+ SalGraphics* StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData );
+ BOOL EndPage();
+ ULONG GetErrorCode() const;
+
+ NSPrintInfo* getPrintInfo() const { return mpPrintInfo; }
+ void setStartPageOffset( int nOffsetX, int nOffsetY ) { mnStartPageOffsetX = nOffsetX; mnStartPageOffsetY = nOffsetY; }
+ sal_Int32 getCurPageRangeStart() const { return mnCurPageRangeStart; }
+ sal_Int32 getCurPageRangeCount() const { return mnCurPageRangeCount; }
+
+ // match width/height against known paper formats, possibly switching orientation
+ const PaperInfo* matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const;
+ void setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation );
+
+ private:
+ AquaSalInfoPrinter( const AquaSalInfoPrinter& );
+ AquaSalInfoPrinter& operator=(const AquaSalInfoPrinter&);
+};
+
+// -----------------
+// - AquaSalPrinter -
+// -----------------
+
+class AquaSalPrinter : public SalPrinter
+{
+ AquaSalInfoPrinter* mpInfoPrinter; // pointer to the compatible InfoPrinter
+ public:
+ AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter );
+ virtual ~AquaSalPrinter();
+
+ virtual BOOL StartJob( const XubString* i_pFileName,
+ const XubString& i_rJobName,
+ const XubString& i_rAppName,
+ ULONG i_nCopies,
+ bool i_bCollate,
+ bool i_bDirect,
+ ImplJobSetup* i_pSetupData );
+ // implement pull model print system
+ virtual BOOL StartJob( const String* i_pFileName,
+ const String& rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rListener );
+
+ virtual BOOL EndJob();
+ virtual BOOL AbortJob();
+ virtual SalGraphics* StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData );
+ virtual BOOL EndPage();
+ virtual ULONG GetErrorCode();
+
+ private:
+ AquaSalPrinter( const AquaSalPrinter& );
+ AquaSalPrinter& operator=(const AquaSalPrinter&);
+};
+
+const double fPtTo100thMM = 35.27777778;
+
+inline int PtTo10Mu( double nPoints ) { return (int)(((nPoints)*fPtTo100thMM)+0.5); }
+
+inline double TenMuToPt( double nUnits ) { return floor(((nUnits)/fPtTo100thMM)+0.5); }
+
+
+
+#endif // _SV_SALPRN_H
diff --git a/vcl/aqua/inc/salsys.h b/vcl/aqua/inc/salsys.h
new file mode 100644
index 000000000000..6f5c45880e68
--- /dev/null
+++ b/vcl/aqua/inc/salsys.h
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALSYS_H
+#define _SV_SALSYS_H
+
+#include "vcl/sv.h"
+#include "vcl/salsys.hxx"
+
+#include <list>
+
+// -----------------
+// - SalSystemData -
+// -----------------
+
+//struct SalSystemData
+//{
+//};
+
+class VCL_DLLPUBLIC AquaSalSystem : public SalSystem
+{
+public:
+ AquaSalSystem() {}
+ virtual ~AquaSalSystem();
+
+ // get info about the display
+ virtual unsigned int GetDisplayScreenCount();
+ virtual bool IsMultiDisplay();
+ virtual unsigned int GetDefaultDisplayNumber();
+ virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen );
+ virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen );
+
+ virtual rtl::OUString GetScreenName( unsigned int nScreen );
+ // overload pure virtual methods
+ virtual int ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton );
+ virtual int ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton);
+};
+
+
+#endif // _SV_SALSYS_H
diff --git a/vcl/aqua/inc/saltimer.h b/vcl/aqua/inc/saltimer.h
new file mode 100644
index 000000000000..374b9c5a45c5
--- /dev/null
+++ b/vcl/aqua/inc/saltimer.h
@@ -0,0 +1,54 @@
+/*************************************************************************
+*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+#ifndef _SV_SALTIMER_H
+#define _SV_SALTIMER_H
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "vcl/saltimer.hxx"
+
+class AquaSalTimer : public SalTimer
+{
+ public:
+
+ AquaSalTimer();
+ virtual ~AquaSalTimer();
+
+ void Start( ULONG nMS );
+ void Stop();
+
+ static void handleStartTimerEvent( NSEvent* pEvent );
+
+
+ static NSTimer* pRunningTimer;
+ static bool bDispatchTimer;
+};
+
+#endif
diff --git a/vcl/aqua/inc/salvd.h b/vcl/aqua/inc/salvd.h
new file mode 100644
index 000000000000..865cb7b5b766
--- /dev/null
+++ b/vcl/aqua/inc/salvd.h
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALVD_H
+#define _SV_SALVD_H
+
+#include "premac.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "postmac.h"
+
+#include "vcl/sv.h"
+#include "vcl/salgdi.hxx"
+#include "salconst.h"
+#include "salcolorutils.hxx"
+#include "vcl/salvd.hxx"
+#include "salgdi.h"
+
+#if PRAGMA_ONCE
+ #pragma once
+#endif
+
+// =======================================================================
+
+// =======================================================================
+
+// -----------------
+// - SalVirDevData -
+// -----------------
+
+struct SalVirDevData
+{
+};
+
+typedef struct SalVirDevData SalVirDevData;
+typedef SalVirDevData *SalVirDevDataPtr;
+typedef SalVirDevDataPtr *SalVirDevDataHandle;
+
+// =======================================================================
+
+class AquaSalGraphics;
+
+// -----------------
+// - SalVirDevData -
+// -----------------
+
+class AquaSalVirtualDevice : public SalVirtualDevice
+{
+private:
+ bool mbGraphicsUsed; // is Graphics used
+ bool mbForeignContext; // is mxContext from outside VCL
+ CGContextRef mxBitmapContext;
+ int mnBitmapDepth;
+ CGLayerRef mxLayer; // Quartz layer
+ AquaSalGraphics* mpGraphics; // current VirDev graphics
+
+ void Destroy();
+
+public:
+ AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData );
+ virtual ~AquaSalVirtualDevice();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL SetSize( long nNewDX, long nNewDY );
+ virtual void GetSize( long& rWidth, long& rHeight );
+};
+
+// =======================================================================
+
+#endif // _SV_SALVD_H
diff --git a/vcl/aqua/inc/svsys.h b/vcl/aqua/inc/svsys.h
new file mode 100644
index 000000000000..1edce25cea28
--- /dev/null
+++ b/vcl/aqua/inc/svsys.h
@@ -0,0 +1,35 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SVSYS_H
+#define _SV_SVSYS_H
+
+#include "premac.h"
+#include "Cocoa/Cocoa.h"
+#include "postmac.h"
+
+#endif // _SV_SVSYS_H
diff --git a/vcl/aqua/inc/vclnsapp.h b/vcl/aqua/inc/vclnsapp.h
new file mode 100755
index 000000000000..59b070b421ea
--- /dev/null
+++ b/vcl/aqua/inc/vclnsapp.h
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_VCLNSAPP_H
+#define _VCL_VCLNSAPP_H
+
+#include "premac.h"
+#include "Cocoa/Cocoa.h"
+#include "postmac.h"
+
+class AquaSalFrame;
+
+@interface CocoaThreadEnabler : NSObject
+{
+}
+-(void)enableCocoaThreads:(id)param;
+@end
+
+// our very own application
+@interface VCL_NSApplication : NSApplication
+{
+}
+-(void)sendEvent:(NSEvent*)pEvent;
+-(void)sendSuperEvent:(NSEvent*)pEvent;
+-(NSMenu*)applicationDockMenu:(NSApplication *)sender;
+-(MacOSBOOL)application: (NSApplication*) app openFile: (NSString*)file;
+-(void)application: (NSApplication*) app openFiles: (NSArray*)files;
+-(MacOSBOOL)application: (NSApplication*) app printFile: (NSString*)file;
+-(NSApplicationPrintReply)application: (NSApplication *) app printFiles:(NSArray *)files withSettings: (NSDictionary *)printSettings showPrintPanels:(MacOSBOOL)bShowPrintPanels;
+-(NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *) app;
+-(void)systemColorsChanged: (NSNotification*) pNotification;
+-(void)screenParametersChanged: (NSNotification*) pNotification;
+-(void)scrollbarVariantChanged: (NSNotification*) pNotification;
+-(void)scrollbarSettingsChanged: (NSNotification*) pNotification;
+-(void)addFallbackMenuItem: (NSMenuItem*)pNewItem;
+-(void)removeFallbackMenuItem: (NSMenuItem*)pOldItem;
+-(void)addDockMenuItem: (NSMenuItem*)pNewItem;
+-(void)applicationWillBecomeActive: (NSNotification *)pNotification;
+-(void)applicationWillResignActive: (NSNotification *)pNotification;
+-(MacOSBOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (MacOSBOOL)bWinVisible;
+-(void)setDockIconClickHandler: (NSObject*)pHandler;
+-(void)cycleFrameForward: (AquaSalFrame*)pCurFrame;
+-(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame;
+@end
+
+#endif
diff --git a/vcl/aqua/source/a11y/aqua11yactionwrapper.h b/vcl/aqua/source/a11y/aqua11yactionwrapper.h
new file mode 100644
index 000000000000..3a7f13f8a545
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yactionwrapper.h
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11ACTIONWRAPPER_H
+#define _SV_AQUA11ACTIONWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yActionWrapper : NSObject
+{
+}
++(NSArray *)actionNamesForElement:(AquaA11yWrapper *)wrapper;
++(void)doAction:(NSString *)action ofElement:(AquaA11yWrapper *)wrapper;
+@end
+
+#endif // _SV_AQUA11ACTIONWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yactionwrapper.mm b/vcl/aqua/source/a11y/aqua11yactionwrapper.mm
new file mode 100644
index 000000000000..fcd49fd67ff4
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yactionwrapper.mm
@@ -0,0 +1,83 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11yactionwrapper.h"
+
+// Wrapper for XAccessibleAction
+
+@implementation AquaA11yActionWrapper : NSObject
+
++(NSString *)nativeActionNameFor:(NSString *)actionName {
+ // TODO: Optimize ?
+ // Use NSAccessibilityActionDescription
+ if ( [ actionName isEqualToString: @"click" ] ) {
+ return NSAccessibilityPressAction;
+ } else if ( [ actionName isEqualToString: @"togglePopup" ] ) {
+ return NSAccessibilityShowMenuAction;
+ } else if ( [ actionName isEqualToString: @"select" ] ) {
+ return NSAccessibilityPickAction;
+ } else if ( [ actionName isEqualToString: @"incrementLine" ] ) {
+ return NSAccessibilityIncrementAction;
+ } else if ( [ actionName isEqualToString: @"decrementLine" ] ) {
+ return NSAccessibilityDecrementAction;
+ } else if ( [ actionName isEqualToString: @"incrementBlock" ] ) {
+ return NSAccessibilityIncrementAction; // TODO ?
+ } else if ( [ actionName isEqualToString: @"decrementBlock" ] ) {
+ return NSAccessibilityDecrementAction; // TODO ?
+ } else if ( [ actionName isEqualToString: @"Browse" ] ) {
+ return NSAccessibilityPressAction; // TODO ?
+ } else {
+ return [ NSString string ];
+ }
+}
+
++(NSArray *)actionNamesForElement:(AquaA11yWrapper *)wrapper {
+ NSMutableArray * actionNames = [ [ NSMutableArray alloc ] init ];
+ if ( [ wrapper accessibleAction ] != nil ) {
+ for ( int cnt = 0; cnt < [ wrapper accessibleAction ] -> getAccessibleActionCount(); cnt++ ) {
+ [ actionNames addObject: [ AquaA11yActionWrapper nativeActionNameFor: CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) ] ];
+ }
+ }
+ return actionNames;
+}
+
++(void)doAction:(NSString *)action ofElement:(AquaA11yWrapper *)wrapper {
+ if ( [ wrapper accessibleAction ] != nil ) {
+ for ( int cnt = 0; cnt < [ wrapper accessibleAction ] -> getAccessibleActionCount(); cnt++ ) {
+ if ( [ action isEqualToString: [ AquaA11yActionWrapper nativeActionNameFor: CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) ] ] ) {
+ [ wrapper accessibleAction ] -> doAccessibleAction ( cnt );
+ break;
+ }
+ }
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ycomponentwrapper.h b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.h
new file mode 100644
index 000000000000..c1806054e253
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.h
@@ -0,0 +1,45 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11COMPONENTWRAPPER_H
+#define _SV_AQUA11COMPONENTWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yComponentWrapper : NSObject
+{
+}
++(id)sizeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)positionAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)descriptionAttributeForElement:(AquaA11yWrapper *)wrapper;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setFocusedAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11COMPONENTWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm
new file mode 100644
index 000000000000..a700b0b89ae9
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm
@@ -0,0 +1,110 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua11ycomponentwrapper.h"
+#include "aqua11yrolehelper.h"
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::uno;
+
+// Wrapper for XAccessibleComponent and XAccessibleExtendedComponent
+
+@implementation AquaA11yComponentWrapper : NSObject
+
++(id)sizeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ Size size = [ wrapper accessibleComponent ] -> getSize();
+ NSSize nsSize = NSMakeSize ( (float) size.Width, (float) size.Height );
+ return [ NSValue valueWithSize: nsSize ];
+}
+
+// TODO: should be merged with AquaSalFrame::VCLToCocoa... to a general helper method
++(id)positionAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // VCL coordinates are in upper-left-notation, Cocoa likes it the Cartesian way (lower-left)
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ Size size = [ wrapper accessibleComponent ] -> getSize();
+ Point location = [ wrapper accessibleComponent ] -> getLocationOnScreen();
+ NSPoint nsPoint = NSMakePoint ( (float) location.X, (float) ( screenRect.size.height - size.Height - location.Y ) );
+ return [ NSValue valueWithPoint: nsPoint ];
+}
+
++(id)descriptionAttributeForElement:(AquaA11yWrapper *)wrapper {
+ if ( [ wrapper accessibleExtendedComponent ] != nil ) {
+ return CreateNSString ( [ wrapper accessibleExtendedComponent ] -> getToolTipText() );
+ } else {
+ return nil;
+ }
+}
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilitySizeAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityEnabledAttribute,
+ nil ] ];
+ [ pool release ];
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
+ MacOSBOOL isSettable = NO;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ if ( [ attribute isEqualToString: NSAccessibilityFocusedAttribute ]
+ && ! [ [ AquaA11yRoleHelper getNativeRoleFrom: [ wrapper accessibleContext ] ] isEqualToString: NSAccessibilityScrollBarRole ]
+ && ! [ [ AquaA11yRoleHelper getNativeRoleFrom: [ wrapper accessibleContext ] ] isEqualToString: NSAccessibilityStaticTextRole ] ) {
+ isSettable = YES;
+ }
+ [ pool release ];
+ return isSettable;
+}
+
++(void)setFocusedAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ if ( [ value boolValue ] == YES ) {
+ if ( [ wrapper accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ // special treatment for comboboxes: find the corresponding PANEL and set focus to it
+ Reference < XAccessible > rxParent = [ wrapper accessibleContext ] -> getAccessibleParent();
+ if ( rxParent.is() ) {
+ Reference < XAccessibleContext > rxContext = rxParent->getAccessibleContext();
+ if ( rxContext.is() && rxContext -> getAccessibleRole() == AccessibleRole::PANEL ) {
+ Reference < XAccessibleComponent > rxComponent = Reference < XAccessibleComponent > ( rxParent -> getAccessibleContext(), UNO_QUERY );
+ if ( rxComponent.is() ) {
+ rxComponent -> grabFocus();
+ }
+ }
+ }
+ } else {
+ [ wrapper accessibleComponent ] -> grabFocus();
+ }
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yfactory.mm b/vcl/aqua/source/a11y/aqua11yfactory.mm
new file mode 100644
index 000000000000..7732ce202cd2
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfactory.mm
@@ -0,0 +1,198 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11yfactory.h"
+#include "aqua11yfocuslistener.hxx"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11yrolehelper.h"
+#include "aqua11ywrapperbutton.h"
+#include "aqua11ywrapperstatictext.h"
+#include "aqua11ywrappertextarea.h"
+#include "aqua11ywrappercheckbox.h"
+#include "aqua11ywrappercombobox.h"
+#include "aqua11ywrappergroup.h"
+#include "aqua11ywrapperlist.h"
+#include "aqua11ywrapperradiobutton.h"
+#include "aqua11ywrapperradiogroup.h"
+#include "aqua11ywrapperrow.h"
+#include "aqua11ywrapperscrollarea.h"
+#include "aqua11ywrapperscrollbar.h"
+#include "aqua11ywrappersplitter.h"
+#include "aqua11ywrappertabgroup.h"
+#include "aqua11ywrappertoolbar.h"
+#include "aqua11ytablewrapper.h"
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+static bool enabled = false;
+
+@implementation AquaA11yFactory : NSObject
+
+#pragma mark -
+#pragma mark Wrapper Repository
+
++(NSMutableDictionary *)allWrapper {
+ static NSMutableDictionary * mdAllWrapper = nil;
+ if ( mdAllWrapper == nil ) {
+ mdAllWrapper = [ [ [ NSMutableDictionary alloc ] init ] retain ];
+ // initialize keyboard focus tracker
+ rtl::Reference< AquaA11yFocusListener > listener( AquaA11yFocusListener::get() );
+ AquaA11yFocusTracker::get().setFocusListener(listener.get());
+ enabled = true;
+ }
+ return mdAllWrapper;
+}
+
++(NSValue *)keyForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ return [ NSValue valueWithPointer: rxAccessibleContext.get() ];
+}
+
++(NSValue *)keyForAccessibleContextAsRadioGroup: (Reference < XAccessibleContext >) rxAccessibleContext {
+ return [ NSValue valueWithPointer: ( rxAccessibleContext.get() + 2 ) ];
+}
+
++(AquaA11yWrapper *)wrapperForAccessible: (Reference < XAccessible >) rxAccessible {
+ if ( rxAccessible.is() ) {
+ Reference< XAccessibleContext > xAccessibleContext = rxAccessible->getAccessibleContext();
+ if( xAccessibleContext.is() ) {
+ return [ AquaA11yFactory wrapperForAccessibleContext: xAccessibleContext ];
+ }
+ }
+ return nil;
+}
+
++(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ return [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: YES asRadioGroup: NO ];
+}
+
++(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate {
+ return [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: bCreate asRadioGroup: NO ];
+}
+
++(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate asRadioGroup:(MacOSBOOL) asRadioGroup{
+ NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ];
+ NSValue * nKey = nil;
+ if ( asRadioGroup ) {
+ nKey = [ AquaA11yFactory keyForAccessibleContextAsRadioGroup: rxAccessibleContext ];
+ } else {
+ nKey = [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ];
+ }
+ AquaA11yWrapper * aWrapper = (AquaA11yWrapper *) [ dAllWrapper objectForKey: nKey ];
+ if ( aWrapper != nil ) {
+ [ aWrapper retain ];
+ } else if ( bCreate ) {
+ NSString * nativeRole = [ AquaA11yRoleHelper getNativeRoleFrom: rxAccessibleContext.get() ];
+ // TODO: reflection
+ if ( [ nativeRole isEqualToString: NSAccessibilityButtonRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperButton alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityTextAreaRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperTextArea alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityStaticTextRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperStaticText alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityComboBoxRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperComboBox alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityGroupRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperGroup alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityToolbarRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperToolbar alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityScrollAreaRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperScrollArea alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityTabGroupRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperTabGroup alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityScrollBarRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperScrollBar alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityCheckBoxRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperCheckBox alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityRadioGroupRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperRadioGroup alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityRadioButtonRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperRadioButton alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityRowRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperRow alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityListRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperList alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilitySplitterRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperSplitter alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityTableRole ] ) {
+ aWrapper = [ [ AquaA11yTableWrapper alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else {
+ aWrapper = [ [ AquaA11yWrapper alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ }
+ [ nativeRole release ];
+ [ aWrapper setActsAsRadioGroup: asRadioGroup ];
+ #if 0
+ /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children.
+ That means we need to cache this, else e.g. tree list boxes are not accessible (moreover
+ it crashes by notifying dead objects - which would seemt o be another bug)
+
+ FIXME:
+ Unfortunately this can increase memory consumption drastically until the non transient parent
+ is destroyed an finally all the transients are released.
+ */
+ if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) )
+ #endif
+ {
+ [ dAllWrapper setObject: aWrapper forKey: nKey ];
+ }
+ }
+ return aWrapper;
+}
+
++(void)insertIntoWrapperRepository: (NSView *) viewElement forAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ];
+ [ dAllWrapper setObject: viewElement forKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ];
+}
+
++(void)removeFromWrapperRepositoryFor: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext {
+ // TODO: when RADIO_BUTTON search for associated RadioGroup-wrapper and delete that as well
+ AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: NO ];
+ if ( theWrapper != nil ) {
+ [ [ AquaA11yFactory allWrapper ] removeObjectForKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ];
+ [ theWrapper release ];
+ }
+}
+
++(void)registerView: (NSView *) theView {
+ if ( enabled && [ theView isKindOfClass: [ AquaA11yWrapper class ] ] ) {
+ // insertIntoWrapperRepository gets called from SalFrameView itself to bootstrap the bridge initially
+ [ (AquaA11yWrapper *) theView accessibleContext ];
+ }
+}
+
++(void)revokeView: (NSView *) theView {
+ if ( enabled && [ theView isKindOfClass: [ AquaA11yWrapper class ] ] ) {
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ (AquaA11yWrapper *) theView accessibleContext ] ];
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yfocuslistener.cxx b/vcl/aqua/source/a11y/aqua11yfocuslistener.cxx
new file mode 100644
index 000000000000..9ac9401abd62
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfocuslistener.cxx
@@ -0,0 +1,118 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua11yfocuslistener.hxx"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11yfactory.h"
+
+#include <salhelper/refobj.hxx>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+
+rtl::Reference< AquaA11yFocusListener > AquaA11yFocusListener::theListener;
+
+//------------------------------------------------------------------------------
+
+rtl::Reference< AquaA11yFocusListener > AquaA11yFocusListener::get()
+{
+ if ( ! theListener.is() )
+ theListener = new AquaA11yFocusListener();
+
+ return theListener;
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yFocusListener::AquaA11yFocusListener() : m_focusedObject(nil)
+{
+}
+
+//------------------------------------------------------------------------------
+
+id AquaA11yFocusListener::getFocusedUIElement()
+{
+ if ( nil == m_focusedObject ) {
+ Reference< XAccessible > xAccessible( AquaA11yFocusTracker::get().getFocusedObject() );
+ try {
+ if( xAccessible.is() ) {
+ Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+ if( xContext.is() )
+ m_focusedObject = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
+ }
+ } catch( RuntimeException ) {
+ // intentionally do nothing ..
+ }
+ }
+
+ return m_focusedObject;
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+AquaA11yFocusListener::focusedObjectChanged(const Reference< XAccessible >& xAccessible)
+{
+ if ( nil != m_focusedObject ) {
+ [ m_focusedObject release ];
+ m_focusedObject = nil;
+ }
+
+ try {
+ if( xAccessible.is() ) {
+ Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+ if( xContext.is() )
+ {
+ m_focusedObject = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
+ NSAccessibilityPostNotification(m_focusedObject, NSAccessibilityFocusedUIElementChangedNotification);
+ }
+ }
+ } catch( RuntimeException ) {
+ // intentionally do nothing ..
+ }
+}
+
+//------------------------------------------------------------------------------
+
+oslInterlockedCount SAL_CALL
+AquaA11yFocusListener::acquire() SAL_THROW(())
+{
+ return ReferenceObject::acquire();
+}
+
+//------------------------------------------------------------------------------
+
+oslInterlockedCount SAL_CALL
+AquaA11yFocusListener::release() SAL_THROW(())
+{
+ return ReferenceObject::release();
+}
+
diff --git a/vcl/aqua/source/a11y/aqua11yfocuslistener.hxx b/vcl/aqua/source/a11y/aqua11yfocuslistener.hxx
new file mode 100644
index 000000000000..1fdd340c698e
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfocuslistener.hxx
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _AQUA11YFOCUSLISTENER_HXX_
+#define _AQUA11YFOCUSLISTENER_HXX_
+
+#include <salhelper/refobj.hxx>
+
+#include "keyboardfocuslistener.hxx"
+#include "aquavcltypes.h"
+
+// #include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+class AquaA11yFocusListener :
+ public KeyboardFocusListener,
+ public salhelper::ReferenceObject
+{
+ id m_focusedObject;
+
+ static rtl::Reference< AquaA11yFocusListener > theListener;
+
+ AquaA11yFocusListener::AquaA11yFocusListener();
+ virtual AquaA11yFocusListener::~AquaA11yFocusListener() {};
+public:
+
+ static rtl::Reference< AquaA11yFocusListener > get();
+
+ id getFocusedUIElement();
+
+ // KeyboardFocusListener
+ virtual void SAL_CALL focusedObjectChanged(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible);
+
+ // rtl::IReference
+ virtual oslInterlockedCount SAL_CALL acquire() SAL_THROW(());
+ virtual oslInterlockedCount SAL_CALL release() SAL_THROW(());
+};
+
+#endif // _AQUA11YFOCUSLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/source/a11y/aqua11yfocustracker.cxx b/vcl/aqua/source/a11y/aqua11yfocustracker.cxx
new file mode 100644
index 000000000000..2a8ebb39bd80
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfocustracker.cxx
@@ -0,0 +1,278 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua11yfocustracker.hxx"
+#include "documentfocuslistener.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+#include "vcl/svapp.hxx"
+#include "vcl/window.hxx"
+#include "vcl/toolbox.hxx"
+#include "vcl/menu.hxx"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+//------------------------------------------------------------------------------
+
+static inline Window *
+getWindow(const ::VclSimpleEvent *pEvent)
+{
+ return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow();
+}
+
+
+//------------------------------------------------------------------------------
+
+// callback function for Application::addEventListener
+
+long AquaA11yFocusTracker::WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent)
+{
+ switch (pEvent->GetId())
+ {
+ case VCLEVENT_WINDOW_PAINT:
+ pFocusTracker-> toolbox_open_floater( getWindow(pEvent) );
+ break;
+ case VCLEVENT_WINDOW_GETFOCUS:
+ pFocusTracker->window_got_focus( getWindow(pEvent) );
+ break;
+ case VCLEVENT_OBJECT_DYING:
+ pFocusTracker->m_aDocumentWindowList.erase( getWindow(pEvent) );
+ // intentional pass through ..
+ case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
+ pFocusTracker->toolbox_highlight_off( getWindow(pEvent) );
+ break;
+ case VCLEVENT_TOOLBOX_HIGHLIGHT:
+ pFocusTracker->toolbox_highlight_on( getWindow(pEvent) );
+ break;
+ case VCLEVENT_TABPAGE_ACTIVATE:
+ pFocusTracker->tabpage_activated( getWindow(pEvent) );
+ break;
+ case VCLEVENT_MENU_HIGHLIGHT:
+ pFocusTracker->menu_highlighted( static_cast < const VclMenuEvent * > (pEvent) );
+ break;
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yFocusTracker::AquaA11yFocusTracker() :
+ m_aWindowEventLink(this, (PSTUB) WindowEventHandler),
+ m_xDocumentFocusListener(new DocumentFocusListener(*this))
+{
+ Application::AddEventListener(m_aWindowEventLink);
+ window_got_focus(Application::GetFocusWindow());
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible)
+{
+ if( xAccessible != m_xFocusedObject )
+ {
+ m_xFocusedObject = xAccessible;
+
+ if( m_aFocusListener.is() )
+ m_aFocusListener->focusedObjectChanged(xAccessible);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)
+{
+ Reference< XAccessible > xAccessible( pToolBox->GetAccessible() );
+
+ if( xAccessible.is() )
+ {
+ Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+
+ if( xContext.is() )
+ {
+ sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
+ if( nPos != TOOLBOX_ITEM_NOTFOUND )
+ setFocusedObject( xContext->getAccessibleChild( nPos ) );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::toolbox_open_floater(Window *pWindow)
+{
+ bool bToolboxFound = false;
+ bool bFloatingWindowFound = false;
+ Window * pFloatingWindow = NULL;
+ while ( pWindow != NULL ) {
+ if ( pWindow->GetType() == WINDOW_TOOLBOX ) {
+ bToolboxFound = true;
+ } else if ( pWindow->GetType() == WINDOW_FLOATINGWINDOW ) {
+ bFloatingWindowFound = true;
+ pFloatingWindow = pWindow;
+ }
+ pWindow = pWindow->GetParent();
+ }
+ if ( bToolboxFound && bFloatingWindowFound ) {
+ Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible();
+ if ( ! rxAccessible.is() ) {
+ return;
+ }
+ Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext();
+ if ( ! rxContext.is() ) {
+ return;
+ }
+ if ( rxContext -> getAccessibleChildCount() > 0 ) {
+ Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
+ if ( ! rxAccessibleChild.is() ) {
+ return;
+ }
+ setFocusedObject ( rxAccessibleChild );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::toolbox_highlight_on(Window *pWindow)
+{
+ // Make sure either the toolbox or its parent toolbox has the focus
+ if ( ! pWindow->HasFocus() )
+ {
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
+ if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
+ return;
+ }
+
+ notify_toolbox_item_focus(static_cast <ToolBox *> (pWindow));
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::toolbox_highlight_off(Window *pWindow)
+{
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
+
+ // Notify when leaving sub toolboxes
+ if( pToolBoxParent && pToolBoxParent->HasFocus() )
+ notify_toolbox_item_focus( pToolBoxParent );
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::tabpage_activated(Window *pWindow)
+{
+ Reference< XAccessible > xAccessible( pWindow->GetAccessible() );
+
+ if( xAccessible.is() )
+ {
+ Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY);
+
+ if( xSelection.is() )
+ setFocusedObject( xSelection->getSelectedAccessibleChild(0) );
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent)
+{
+ Menu * pMenu = pEvent->GetMenu();
+
+ if( pMenu )
+ {
+ Reference< XAccessible > xAccessible( pMenu->GetAccessible() );
+
+ if( xAccessible.is() )
+ setFocusedObject( xAccessible );
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::window_got_focus(Window *pWindow)
+{
+ // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
+ if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
+ return;
+
+ // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
+ if( pWindow->GetType() == WINDOW_TOOLBOX )
+ return;
+
+ if( pWindow->GetType() == WINDOW_TABCONTROL )
+ {
+ tabpage_activated( pWindow );
+ return;
+ }
+
+ Reference< XAccessible > xAccessible(pWindow->GetAccessible());
+
+ if( ! xAccessible.is() )
+ return;
+
+ Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
+
+ if( ! xContext.is() )
+ return;
+
+ Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
+
+ if( ! xStateSet.is() )
+ return;
+
+/* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
+ * need to add listeners to the children instead of re-using the tabpage stuff
+ */
+ if( xStateSet->contains(AccessibleStateType::FOCUSED) && (pWindow->GetType() != WINDOW_TREELISTBOX) )
+ {
+ setFocusedObject( xAccessible );
+ }
+ else
+ {
+ if( m_aDocumentWindowList.find(pWindow) == m_aDocumentWindowList.end() )
+ {
+ m_aDocumentWindowList.insert(pWindow);
+ m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
+ }
+#ifdef ENABLE_TRACING
+ else
+ fprintf(stderr, "Window %p already in the list\n", pWindow );
+#endif
+ }
+}
diff --git a/vcl/aqua/source/a11y/aqua11ylistener.cxx b/vcl/aqua/source/a11y/aqua11ylistener.cxx
new file mode 100644
index 000000000000..7f680f43b3a6
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ylistener.cxx
@@ -0,0 +1,158 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "aqua11ylistener.hxx"
+#include "aqua11yfactory.h"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11ytextwrapper.h"
+#include "aqua11ywrapper.h"
+#include "salinst.h"
+
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+NSString * getTableNotification( const AccessibleEventObject& aEvent )
+{
+ AccessibleTableModelChange aChange;
+ NSString * notification = nil;
+
+ if( (aEvent.NewValue >>= aChange) &&
+ ( AccessibleTableModelChangeType::INSERT == aChange.Type || AccessibleTableModelChangeType::DELETE == aChange.Type ) &&
+ aChange.FirstRow != aChange.LastRow )
+ {
+ notification = NSAccessibilityRowCountChangedNotification;
+ }
+
+ return notification;
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yEventListener::AquaA11yEventListener(id wrapperObject, sal_Int16 role) : m_wrapperObject(wrapperObject), m_role(role)
+{
+ [ m_wrapperObject retain ];
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yEventListener::~AquaA11yEventListener()
+{
+ [ m_wrapperObject release ];
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+AquaA11yEventListener::disposing( const EventObject& Source ) throw( RuntimeException )
+{
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ (AquaA11yWrapper *) m_wrapperObject accessibleContext ] ];
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+AquaA11yEventListener::notifyEvent( const AccessibleEventObject& aEvent ) throw( RuntimeException )
+{
+ NSString * notification = nil;
+ id element = m_wrapperObject;
+ Rectangle bounds;
+
+ // TODO: NSAccessibilityValueChanged, NSAccessibilitySelectedRowsChangedNotification
+ switch( aEvent.EventId )
+ {
+ case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED:
+ if( m_role != AccessibleRole::LIST ) {
+ Reference< XAccessible > xAccessible;
+ if( aEvent.NewValue >>= xAccessible )
+ AquaA11yFocusTracker::get().setFocusedObject( xAccessible );
+ }
+ break;
+
+ case AccessibleEventId::NAME_CHANGED:
+ notification = NSAccessibilityTitleChangedNotification;
+ break;
+
+ case AccessibleEventId::CHILD:
+ // only needed for tooltips (says Apple)
+ if ( m_role == AccessibleRole::TOOL_TIP ) {
+ if(aEvent.NewValue.hasValue()) {
+ notification = NSAccessibilityCreatedNotification;
+ } else if(aEvent.OldValue.hasValue()) {
+ notification = NSAccessibilityUIElementDestroyedNotification;
+ }
+ }
+ break;
+
+ case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+ // TODO: depricate or remember all children
+ break;
+
+ case AccessibleEventId::BOUNDRECT_CHANGED:
+ bounds = [ element accessibleComponent ] -> getBounds();
+ if ( m_oldBounds.X != 0 && ( bounds.X != m_oldBounds.X || bounds.Y != m_oldBounds.Y ) ) {
+ NSAccessibilityPostNotification(element, NSAccessibilityMovedNotification); // post directly since both cases can happen simultaneously
+ }
+ if ( m_oldBounds.X != 0 && ( bounds.Width != m_oldBounds.Width || bounds.Height != m_oldBounds.Height ) ) {
+ NSAccessibilityPostNotification(element, NSAccessibilityResizedNotification); // post directly since both cases can happen simultaneously
+ }
+ m_oldBounds = bounds;
+ break;
+
+ case AccessibleEventId::SELECTION_CHANGED:
+ notification = NSAccessibilitySelectedChildrenChangedNotification;
+ break;
+
+ case AccessibleEventId::TEXT_SELECTION_CHANGED:
+ notification = NSAccessibilitySelectedTextChangedNotification;
+ break;
+
+ case AccessibleEventId::TABLE_MODEL_CHANGED:
+ notification = getTableNotification(aEvent);
+ break;
+
+ case AccessibleEventId::CARET_CHANGED:
+ notification = NSAccessibilitySelectedTextChangedNotification;
+ break;
+
+ case AccessibleEventId::TEXT_CHANGED:
+ notification = NSAccessibilityValueChangedNotification;
+ break;
+
+ default:
+ break;
+ }
+
+ if( nil != notification )
+ NSAccessibilityPostNotification(element, notification);
+}
diff --git a/vcl/aqua/source/a11y/aqua11yrolehelper.h b/vcl/aqua/source/a11y/aqua11yrolehelper.h
new file mode 100644
index 000000000000..f847eb3f41c3
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yrolehelper.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11ROLEHELPER_H
+#define _SV_AQUA11ROLEHELPER_H
+
+#include "salinst.h"
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+@interface AquaA11yRoleHelper : NSObject
+{
+}
++(id)getNativeRoleFrom: (::com::sun::star::accessibility::XAccessibleContext *) accessibleContext;
++(id)getNativeSubroleFrom: (sal_Int16) nRole;
++(id)getRoleDescriptionFrom: (NSString *) role with: (NSString *) subRole;
+@end
+
+#endif // _SV_AQUA11ROLEHELPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yrolehelper.mm b/vcl/aqua/source/a11y/aqua11yrolehelper.mm
new file mode 100644
index 000000000000..b8ebdb08c3df
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yrolehelper.mm
@@ -0,0 +1,272 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua11yrolehelper.h"
+#include "aqua11yfactory.h"
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+@implementation AquaA11yRoleHelper
+
++(id)simpleMapNativeRoleFrom: (XAccessibleContext *) accessibleContext {
+ id nativeRole = nil;
+ switch( accessibleContext -> getAccessibleRole() ) {
+#define MAP(a,b) \
+ case a: nativeRole = b; break
+
+ MAP( AccessibleRole::UNKNOWN, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::ALERT, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::COLUMN_HEADER, NSAccessibilityColumnRole );
+ MAP( AccessibleRole::CANVAS, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::CHECK_BOX, NSAccessibilityCheckBoxRole );
+ MAP( AccessibleRole::CHECK_MENU_ITEM, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::COLOR_CHOOSER, NSAccessibilityColorWellRole ); // FIXME
+ MAP( AccessibleRole::COMBO_BOX, NSAccessibilityComboBoxRole );
+ MAP( AccessibleRole::DATE_EDITOR, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DESKTOP_ICON, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DESKTOP_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DIRECTORY_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DIALOG, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::DOCUMENT, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::EMBEDDED_OBJECT, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::END_NOTE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FILE_CHOOSER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FILLER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FONT_CHOOSER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FOOTER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FOOTNOTE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FRAME, NSAccessibilityWindowRole );
+ MAP( AccessibleRole::GLASS_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::GRAPHIC, NSAccessibilityImageRole );
+ MAP( AccessibleRole::GROUP_BOX, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::HEADER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::HEADING, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::HYPER_LINK, NSAccessibilityLinkRole );
+ MAP( AccessibleRole::ICON, NSAccessibilityImageRole );
+ MAP( AccessibleRole::INTERNAL_FRAME, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::LABEL, NSAccessibilityStaticTextRole );
+ MAP( AccessibleRole::LAYERED_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::LIST, NSAccessibilityMenuRole );
+ MAP( AccessibleRole::LIST_ITEM, NSAccessibilityMenuItemRole );
+ MAP( AccessibleRole::MENU, NSAccessibilityMenuRole );
+ MAP( AccessibleRole::MENU_BAR, NSAccessibilityMenuBarRole );
+ MAP( AccessibleRole::MENU_ITEM, NSAccessibilityMenuItemRole );
+ MAP( AccessibleRole::OPTION_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::PAGE_TAB, NSAccessibilityButtonRole );
+ MAP( AccessibleRole::PAGE_TAB_LIST, NSAccessibilityTabGroupRole );
+ MAP( AccessibleRole::PANEL, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::PARAGRAPH, NSAccessibilityTextAreaRole );
+ MAP( AccessibleRole::PASSWORD_TEXT, NSAccessibilityTextFieldRole );
+ MAP( AccessibleRole::POPUP_MENU, NSAccessibilityMenuRole );
+ MAP( AccessibleRole::PUSH_BUTTON, NSAccessibilityButtonRole );
+ MAP( AccessibleRole::PROGRESS_BAR, NSAccessibilityProgressIndicatorRole );
+ MAP( AccessibleRole::RADIO_BUTTON, NSAccessibilityRadioButtonRole );
+ MAP( AccessibleRole::RADIO_MENU_ITEM, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::ROW_HEADER, NSAccessibilityRowRole );
+ MAP( AccessibleRole::ROOT_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::SCROLL_BAR, NSAccessibilityScrollBarRole );
+ MAP( AccessibleRole::SCROLL_PANE, NSAccessibilityScrollAreaRole );
+ MAP( AccessibleRole::SHAPE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::SEPARATOR, NSAccessibilitySplitterRole ); // FIXME
+ MAP( AccessibleRole::SLIDER, NSAccessibilitySliderRole );
+ MAP( AccessibleRole::SPIN_BOX, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::SPLIT_PANE, NSAccessibilitySplitterRole );
+ MAP( AccessibleRole::STATUS_BAR, NSAccessibilityGroupRole ); // FIXME
+ MAP( AccessibleRole::TABLE, NSAccessibilityTableRole );
+ MAP( AccessibleRole::TABLE_CELL, NSAccessibilityTextFieldRole );
+ MAP( AccessibleRole::TEXT, NSAccessibilityTextAreaRole );
+ MAP( AccessibleRole::TEXT_FRAME, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::TOGGLE_BUTTON, NSAccessibilityCheckBoxRole );
+ MAP( AccessibleRole::TOOL_BAR, NSAccessibilityToolbarRole );
+ MAP( AccessibleRole::TOOL_TIP, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::TREE, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::VIEW_PORT, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::WINDOW, NSAccessibilityWindowRole );
+
+ MAP( AccessibleRole::BUTTON_DROPDOWN, NSAccessibilityMenuButtonRole );
+ MAP( AccessibleRole::BUTTON_MENU, NSAccessibilityMenuButtonRole );
+ MAP( AccessibleRole::CAPTION, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::CHART, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::FORM, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::IMAGE_MAP, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::NOTE, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::PAGE, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::RULER, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::SECTION, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::TREE_ITEM, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::TREE_TABLE, NSAccessibilityUnknownRole );
+
+#undef MAP
+ default:
+ break;
+ }
+ return nativeRole;
+}
+
++(id)getNativeRoleFrom: (XAccessibleContext *) accessibleContext {
+ id nativeRole = [ AquaA11yRoleHelper simpleMapNativeRoleFrom: accessibleContext ];
+ if ( accessibleContext -> getAccessibleRole() == AccessibleRole::LABEL ) {
+ if ( accessibleContext -> getAccessibleChildCount() > 0 ) {
+ [ nativeRole release ];
+ nativeRole = NSAccessibilityOutlineRole;
+ } else if ( accessibleContext -> getAccessibleParent().is() ) {
+ Reference < XAccessibleContext > rxParentContext = accessibleContext -> getAccessibleParent() -> getAccessibleContext();
+ if ( rxParentContext.is() ) {
+ NSString * roleParent = (NSString *) [ AquaA11yRoleHelper simpleMapNativeRoleFrom: rxParentContext.get() ];
+ if ( [ roleParent isEqualToString: NSAccessibilityOutlineRole ] ) {
+ [ nativeRole release ];
+ nativeRole = NSAccessibilityRowRole;
+ }
+ [ roleParent release ];
+ }
+ }
+ } else if ( accessibleContext -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ Reference < XAccessible > rxAccessible = accessibleContext -> getAccessibleChild(0);
+ if ( rxAccessible.is() ) {
+ Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
+ if ( rxAccessibleContext.is() && rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TEXT ) {
+ if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::EDITABLE ) ) {
+ [ nativeRole release ];
+ nativeRole = NSAccessibilityPopUpButtonRole;
+ }
+ }
+ }
+ }
+ return nativeRole;
+}
+
++(id)getNativeSubroleFrom: (sal_Int16) nRole {
+ id nativeSubrole = nil;
+ switch( nRole ) {
+#define MAP(a,b) \
+ case a: nativeSubrole = b; break
+
+ MAP( AccessibleRole::UNKNOWN, NSAccessibilityUnknownSubrole );
+ MAP( AccessibleRole::ALERT, NSAccessibilitySystemDialogSubrole );
+ MAP( AccessibleRole::COLUMN_HEADER, @"" );
+ MAP( AccessibleRole::CANVAS, @"" );
+ MAP( AccessibleRole::CHECK_BOX, @"" );
+ MAP( AccessibleRole::CHECK_MENU_ITEM, @"" );
+ MAP( AccessibleRole::COLOR_CHOOSER, @"" );
+ MAP( AccessibleRole::COMBO_BOX, @"" );
+ MAP( AccessibleRole::DATE_EDITOR, @"" );
+ MAP( AccessibleRole::DESKTOP_ICON, @"" );
+ MAP( AccessibleRole::DESKTOP_PANE, @"" );
+ MAP( AccessibleRole::DIRECTORY_PANE, @"" );
+ MAP( AccessibleRole::DIALOG, NSAccessibilityDialogSubrole );
+ MAP( AccessibleRole::DOCUMENT, @"" );
+ MAP( AccessibleRole::EMBEDDED_OBJECT, @"" );
+ MAP( AccessibleRole::END_NOTE, @"" );
+ MAP( AccessibleRole::FILE_CHOOSER, @"" );
+ MAP( AccessibleRole::FILLER, @"" );
+ MAP( AccessibleRole::FONT_CHOOSER, @"" );
+ MAP( AccessibleRole::FOOTER, @"" );
+ MAP( AccessibleRole::FOOTNOTE, @"" );
+ MAP( AccessibleRole::FRAME, @"" );
+ MAP( AccessibleRole::GLASS_PANE, @"" );
+ MAP( AccessibleRole::GRAPHIC, @"" );
+ MAP( AccessibleRole::GROUP_BOX, @"" );
+ MAP( AccessibleRole::HEADER, @"" );
+ MAP( AccessibleRole::HEADING, @"" );
+ MAP( AccessibleRole::HYPER_LINK, NSAccessibilityTextLinkSubrole );
+ MAP( AccessibleRole::ICON, @"" );
+ MAP( AccessibleRole::INTERNAL_FRAME, @"" );
+ MAP( AccessibleRole::LABEL, @"" );
+ MAP( AccessibleRole::LAYERED_PANE, @"" );
+ MAP( AccessibleRole::LIST, @"" );
+ MAP( AccessibleRole::LIST_ITEM, NSAccessibilityOutlineRowSubrole );
+ MAP( AccessibleRole::MENU, @"" );
+ MAP( AccessibleRole::MENU_BAR, @"" );
+ MAP( AccessibleRole::MENU_ITEM, @"" );
+ MAP( AccessibleRole::OPTION_PANE, @"" );
+ MAP( AccessibleRole::PAGE_TAB, @"" );
+ MAP( AccessibleRole::PAGE_TAB_LIST, @"" );
+ MAP( AccessibleRole::PANEL, @"" );
+ MAP( AccessibleRole::PARAGRAPH, @"" );
+ MAP( AccessibleRole::PASSWORD_TEXT, NSAccessibilitySecureTextFieldSubrole );
+ MAP( AccessibleRole::POPUP_MENU, @"" );
+ MAP( AccessibleRole::PUSH_BUTTON, @"" );
+ MAP( AccessibleRole::PROGRESS_BAR, @"" );
+ MAP( AccessibleRole::RADIO_BUTTON, @"" );
+ MAP( AccessibleRole::RADIO_MENU_ITEM, @"" );
+ MAP( AccessibleRole::ROW_HEADER, @"" );
+ MAP( AccessibleRole::ROOT_PANE, @"" );
+ MAP( AccessibleRole::SCROLL_BAR, @"" );
+ MAP( AccessibleRole::SCROLL_PANE, @"" );
+ MAP( AccessibleRole::SHAPE, @"" );
+ MAP( AccessibleRole::SEPARATOR, @"" );
+ MAP( AccessibleRole::SLIDER, @"" );
+ MAP( AccessibleRole::SPIN_BOX, @"" );
+ MAP( AccessibleRole::SPLIT_PANE, @"" );
+ MAP( AccessibleRole::STATUS_BAR, @"" );
+ MAP( AccessibleRole::TABLE, @"" );
+ MAP( AccessibleRole::TABLE_CELL, @"" );
+ MAP( AccessibleRole::TEXT, @"" );
+ MAP( AccessibleRole::TEXT_FRAME, @"" );
+ MAP( AccessibleRole::TOGGLE_BUTTON, @"" );
+ MAP( AccessibleRole::TOOL_BAR, @"" );
+ MAP( AccessibleRole::TOOL_TIP, @"" );
+ MAP( AccessibleRole::TREE, @"" );
+ MAP( AccessibleRole::VIEW_PORT, @"" );
+ MAP( AccessibleRole::WINDOW, NSAccessibilityStandardWindowSubrole );
+
+ MAP( AccessibleRole::BUTTON_DROPDOWN, @"" );
+ MAP( AccessibleRole::BUTTON_MENU, @"" );
+ MAP( AccessibleRole::CAPTION, @"" );
+ MAP( AccessibleRole::CHART, @"" );
+ MAP( AccessibleRole::FORM, @"" );
+ MAP( AccessibleRole::IMAGE_MAP, @"" );
+ MAP( AccessibleRole::NOTE, @"" );
+ MAP( AccessibleRole::PAGE, @"" );
+ MAP( AccessibleRole::RULER, @"" );
+ MAP( AccessibleRole::SECTION, @"" );
+ MAP( AccessibleRole::TREE_ITEM, @"" );
+ MAP( AccessibleRole::TREE_TABLE, @"" );
+
+#undef MAP
+ default:
+ break;
+ }
+ return nativeSubrole;
+}
+
++(id)getRoleDescriptionFrom: (NSString *) role with: (NSString *) subRole {
+ id roleDescription;
+ if ( [ subRole length ] == 0 )
+ roleDescription = NSAccessibilityRoleDescription( role, nil );
+ else
+ roleDescription = NSAccessibilityRoleDescription( role, subRole );
+ return roleDescription;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yselectionwrapper.h b/vcl/aqua/source/a11y/aqua11yselectionwrapper.h
new file mode 100644
index 000000000000..a88e6c71c04b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yselectionwrapper.h
@@ -0,0 +1,43 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11SELECTIONWRAPPER_H
+#define _SV_AQUA11SELECTIONWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11ySelectionWrapper : NSObject
+{
+}
++(id)selectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setSelectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11SELECTIONWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yselectionwrapper.mm b/vcl/aqua/source/a11y/aqua11yselectionwrapper.mm
new file mode 100644
index 000000000000..53ab6dd36128
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yselectionwrapper.mm
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11yfactory.h"
+#include "aqua11yselectionwrapper.h"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+@implementation AquaA11ySelectionWrapper : NSObject
+
++(id)selectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper
+{
+ Reference< XAccessibleSelection > xAccessibleSelection = [ wrapper accessibleSelection ];
+ NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
+
+ try {
+ sal_Int32 n = xAccessibleSelection -> getSelectedAccessibleChildCount();
+ for ( sal_Int32 i=0 ; i < n ; ++i ) {
+ [ children addObject: [ AquaA11yFactory wrapperForAccessible: xAccessibleSelection -> getSelectedAccessibleChild( i ) ] ];
+ }
+
+ return children;
+
+ } catch ( Exception& e) {
+ return nil;
+ }
+
+}
+
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames
+{
+ [ attributeNames addObject: NSAccessibilitySelectedChildrenAttribute ];
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper
+{
+ if ( [ attribute isEqualToString: NSAccessibilitySelectedChildrenAttribute ] )
+ {
+ return YES;
+ }
+ else
+ {
+ return NO;
+ }
+}
+
++(void)setSelectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value
+{
+ Reference< XAccessibleSelection > xAccessibleSelection = [ wrapper accessibleSelection ];
+ try {
+ xAccessibleSelection -> clearAccessibleSelection();
+
+ unsigned c = [ value count ];
+ for ( unsigned i = 0 ; i < c ; ++i ) {
+ xAccessibleSelection -> selectAccessibleChild( [ [ value objectAtIndex: i ] accessibleContext ] -> getAccessibleIndexInParent() );
+ }
+ } catch ( Exception& e) {
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ytablewrapper.h b/vcl/aqua/source/a11y/aqua11ytablewrapper.h
new file mode 100644
index 000000000000..7bf3e44a2945
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytablewrapper.h
@@ -0,0 +1,44 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11TABLEWRAPPER_H
+#define _SV_AQUA11TABLEWRAPPER_H
+
+#include "aqua11ywrapper.h"
+
+#define MAXIMUM_ACCESSIBLE_TABLE_CELLS 1000
+
+@interface AquaA11yTableWrapper : AquaA11yWrapper
+{
+}
++(id)childrenAttributeForElement:(AquaA11yTableWrapper *)wrapper;
++(void)addAttributeNamesTo: (NSMutableArray *)attributeNames object: (AquaA11yWrapper*)pObject;
+
+-(id)rowsAttribute;
+-(id)columnsAttribute;
+@end
+#endif // _SV_AQUA11TABLEWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ytablewrapper.mm b/vcl/aqua/source/a11y/aqua11ytablewrapper.mm
new file mode 100644
index 000000000000..98454ab8d57b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytablewrapper.mm
@@ -0,0 +1,211 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua11ytablewrapper.h"
+#include "aqua11yfactory.h"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::uno;
+
+@implementation AquaA11yTableWrapper : AquaA11yWrapper
+
++(id)childrenAttributeForElement:(AquaA11yTableWrapper *)wrapper
+{
+ XAccessibleTable * accessibleTable = [ wrapper accessibleTable ];
+ NSArray* pResult = nil;
+ if( accessibleTable )
+ {
+ NSMutableArray * cells = [ [ NSMutableArray alloc ] init ];
+ try
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+
+ if( nRows * nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ // make all children visible to the hierarchy
+ for ( sal_Int32 rowCount = 0; rowCount < nRows; rowCount++ )
+ {
+ for ( sal_Int32 columnCount = 0; columnCount < nCols; columnCount++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( rowCount, columnCount );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ }
+ }
+ else
+ {
+ XAccessibleComponent * accessibleComponent = [ wrapper accessibleComponent ];
+ // find out which cells are actually visible by determining the top-left-cell and the bottom-right-cell
+ Size tableSize = accessibleComponent -> getSize();
+ Point point;
+ point.X = 0;
+ point.Y = 0;
+ Reference < XAccessible > rAccessibleTopLeft = accessibleComponent -> getAccessibleAtPoint ( point );
+ point.X = tableSize.Width - 1;
+ point.Y = tableSize.Height - 1;
+ Reference < XAccessible > rAccessibleBottomRight = accessibleComponent -> getAccessibleAtPoint ( point );
+ if ( rAccessibleTopLeft.is() && rAccessibleBottomRight.is() )
+ {
+ sal_Int32 idxTopLeft = rAccessibleTopLeft -> getAccessibleContext() -> getAccessibleIndexInParent();
+ sal_Int32 idxBottomRight = rAccessibleBottomRight -> getAccessibleContext() -> getAccessibleIndexInParent();
+ sal_Int32 rowTopLeft = accessibleTable -> getAccessibleRow ( idxTopLeft );
+ sal_Int32 columnTopLeft = accessibleTable -> getAccessibleColumn ( idxTopLeft );
+ sal_Int32 rowBottomRight = accessibleTable -> getAccessibleRow ( idxBottomRight );
+ sal_Int32 columnBottomRight = accessibleTable -> getAccessibleColumn ( idxBottomRight );
+ // create an array containing the visible cells
+ for ( sal_Int32 rowCount = rowTopLeft; rowCount <= rowBottomRight; rowCount++ )
+ {
+ for ( sal_Int32 columnCount = columnTopLeft; columnCount <= columnBottomRight; columnCount++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( rowCount, columnCount );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ }
+ }
+ }
+ pResult = NSAccessibilityUnignoredChildren( cells );
+ }
+ catch (const Exception &e)
+ {
+ }
+ [cells autorelease];
+ }
+
+ return pResult;
+}
+
++(void)addAttributeNamesTo: (NSMutableArray *)attributeNames object: (AquaA11yWrapper*)pObject
+{
+ XAccessibleTable * accessibleTable = [ pObject accessibleTable ];
+ if( accessibleTable )
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+
+
+ if( nRows*nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ [ attributeNames addObject: NSAccessibilityRowsAttribute ];
+ [ attributeNames addObject: NSAccessibilityColumnsAttribute ];
+ }
+ }
+}
+
+-(id)rowsAttribute
+{
+ NSArray* pResult = nil;
+
+ XAccessibleTable * accessibleTable = [ self accessibleTable ];
+ if( accessibleTable )
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+ if( nRows * nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ NSMutableArray * cells = [ [ NSMutableArray alloc ] init ];
+ try
+ {
+ // find out number of rows
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ for( sal_Int32 n = 0; n < nRows; n++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( n, 0 );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ pResult = NSAccessibilityUnignoredChildren( cells );
+ }
+ catch (const Exception &e)
+ {
+ pResult = nil;
+ }
+ [ cells autorelease ];
+ }
+ }
+
+ return pResult;
+}
+
+-(id)columnsAttribute
+{
+ NSArray* pResult = nil;
+
+ XAccessibleTable * accessibleTable = [ self accessibleTable ];
+
+ if( accessibleTable )
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+ if( nRows * nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ NSMutableArray * cells = [ [ NSMutableArray alloc ] init ];
+ try
+ {
+ // find out number of columns
+ for( sal_Int32 n = 0; n < nCols; n++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( 0, n );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ pResult = NSAccessibilityUnignoredChildren( cells );
+ }
+ catch (const Exception &e)
+ {
+ pResult = nil;
+ }
+ [ cells autorelease ];
+ }
+ }
+
+ return pResult;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h
new file mode 100644
index 000000000000..fcf185ca5478
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11TEXTATTRIBUTESWRAPPER_H
+#define _SV_AQUA11TEXTATTRIBUTESWRAPPER_H
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yTextAttributesWrapper : NSObject
+{
+}
++(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange;
+@end
+#endif // _SV_AQUA11TEXTATTRIBUTESWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm
new file mode 100644
index 000000000000..6577cebf295e
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm
@@ -0,0 +1,254 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua11ytextattributeswrapper.h"
+#include "salinst.h"
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::rtl;
+
+@implementation AquaA11yTextAttributesWrapper : NSObject
+
++(int)convertUnderlineStyle:(PropertyValue)property {
+ int underlineStyle = NSNoUnderlineStyle;
+ sal_Int16 value = 0;
+ property.Value >>= value;
+ if ( value != FontUnderline::NONE
+ && value != FontUnderline::DONTKNOW) {
+ underlineStyle = NSSingleUnderlineStyle;
+ }
+ return underlineStyle;
+}
+
++(int)convertBoldStyle:(PropertyValue)property {
+ int boldStyle = 0;
+ float value = 0;
+ property.Value >>= value;
+ if ( value == FontWeight::SEMIBOLD
+ || value == FontWeight::BOLD
+ || value == FontWeight::ULTRABOLD
+ || value == FontWeight::BLACK ) {
+ boldStyle = NSBoldFontMask;
+ }
+ return boldStyle;
+}
+
++(int)convertItalicStyle:(PropertyValue)property {
+ int italicStyle = 0;
+ sal_Int16 value = property.Value.get<FontSlant>();
+ if ( value == FontSlant_ITALIC ) {
+ italicStyle = NSItalicFontMask;
+ }
+ return italicStyle;
+}
+
++(MacOSBOOL)isStrikethrough:(PropertyValue)property {
+ MacOSBOOL strikethrough = NO;
+ sal_Int16 value = 0;
+ property.Value >>= value;
+ if ( value != FontStrikeout::NONE
+ && value != FontStrikeout::DONTKNOW ) {
+ strikethrough = YES;
+ }
+ return strikethrough;
+}
+
++(MacOSBOOL)convertBoolean:(PropertyValue)property {
+ MacOSBOOL myBoolean = NO;
+ bool value = sal_False;
+ property.Value >>= value;
+ if ( value ) {
+ myBoolean = YES;
+ }
+ return myBoolean;
+}
+
++(NSNumber *)convertShort:(PropertyValue)property {
+ sal_Int16 value = 0;
+ property.Value >>= value;
+ return [ NSNumber numberWithShort: value ];
+}
+
++(void)addColor:(sal_Int32)salColor forAttribute:(NSString *)attribute andRange:(NSRange)range toString:(NSMutableAttributedString *)string {
+ if ( salColor != -1 ) {
+ float elements[] = { salColor & 0x00ff0000, salColor & 0x0000ff00, salColor & 0x000000ff };
+ CGColorRef color = CGColorCreate ( CGColorSpaceCreateWithName ( kCGColorSpaceGenericRGB ), elements );
+ [ string addAttribute: attribute value: (id) color range: range ];
+ CGColorRelease ( color );
+ }
+}
+
++(void)addFont:(NSFont *)font toString:(NSMutableAttributedString *)string forRange:(NSRange)range {
+ if ( font != nil ) {
+ NSDictionary * fontDictionary = [ NSDictionary dictionaryWithObjectsAndKeys:
+ [ font fontName ], NSAccessibilityFontNameKey,
+ [ font familyName ], NSAccessibilityFontFamilyKey,
+ [ font displayName ], NSAccessibilityVisibleNameKey,
+ [ NSNumber numberWithFloat: [ font pointSize ] ], NSAccessibilityFontSizeKey,
+ nil
+ ];
+ [ string addAttribute: NSAccessibilityFontTextAttribute
+ value: fontDictionary
+ range: range
+ ];
+ }
+}
+
++(void)applyAttributesFrom:(Sequence < PropertyValue >)attributes toString:(NSMutableAttributedString *)string forRange:(NSRange)range storeDefaultsTo:(AquaA11yWrapper *)wrapperStore getDefaultsFrom:(AquaA11yWrapper *)wrapper {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ // constants
+ static const OUString attrUnderline = OUString::createFromAscii("CharUnderline");
+ static const OUString attrBold = OUString::createFromAscii("CharWeight");
+ static const OUString attrFontname = OUString::createFromAscii("CharFontName");
+ static const OUString attrItalic = OUString::createFromAscii("CharPosture");
+ static const OUString attrHeight = OUString::createFromAscii("CharHeight");
+ static const OUString attrStrikethrough = OUString::createFromAscii("CharStrikeout");
+ static const OUString attrShadow = OUString::createFromAscii("CharShadowed");
+ static const OUString attrUnderlineColor = OUString::createFromAscii("CharUnderlineColor");
+ static const OUString attrUnderlineHasColor = OUString::createFromAscii("CharUnderlineHasColor");
+ static const OUString attrForegroundColor = OUString::createFromAscii("CharColor");
+ static const OUString attrBackgroundColor = OUString::createFromAscii("CharBackColor");
+ static const OUString attrSuperscript = OUString::createFromAscii("CharEscapement");
+ // vars
+ OUString fontname;
+ int fonttraits = 0;
+ float fontsize = 0.0;
+ sal_Int32 underlineColor = 0;
+ MacOSBOOL underlineHasColor = NO;
+ // add attributes to string
+ for ( int attrIndex = 0; attrIndex < attributes.getLength(); attrIndex++ ) {
+ PropertyValue property = attributes [ attrIndex ];
+ // TODO: NSAccessibilityMisspelledTextAttribute, NSAccessibilityAttachmentTextAttribute, NSAccessibilityLinkTextAttribute
+ // NSAccessibilityStrikethroughColorTextAttribute is unsupported by UNP-API
+ if ( property.Value.hasValue() ) {
+ if ( property.Name.equals ( attrUnderline ) ) {
+ int style = [ AquaA11yTextAttributesWrapper convertUnderlineStyle: property ];
+ if ( style != NSNoUnderlineStyle ) {
+ [ string addAttribute: NSAccessibilityUnderlineTextAttribute value: [ NSNumber numberWithInt: style ] range: range ];
+ }
+ } else if ( property.Name.equals ( attrFontname ) ) {
+ property.Value >>= fontname;
+ } else if ( property.Name.equals ( attrBold ) ) {
+ fonttraits |= [ AquaA11yTextAttributesWrapper convertBoldStyle: property ];
+ } else if ( property.Name.equals ( attrItalic ) ) {
+ fonttraits |= [ AquaA11yTextAttributesWrapper convertItalicStyle: property ];
+ } else if ( property.Name.equals ( attrHeight ) ) {
+ property.Value >>= fontsize;
+ } else if ( property.Name.equals ( attrStrikethrough ) ) {
+ if ( [ AquaA11yTextAttributesWrapper isStrikethrough: property ] ) {
+ [ string addAttribute: NSAccessibilityStrikethroughTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
+ }
+ } else if ( property.Name.equals ( attrShadow ) ) {
+ if ( [ AquaA11yTextAttributesWrapper convertBoolean: property ] ) {
+ [ string addAttribute: NSAccessibilityShadowTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
+ }
+ } else if ( property.Name.equals ( attrUnderlineColor ) ) {
+ property.Value >>= underlineColor;
+ } else if ( property.Name.equals ( attrUnderlineHasColor ) ) {
+ underlineHasColor = [ AquaA11yTextAttributesWrapper convertBoolean: property ];
+ } else if ( property.Name.equals ( attrForegroundColor ) ) {
+ [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityForegroundColorTextAttribute andRange: range toString: string ];
+ } else if ( property.Name.equals ( attrBackgroundColor ) ) {
+ [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityBackgroundColorTextAttribute andRange: range toString: string ];
+ } else if ( property.Name.equals ( attrSuperscript ) ) {
+ // values < zero mean subscript
+ // values > zero mean superscript
+ // this is true for both NSAccessibility-API and UNO-API
+ NSNumber * number = [ AquaA11yTextAttributesWrapper convertShort: property ];
+ if ( [ number shortValue ] != 0 ) {
+ [ string addAttribute: NSAccessibilitySuperscriptTextAttribute value: number range: range ];
+ }
+ }
+ }
+ }
+ // add underline information
+ if ( underlineHasColor ) {
+ [ AquaA11yTextAttributesWrapper addColor: underlineColor forAttribute: NSAccessibilityUnderlineColorTextAttribute andRange: range toString: string ];
+ }
+ // add font information
+ if ( wrapperStore != nil ) { // default
+ [ wrapperStore setDefaultFontname: CreateNSString ( fontname ) ];
+ [ wrapperStore setDefaultFontsize: fontsize ];
+ NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: CreateNSString ( fontname ) traits: fonttraits weight: 0 size: fontsize ];
+ [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
+ } else if ( wrapper != nil && fonttraits != 0 ) { // attribute run and bold and/or italic was found
+ NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: [ wrapper defaultFontname ] traits: fonttraits weight: 0 size: [ wrapper defaultFontsize ] ];
+ [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
+ }
+ [ pool release ];
+}
+
++(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange {
+ static const Sequence < OUString > emptySequence;
+ // vars
+ NSMutableAttributedString * string = nil;
+ int loc = [ origRange rangeValue ].location;
+ int len = [ origRange rangeValue ].length;
+ int endIndex = loc + len;
+ int currentIndex = loc;
+ try {
+ NSString * myString = CreateNSString ( [ wrapper accessibleText ] -> getText() ); // TODO: dirty fix for i87817
+ string = [ [ NSMutableAttributedString alloc ] initWithString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
+ if ( [ wrapper accessibleTextAttributes ] != nil && [myString characterAtIndex:0] != 57361) { // TODO: dirty fix for i87817
+ [ string beginEditing ];
+ // add default attributes for whole string
+ Sequence < PropertyValue > defaultAttributes = [ wrapper accessibleTextAttributes ] -> getDefaultAttributes ( emptySequence );
+ [ AquaA11yTextAttributesWrapper applyAttributesFrom: defaultAttributes toString: string forRange: [ origRange rangeValue ] storeDefaultsTo: wrapper getDefaultsFrom: nil ];
+ // add attributes for attribute run(s)
+ while ( currentIndex < endIndex ) {
+ TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( currentIndex, AccessibleTextType::ATTRIBUTE_RUN );
+ int endOfRange = endIndex > textSegment.SegmentEnd ? textSegment.SegmentEnd : endIndex;
+ NSRange rangeForAttributeRun = NSMakeRange ( currentIndex, endOfRange - currentIndex );
+ // add run attributes
+ Sequence < PropertyValue > attributes = [ wrapper accessibleTextAttributes ] -> getRunAttributes ( currentIndex, emptySequence );
+ [ AquaA11yTextAttributesWrapper applyAttributesFrom: attributes toString: string forRange: rangeForAttributeRun storeDefaultsTo: nil getDefaultsFrom: wrapper ];
+ currentIndex = textSegment.SegmentEnd;
+ }
+ [ string endEditing ];
+ }
+ } catch ( IllegalArgumentException & e ) {
+ // empty
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ } catch ( RuntimeException& ) {
+ // at least don't crash
+ }
+ return string;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ytextwrapper.h b/vcl/aqua/source/a11y/aqua11ytextwrapper.h
new file mode 100644
index 000000000000..dfdab349bafe
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextwrapper.h
@@ -0,0 +1,64 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11TEXTWRAPPER_H
+#define _SV_AQUA11TEXTWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yTextWrapper : NSObject
+{
+}
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)numberOfCharactersAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)selectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)visibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)attributedStringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)rangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index;
++(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point;
++(id)boundsForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)styleRangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index;
++(id)rTFForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)lineForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index;
++(id)rangeForLineAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)line;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(void)addParameterizedAttributeNamesTo:(NSMutableArray *)attributeNames;
++(NSArray *)specialAttributeNames;
++(NSArray *)specialParameterizedAttributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setVisibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
++(void)setSelectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
++(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11TEXTWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ytextwrapper.mm b/vcl/aqua/source/a11y/aqua11ytextwrapper.mm
new file mode 100644
index 000000000000..2033135564d8
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextwrapper.mm
@@ -0,0 +1,289 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ytextwrapper.h"
+#include "aqua11ytextattributeswrapper.h"
+#include "aqua11yutil.h"
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::rtl;
+
+// Wrapper for XAccessibleText, XAccessibleEditableText and XAccessibleMultiLineText
+
+@implementation AquaA11yTextWrapper : NSObject
+
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return CreateNSString ( [ wrapper accessibleText ] -> getText() );
+}
+
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ // TODO
+}
+
++(id)numberOfCharactersAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return [ NSNumber numberWithLong: [ wrapper accessibleText ] -> getCharacterCount() ];
+}
+
++(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return CreateNSString ( [ wrapper accessibleText ] -> getSelectedText() );
+}
+
++(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ if ( [ wrapper accessibleEditableText ] != nil ) {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ OUString newText = GetOUString ( (NSString *) value );
+ NSRange selectedTextRange = [ [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: wrapper ] rangeValue ];
+ try {
+ [ wrapper accessibleEditableText ] -> replaceText ( selectedTextRange.location, selectedTextRange.location + selectedTextRange.length, newText );
+ } catch ( const Exception & e ) {
+ // empty
+ }
+ [ pool release ];
+ }
+}
+
++(id)selectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ sal_Int32 start = [ wrapper accessibleText ] -> getSelectionStart();
+ sal_Int32 end = [ wrapper accessibleText ] -> getSelectionEnd();
+ if ( start != end ) {
+ return [ NSValue valueWithRange: NSMakeRange ( start, end - start ) ]; // true selection
+ } else {
+ long caretPos = [ wrapper accessibleText ] -> getCaretPosition();
+ if ( caretPos < 0 || caretPos > [ wrapper accessibleText ] -> getCharacterCount() ) {
+ return nil;
+ }
+ return [ NSValue valueWithRange: NSMakeRange ( caretPos, 0 ) ]; // insertion point
+ }
+}
+
++(void)setSelectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ NSRange range = [ value rangeValue ];
+ try {
+ [ wrapper accessibleText ] -> setSelection ( range.location, range.location + range.length );
+ } catch ( const Exception & e ) {
+ // empty
+ }
+}
+
++(id)visibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // the OOo a11y API returns only the visible portion...
+ return [ NSValue valueWithRange: NSMakeRange ( 0, [ wrapper accessibleText ] -> getCharacterCount() ) ];
+}
+
++(void)setVisibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ // do nothing
+}
+
++(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return [ [ NSArray alloc ] init ]; // unsupported
+}
+
++(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ]; // unsupported
+}
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
+ [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+}
+
++(NSArray *)specialAttributeNames {
+ return [ NSArray arrayWithObjects:
+ NSAccessibilityValueAttribute,
+ NSAccessibilityNumberOfCharactersAttribute,
+ NSAccessibilitySelectedTextAttribute,
+ NSAccessibilitySelectedTextRangeAttribute,
+ NSAccessibilityVisibleCharacterRangeAttribute,
+ NSAccessibilitySharedTextUIElementsAttribute,
+ NSAccessibilitySharedCharacterRangeAttribute,
+ nil ];
+}
+
++(void)addParameterizedAttributeNamesTo:(NSMutableArray *)attributeNames {
+ [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialParameterizedAttributeNames ] ];
+}
+
++(NSArray *)specialParameterizedAttributeNames {
+ return [ NSArray arrayWithObjects:
+ NSAccessibilityStringForRangeParameterizedAttribute,
+ NSAccessibilityAttributedStringForRangeParameterizedAttribute,
+ NSAccessibilityRangeForIndexParameterizedAttribute,
+ NSAccessibilityRangeForPositionParameterizedAttribute,
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+ NSAccessibilityStyleRangeForIndexParameterizedAttribute,
+ NSAccessibilityRTFForRangeParameterizedAttribute,
+ NSAccessibilityLineForIndexParameterizedAttribute,
+ NSAccessibilityRangeForLineParameterizedAttribute,
+ nil ];
+}
+
++(id)lineForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
+ NSNumber * lineNumber = nil;
+ try {
+ sal_Int32 line = [ wrapper accessibleMultiLineText ] -> getLineNumberAtIndex ( (sal_Int32) [ index intValue ] );
+ lineNumber = [ NSNumber numberWithInt: line ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return lineNumber;
+}
+
++(id)rangeForLineAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)line {
+ NSValue * range = nil;
+ try {
+ TextSegment textSegment = [ wrapper accessibleMultiLineText ] -> getTextAtLineNumber ( [ line intValue ] );
+ range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return range;
+}
+
++(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ int loc = [ range rangeValue ].location;
+ int len = [ range rangeValue ].length;
+ NSMutableString * textRange = [ [ NSMutableString alloc ] init ];
+ try {
+ [ textRange appendString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return textRange;
+}
+
++(id)attributedStringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ return [ AquaA11yTextAttributesWrapper createAttributedStringForElement: wrapper inOrigRange: range ];
+}
+
++(id)rangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
+ NSValue * range = nil;
+ try {
+ TextSegment textSegment = [ wrapper accessibleText ] -> getTextBeforeIndex ( [ index intValue ], AccessibleTextType::GLYPH );
+ range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ } catch ( IllegalArgumentException & e ) {
+ // empty
+ }
+ return range;
+}
+
++(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point {
+ NSValue * value = nil;
+ sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint ( [ AquaA11yUtil nsPointToVclPoint: point ] );
+ if ( index > -1 ) {
+ value = [ AquaA11yTextWrapper rangeForIndexAttributeForElement: wrapper forParameter: [ NSNumber numberWithLong: index ] ];
+ }
+ return value;
+}
+
++(id)boundsForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ NSValue * rect = nil;
+ try {
+ // TODO: this is ugly!!!
+ // the UNP-API can only return the bounds for a single character, not for a range
+ int loc = [ range rangeValue ].location;
+ int len = [ range rangeValue ].length;
+ int minx = 0x7fffffff, miny = 0x7fffffff, maxx = 0, maxy = 0;
+ for ( int i = 0; i < len; i++ ) {
+ Rectangle vclRect = [ wrapper accessibleText ] -> getCharacterBounds ( loc + i );
+ if ( vclRect.X < minx ) {
+ minx = vclRect.X;
+ }
+ if ( vclRect.Y < miny ) {
+ miny = vclRect.Y;
+ }
+ if ( vclRect.Width + vclRect.X > maxx ) {
+ maxx = vclRect.Width + vclRect.X;
+ }
+ if ( vclRect.Height + vclRect.Y > maxy ) {
+ maxy = vclRect.Height + vclRect.Y;
+ }
+ }
+ if ( [ wrapper accessibleComponent ] != nil ) {
+ // get location on screen (must be added since get CharacterBounds returns values relative to parent)
+ Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen();
+ Point pos ( minx + screenPos.X, miny + screenPos.Y );
+ Point size ( maxx - minx, maxy - miny );
+ NSValue * nsPos = [ AquaA11yUtil vclPointToNSPoint: pos ];
+ rect = [ NSValue valueWithRect: NSMakeRect ( [ nsPos pointValue ].x, [ nsPos pointValue ].y - size.Y, size.X, size.Y ) ];
+ //printf("Range: %s --- Rect: %s\n", [ NSStringFromRange ( [ range rangeValue ] ) UTF8String ], [ NSStringFromRect ( [ rect rectValue ] ) UTF8String ]);
+ }
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return rect;
+}
+
++(id)styleRangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
+ NSValue * range = nil;
+ try {
+ TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( [ index intValue ], AccessibleTextType::ATTRIBUTE_RUN );
+ range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ } catch ( IllegalArgumentException & e ) {
+ // empty
+ }
+ return range;
+}
+
++(id)rTFForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ NSData * rtfData = nil;
+ NSAttributedString * attrString = (NSAttributedString *) [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: wrapper forParameter: range ];
+ if ( attrString != nil ) {
+ @try {
+ rtfData = [ attrString RTFFromRange: [ range rangeValue ] documentAttributes: nil ];
+ } @catch ( NSException * e) {
+ // emtpy
+ }
+ }
+ return rtfData;
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
+ MacOSBOOL isSettable = NO;
+ if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
+ || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) {
+ if ( ! [ [ wrapper accessibilityAttributeValue: NSAccessibilityRoleAttribute ] isEqualToString: NSAccessibilityStaticTextRole ] ) {
+ isSettable = YES;
+ }
+ }
+ return isSettable;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yutil.h b/vcl/aqua/source/a11y/aqua11yutil.h
new file mode 100644
index 000000000000..adf565f4d9bb
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yutil.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11YUTIL_H
+#define _SV_AQUA11YUTIL_H
+
+#include <com/sun/star/awt/Point.hpp>
+
+@interface AquaA11yUtil : NSObject {
+}
++(NSValue *)vclPointToNSPoint:(::com::sun::star::awt::Point)vclPoint;
++(::com::sun::star::awt::Point)nsPointToVclPoint:(NSValue *)nsPoint;
+@end
+
+#endif // _SV_AQUA11YUTIL_H \ No newline at end of file
diff --git a/vcl/aqua/source/a11y/aqua11yutil.mm b/vcl/aqua/source/a11y/aqua11yutil.mm
new file mode 100644
index 000000000000..4749a3b40822
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yutil.mm
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aquavcltypes.h"
+#include "aqua11yutil.h"
+
+using namespace ::com::sun::star::awt;
+
+@implementation AquaA11yUtil : NSObject
+
+// TODO: should be merged with AquaSalFrame::VCLToCocoa... to a general helper method
++(NSValue *)vclPointToNSPoint:(Point)vclPoint {
+ // VCL coordinates are in upper-left-notation, Cocoa likes it the Cartesian way (lower-left)
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ NSPoint nsPoint = NSMakePoint ( (float) vclPoint.X, (float) ( screenRect.size.height - vclPoint.Y ) );
+ return [ NSValue valueWithPoint: nsPoint ];
+}
+
+// TODO: should be merged with AquaSalFrame::VCLToCocoa... to a general helper method
++(Point)nsPointToVclPoint:(NSValue *)nsPoint {
+ // VCL coordinates are in upper-left-notation, Cocoa likes it the Cartesian way (lower-left)
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ return Point ( static_cast<long>([ nsPoint pointValue ].x), static_cast<long>(screenRect.size.height - [ nsPoint pointValue ].y) );
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yvaluewrapper.h b/vcl/aqua/source/a11y/aqua11yvaluewrapper.h
new file mode 100644
index 000000000000..d3afebf7f828
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yvaluewrapper.h
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11VALUEWRAPPER_H
+#define _SV_AQUA11VALUEWRAPPER_H
+
+#include "salinst.h"
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yValueWrapper : NSObject
+{
+}
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)minValueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)maxValueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11VALUEWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yvaluewrapper.mm b/vcl/aqua/source/a11y/aqua11yvaluewrapper.mm
new file mode 100644
index 000000000000..85ef0041da95
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yvaluewrapper.mm
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua11yvaluewrapper.h"
+#include "aqua11ywrapperstatictext.h"
+
+using namespace ::com::sun::star::uno;
+
+// Wrapper for XAccessibleValue
+// Remember: A UNO-Value is a single numeric value. Regarding the Mac A11y-API, a value can be anything!
+
+@implementation AquaA11yValueWrapper : NSObject
+
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // TODO: Detect Type from Any
+ if ( [ wrapper accessibleValue ] != nil ) {
+ long value = 0;
+ [ wrapper accessibleValue ] -> getCurrentValue() >>= value;
+ return [ NSNumber numberWithLong: value ];
+ }
+ return [ NSNumber numberWithLong: 0 ];
+}
+
++(id)minValueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // TODO: Detect Type from Any
+ if ( [ wrapper accessibleValue ] != nil ) {
+ long value = 0;
+ [ wrapper accessibleValue ] -> getMinimumValue() >>= value;
+ return [ NSNumber numberWithLong: value ];
+ }
+ return [ NSNumber numberWithLong: 0 ];
+}
+
++(id)maxValueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // TODO: Detect Type from Any
+ if ( [ wrapper accessibleValue ] != nil ) {
+ long value = 0;
+ [ wrapper accessibleValue ] -> getMaximumValue() >>= value;
+ return [ NSNumber numberWithLong: value ];
+ }
+ return [ NSNumber numberWithLong: 0 ];
+}
+
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ // TODO: Detect Type from NSNumber
+ if ( [ value isKindOfClass: [ NSNumber class ] ]
+ && [ wrapper accessibleValue ] != nil ) {
+ NSNumber * number = (NSNumber *) value;
+ Any numberAny ( [ number longValue ] );
+ [ wrapper accessibleValue ] -> setCurrentValue ( numberAny );
+ }
+}
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
+ [ attributeNames addObject: NSAccessibilityValueAttribute ];
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
+ MacOSBOOL isSettable = NO;
+ if ( [ wrapper accessibleValue ] != nil
+ && [ attribute isEqualToString: NSAccessibilityValueAttribute ]
+ && ! [ wrapper isKindOfClass: [ AquaA11yWrapperStaticText class ] ] ) {
+ isSettable = YES;
+ }
+ return isSettable;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapper.mm b/vcl/aqua/source/a11y/aqua11ywrapper.mm
new file mode 100644
index 000000000000..e86676e725f2
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapper.mm
@@ -0,0 +1,1142 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "saldata.hxx"
+
+#include "aqua11ywrapper.h"
+#include "aqua11yactionwrapper.h"
+#include "aqua11ycomponentwrapper.h"
+#include "aqua11ylistener.hxx"
+#include "aqua11yselectionwrapper.h"
+#include "aqua11ytablewrapper.h"
+#include "aqua11ytextwrapper.h"
+#include "aqua11yvaluewrapper.h"
+#include "aqua11yfactory.h"
+#include "aqua11yfocuslistener.hxx"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11yrolehelper.h"
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+@interface SalFrameWindow : NSWindow
+{
+}
+-(Reference<XAccessibleContext>)accessibleContext;
+@end
+
+static MacOSBOOL isPopupMenuOpen = NO;
+
+@implementation AquaA11yWrapper : NSView
+
+#pragma mark -
+#pragma mark Init and dealloc
+
+-(id)initWithAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ self = [ super init ];
+ if ( self != nil ) {
+ [ self setDefaults: rxAccessibleContext ];
+ }
+ return self;
+}
+
+-(void) setDefaults: (Reference < XAccessibleContext >) rxAccessibleContext {
+ mDefaultFontsize = 0.0;
+ mpDefaultFontname = nil;
+ mpReferenceWrapper = new ReferenceWrapper;
+ mActsAsRadioGroup = NO;
+ mpReferenceWrapper -> rAccessibleContext = rxAccessibleContext;
+ mIsTableCell = NO;
+ // Querying all supported interfaces
+ try {
+ // XAccessibleComponent
+ mpReferenceWrapper -> rAccessibleComponent = Reference < XAccessibleComponent > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleExtendedComponent
+ mpReferenceWrapper -> rAccessibleExtendedComponent = Reference < XAccessibleExtendedComponent > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleSelection
+ mpReferenceWrapper -> rAccessibleSelection = Reference< XAccessibleSelection > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleTable
+ mpReferenceWrapper -> rAccessibleTable = Reference < XAccessibleTable > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleText
+ mpReferenceWrapper -> rAccessibleText = Reference < XAccessibleText > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleEditableText
+ mpReferenceWrapper -> rAccessibleEditableText = Reference < XAccessibleEditableText > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleValue
+ mpReferenceWrapper -> rAccessibleValue = Reference < XAccessibleValue > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleAction
+ mpReferenceWrapper -> rAccessibleAction = Reference < XAccessibleAction > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleTextAttributes
+ mpReferenceWrapper -> rAccessibleTextAttributes = Reference < XAccessibleTextAttributes > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleMultiLineText
+ mpReferenceWrapper -> rAccessibleMultiLineText = Reference < XAccessibleMultiLineText > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleEventBroadcaster
+ #if 0
+ /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children.
+ That means we need to cache this, else e.g. tree list boxes are not accessible (moreover
+ it crashes by notifying dead objects - which would seemt o be another bug)
+
+ FIXME:
+ Unfortunately this can increase memory consumption drastically until the non transient parent
+ is destroyed an finally all the transients are released.
+ */
+ if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) )
+ #endif
+ {
+ Reference< XAccessibleEventBroadcaster > xBroadcaster(rxAccessibleContext, UNO_QUERY);
+ if( xBroadcaster.is() ) {
+ /*
+ * We intentionally do not hold a reference to the event listener in the wrapper object,
+ * but let the listener control the life cycle of the wrapper instead ..
+ */
+ xBroadcaster->addEventListener( new AquaA11yEventListener( self, rxAccessibleContext -> getAccessibleRole() ) );
+ }
+ }
+ // TABLE_CELL
+ if ( rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TABLE_CELL ) {
+ mIsTableCell = YES;
+ }
+ } catch ( const Exception ) {
+ }
+}
+
+-(void)dealloc {
+ if ( mpReferenceWrapper != nil ) {
+ delete mpReferenceWrapper;
+ }
+ if ( mpDefaultFontname != nil ) {
+ [ mpDefaultFontname release ];
+ }
+ [ super dealloc ];
+}
+
+#pragma mark -
+#pragma mark Utility Section
+
+// generates selectors for attribute name AXAttributeNameHere
+// (getter without parameter) attributeNameHereAttribute
+// (getter with parameter) attributeNameHereAttributeForParameter:
+// (setter) setAttributeNameHereAttributeForElement:to:
+-(SEL)selectorForAttribute:(NSString *)attribute asGetter:(MacOSBOOL)asGetter withGetterParameter:(MacOSBOOL)withGetterParameter {
+ SEL selector = nil;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ @try {
+ // step 1: create method name from attribute name
+ NSMutableString * methodName = [ NSMutableString string ];
+ if ( ! asGetter ) {
+ [ methodName appendString: @"set" ];
+ }
+ NSString * firstChar = [ attribute substringWithRange: NSMakeRange ( 2, 1 ) ]; // drop leading "AX" and get first char
+ if ( asGetter ) {
+ [ methodName appendString: [ firstChar lowercaseString ] ];
+ } else {
+ [ methodName appendString: firstChar ];
+ }
+ [ methodName appendString: [ attribute substringFromIndex: 3 ] ]; // append rest of attribute name
+ // append rest of method name
+ [ methodName appendString: @"Attribute" ];
+ if ( ! asGetter ) {
+ [ methodName appendString: @"ForElement:to:" ];
+ } else if ( asGetter && withGetterParameter ) {
+ [ methodName appendString: @"ForParameter:" ];
+ }
+ // step 2: create selector
+ selector = NSSelectorFromString ( methodName );
+ } @catch ( id exception ) {
+ selector = nil;
+ }
+ [ pool release ];
+ return selector;
+}
+
+-(Reference < XAccessible >)getFirstRadioButtonInGroup {
+ Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
+ if( rxAccessibleRelationSet.is() )
+ {
+ AccessibleRelation relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
+ if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() )
+ return Reference < XAccessible > ( relationMemberOf.TargetSet[0], UNO_QUERY );
+ }
+ return Reference < XAccessible > ();
+}
+
+-(MacOSBOOL)isFirstRadioButtonInGroup {
+ Reference < XAccessible > rFirstMateAccessible = [ self getFirstRadioButtonInGroup ];
+ if ( rFirstMateAccessible.is() && rFirstMateAccessible -> getAccessibleContext().get() == [ self accessibleContext ] ) {
+ return YES;
+ }
+ return NO;
+}
+
+#pragma mark -
+#pragma mark Attribute Value Getters
+// ( called via Reflection by accessibilityAttributeValue )
+
+/*
+ Radiobutton grouping is done differently in NSAccessibility and the UNO-API. In UNO related radio buttons share an entry in their
+ RelationSet. In NSAccessibility the relationship is axpressed through the hierarchy. A AXRadioGroup contains two or more AXRadioButton
+ objects. Since this group is not available in the UNO hierarchy, an extra wrapper is used for it. This wrapper shares almost all
+ attributes with the first radio button of the group, except for the role, subrole, role description, parent and children attributes.
+ So in this five methods there is a special treatment for radio buttons and groups.
+*/
+
+-(id)roleAttribute {
+ if ( mActsAsRadioGroup ) {
+ return NSAccessibilityRadioGroupRole;
+ }
+ else {
+ return [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ];
+ }
+}
+
+-(id)subroleAttribute {
+ if ( mActsAsRadioGroup ) {
+ return @"";
+ } else {
+ NSString * subRole = [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ];
+ if ( ! [ subRole isEqualToString: @"" ] ) {
+ return subRole;
+ } else {
+ [ subRole release ];
+ return [ super accessibilityAttributeValue: NSAccessibilitySubroleAttribute ];
+ }
+ }
+}
+
+-(id)titleAttribute {
+ return CreateNSString ( [ self accessibleContext ] -> getAccessibleName() );
+}
+
+-(id)descriptionAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ return [ self titleAttribute ];
+ } else if ( [ self accessibleExtendedComponent ] != nil ) {
+ return [ AquaA11yComponentWrapper descriptionAttributeForElement: self ];
+ } else {
+ return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
+ }
+}
+
+-(id)enabledAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::ENABLED ) ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)focusedAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ id isFocused = nil;
+ Reference < XAccessible > rxParent = [ self accessibleContext ] -> getAccessibleParent();
+ if ( rxParent.is() ) {
+ Reference < XAccessibleContext > rxContext = rxParent -> getAccessibleContext();
+ if ( rxContext.is() && rxContext -> getAccessibleStateSet().is() ) {
+ isFocused = [ NSNumber numberWithBool: rxContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
+ }
+ }
+ return isFocused;
+ } else if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)parentAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON && ! mActsAsRadioGroup ) {
+ Reference < XAccessible > rxAccessible = [ self getFirstRadioButtonInGroup ];
+ if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
+ Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
+ id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: YES asRadioGroup: YES ];
+ [ parent_wrapper autorelease ];
+ return NSAccessibilityUnignoredAncestor( parent_wrapper );
+ }
+ return nil;
+ }
+ try {
+ Reference< XAccessible > xParent( [ self accessibleContext ] -> getAccessibleParent() );
+ if ( xParent.is() ) {
+ Reference< XAccessibleContext > xContext( xParent -> getAccessibleContext() );
+ if ( xContext.is() ) {
+ id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
+ [ parent_wrapper autorelease ];
+ return NSAccessibilityUnignoredAncestor( parent_wrapper );
+ }
+ }
+ } catch (const Exception&) {
+ }
+
+ OSL_ASSERT( 0 );
+ return nil;
+}
+
+-(id)childrenAttribute {
+ if ( mActsAsRadioGroup ) {
+ NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
+ Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
+ AccessibleRelation relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
+ if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() ) {
+ for ( int index = 0; index < relationMemberOf.TargetSet.getLength(); index++ ) {
+ Reference < XAccessible > rMateAccessible = Reference < XAccessible > ( relationMemberOf.TargetSet[index], UNO_QUERY );
+ if ( rMateAccessible.is() ) {
+ Reference< XAccessibleContext > rMateAccessibleContext( rMateAccessible -> getAccessibleContext() );
+ if ( rMateAccessibleContext.is() ) {
+ id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rMateAccessibleContext ];
+ [ children addObject: wrapper ];
+ [ wrapper release ];
+ }
+ }
+ }
+ }
+ return children;
+ } else if ( [ self accessibleTable ] != nil )
+ {
+ AquaA11yTableWrapper* pTable = [self isKindOfClass: [AquaA11yTableWrapper class]] ? (AquaA11yTableWrapper*)self : nil;
+ return [ AquaA11yTableWrapper childrenAttributeForElement: pTable ];
+ } else {
+ try {
+ NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
+ Reference< XAccessibleContext > xContext( [ self accessibleContext ] );
+
+ sal_Int32 cnt = xContext -> getAccessibleChildCount();
+ for ( sal_Int32 i = 0; i < cnt; i++ ) {
+ Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
+ if( xChild.is() ) {
+ Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
+ // the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
+ if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
+ id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
+ [ children addObject: wrapper ];
+ [ wrapper release ];
+ }
+ }
+ }
+
+ // if not already acting as RadioGroup now is the time to replace RadioButtons with RadioGroups and remove RadioButtons
+ if ( ! mActsAsRadioGroup ) {
+ NSEnumerator * enumerator = [ children objectEnumerator ];
+ AquaA11yWrapper * element;
+ while ( ( element = ( (AquaA11yWrapper *) [ enumerator nextObject ] ) ) ) {
+ if ( [ element accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
+ if ( [ element isFirstRadioButtonInGroup ] ) {
+ id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ element accessibleContext ] createIfNotExists: YES asRadioGroup: YES ];
+ [ children replaceObjectAtIndex: [ children indexOfObjectIdenticalTo: element ] withObject: wrapper ];
+ }
+ [ children removeObject: element ];
+ }
+ }
+ }
+
+ [ children autorelease ];
+ return NSAccessibilityUnignoredChildren( children );
+ } catch (const Exception &e) {
+ // TODO: Log
+ return nil;
+ }
+ }
+}
+
+-(id)windowAttribute {
+ // go upstairs until reaching the broken connection
+ AquaA11yWrapper * aWrapper = self;
+ while ( [ aWrapper accessibleContext ] -> getAccessibleParent().is() ) {
+ aWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ aWrapper accessibleContext ] -> getAccessibleParent() -> getAccessibleContext() ];
+ [ aWrapper autorelease ];
+ }
+ // get associated NSWindow
+ NSView * theView = [ aWrapper viewElementForParent ];
+ return theView;
+}
+
+-(id)topLevelUIElementAttribute {
+ return [ self windowAttribute ];
+}
+
+-(id)sizeAttribute {
+ if ( [ self accessibleComponent ] != nil ) {
+ return [ AquaA11yComponentWrapper sizeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)positionAttribute {
+ if ( [ self accessibleComponent ] != nil ) {
+ return [ AquaA11yComponentWrapper positionAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)helpAttribute {
+ return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
+}
+
+-(id)roleDescriptionAttribute {
+ if ( mActsAsRadioGroup ) {
+ return [ AquaA11yRoleHelper getRoleDescriptionFrom: NSAccessibilityRadioGroupRole with: @"" ];
+ } else if( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
+ // FIXME: VO should read this because of hierarchy, this is just a workaround
+ // get parent and its children
+ AquaA11yWrapper * parent = [ self parentAttribute ];
+ NSArray * children = [ parent childrenAttribute ];
+ // find index of self
+ int index = 1;
+ NSEnumerator * enumerator = [ children objectEnumerator ];
+ AquaA11yWrapper * child = nil;
+ while ( ( child = [ enumerator nextObject ] ) ) {
+ if ( self == child ) {
+ break;
+ }
+ index++;
+ }
+ // build string
+ NSNumber * nIndex = [ NSNumber numberWithInt: index ];
+ NSNumber * nGroupsize = [ NSNumber numberWithInt: [ children count ] ];
+ NSMutableString * value = [ [ NSMutableString alloc ] init ];
+ [ value appendString: @"radio button " ];
+ [ value appendString: [ nIndex stringValue ] ];
+ [ value appendString: @" of " ];
+ [ value appendString: [ nGroupsize stringValue ] ];
+ // clean up and return string
+ [ nIndex release ];
+ [ nGroupsize release ];
+ [ children release ];
+ return value;
+ } else {
+ return [ AquaA11yRoleHelper getRoleDescriptionFrom:
+ [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ]
+ with: [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ] ];
+ }
+}
+
+-(id)valueAttribute {
+ if ( [ [ self roleAttribute ] isEqualToString: NSAccessibilityMenuItemRole ] ) {
+ return nil;
+ } else if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper valueAttributeForElement: self ];
+ } else if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper valueAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)minValueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper minValueAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)maxValueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper maxValueAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)contentsAttribute {
+ return [ self childrenAttribute ];
+}
+
+-(id)selectedChildrenAttribute {
+ return [ AquaA11ySelectionWrapper selectedChildrenAttributeForElement: self ];
+}
+
+-(id)numberOfCharactersAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper numberOfCharactersAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)selectedTextAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper selectedTextAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)selectedTextRangeAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)visibleCharacterRangeAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper visibleCharacterRangeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)tabsAttribute {
+ return self; // TODO ???
+}
+
+-(id)sharedTextUIElementsAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper sharedTextUIElementsAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)sharedCharacterRangeAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper sharedCharacterRangeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)expandedAttribute {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::EXPANDED ) ];
+}
+
+-(id)selectedAttribute {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::SELECTED ) ];
+}
+
+-(id)stringForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper stringForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)attributedStringForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rangeForIndexAttributeForParameter:(id)index {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper rangeForIndexAttributeForElement: self forParameter: index ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rangeForPositionAttributeForParameter:(id)point {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper rangeForPositionAttributeForElement: self forParameter: point ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)boundsForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper boundsForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)styleRangeForIndexAttributeForParameter:(id)index {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper styleRangeForIndexAttributeForElement: self forParameter: index ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rTFForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper rTFForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)orientationAttribute {
+ NSString * orientation = nil;
+ Reference < XAccessibleStateSet > stateSet = [ self accessibleContext ] -> getAccessibleStateSet();
+ if ( stateSet -> contains ( AccessibleStateType::HORIZONTAL ) ) {
+ orientation = NSAccessibilityHorizontalOrientationValue;
+ } else if ( stateSet -> contains ( AccessibleStateType::VERTICAL ) ) {
+ orientation = NSAccessibilityVerticalOrientationValue;
+ }
+ return orientation;
+}
+
+-(id)titleUIElementAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
+ NSString * title = [ self titleAttribute ];
+ id titleElement = nil;
+ if ( [ title length ] == 0 ) {
+ AccessibleRelation relationLabeledBy = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABELED_BY );
+ if ( relationLabeledBy.RelationType == AccessibleRelationType::LABELED_BY && relationLabeledBy.TargetSet.hasElements() ) {
+ Reference < XAccessible > rxAccessible ( relationLabeledBy.TargetSet[0], UNO_QUERY );
+ titleElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
+ }
+ }
+ if ( title != nil ) {
+ [ title release ];
+ }
+ return titleElement;
+ } else {
+ return nil;
+ }
+}
+
+-(id)servesAsTitleForUIElementsAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
+ id titleForElement = nil;
+ AccessibleRelation relationLabelFor = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABEL_FOR );
+ if ( relationLabelFor.RelationType == AccessibleRelationType::LABEL_FOR && relationLabelFor.TargetSet.hasElements() ) {
+ Reference < XAccessible > rxAccessible ( relationLabelFor.TargetSet[0], UNO_QUERY );
+ titleForElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
+ }
+ return titleForElement;
+ } else {
+ return nil;
+ }
+}
+
+-(id)lineForIndexAttributeForParameter:(id)index {
+ if ( [ self accessibleMultiLineText ] != nil ) {
+ return [ AquaA11yTextWrapper lineForIndexAttributeForElement: self forParameter: index ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rangeForLineAttributeForParameter:(id)line {
+ if ( [ self accessibleMultiLineText ] != nil ) {
+ return [ AquaA11yTextWrapper rangeForLineAttributeForElement: self forParameter: line ];
+ } else {
+ return nil;
+ }
+}
+
+#pragma mark -
+#pragma mark Accessibility Protocol
+
+-(id)accessibilityAttributeValue:(NSString *)attribute {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+
+ id value = nil;
+ // if we are no longer in the wrapper repository, we have been disposed
+ AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ self accessibleContext ] createIfNotExists: NO ];
+ if ( theWrapper != nil || mIsTableCell ) {
+ try {
+ SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: NO ];
+ if ( [ self respondsToSelector: methodSelector ] ) {
+ value = [ self performSelector: methodSelector ];
+ }
+ } catch ( const DisposedException & e ) {
+ mIsTableCell = NO; // just to be sure
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
+ return nil;
+ } catch ( const Exception & e ) {
+ // empty
+ }
+ }
+ if ( theWrapper != nil ) {
+ [ theWrapper release ]; // the above called method calls retain on the returned Wrapper
+ }
+ return value;
+}
+
+-(MacOSBOOL)accessibilityIsIgnored {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+ MacOSBOOL ignored = NO;
+ sal_Int16 nRole = [ self accessibleContext ] -> getAccessibleRole();
+ switch ( nRole ) {
+ case AccessibleRole::PANEL:
+ case AccessibleRole::FRAME:
+ case AccessibleRole::ROOT_PANE:
+ case AccessibleRole::SEPARATOR:
+ case AccessibleRole::FILLER:
+ case AccessibleRole::DIALOG:
+ ignored = YES;
+ break;
+ default:
+ ignored = ! ( [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::VISIBLE ) );
+ break;
+ }
+ return ignored; // TODO: to be completed
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+ NSString * nativeSubrole = nil;
+ NSString * title = nil;
+ NSMutableArray * attributeNames = nil;
+ sal_Int32 nAccessibleChildren = 0;
+ try {
+ // Default Attributes
+ attributeNames = [ NSMutableArray arrayWithObjects:
+ NSAccessibilityRoleAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityWindowAttribute,
+ NSAccessibilityHelpAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ nil ];
+ nativeSubrole = (NSString *) [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ];
+ title = (NSString *) [ self titleAttribute ];
+ Reference < XAccessibleRelationSet > rxRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
+ // Special Attributes depending on attribute values
+ if ( nativeSubrole != nil && ! [ nativeSubrole isEqualToString: @"" ] ) {
+ [ attributeNames addObject: NSAccessibilitySubroleAttribute ];
+ }
+ try
+ {
+ nAccessibleChildren = [ self accessibleContext ] -> getAccessibleChildCount();
+ if ( nAccessibleChildren > 0 ) {
+ [ attributeNames addObject: NSAccessibilityChildrenAttribute ];
+ }
+ }
+ catch( DisposedException& ) {}
+ catch( RuntimeException& ) {}
+
+ if ( title != nil && ! [ title isEqualToString: @"" ] ) {
+ [ attributeNames addObject: NSAccessibilityTitleAttribute ];
+ }
+ if ( [ title length ] == 0 && rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABELED_BY ) ) {
+ [ attributeNames addObject: NSAccessibilityTitleUIElementAttribute ];
+ }
+ if ( rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABEL_FOR ) ) {
+ [ attributeNames addObject: NSAccessibilityServesAsTitleForUIElementsAttribute ];
+ }
+ // Special Attributes depending on interface
+ if( [self accessibleContext ] -> getAccessibleRole() == AccessibleRole::TABLE )
+ [AquaA11yTableWrapper addAttributeNamesTo: attributeNames object: self];
+
+ if ( [ self accessibleText ] != nil ) {
+ [ AquaA11yTextWrapper addAttributeNamesTo: attributeNames ];
+ }
+ if ( [ self accessibleComponent ] != nil ) {
+ [ AquaA11yComponentWrapper addAttributeNamesTo: attributeNames ];
+ }
+ if ( [ self accessibleSelection ] != nil ) {
+ [ AquaA11ySelectionWrapper addAttributeNamesTo: attributeNames ];
+ }
+ if ( [ self accessibleValue ] != nil ) {
+ [ AquaA11yValueWrapper addAttributeNamesTo: attributeNames ];
+ }
+ [ nativeSubrole release ];
+ [ title release ];
+ return attributeNames;
+ } catch ( DisposedException & e ) { // Object is no longer available
+ if ( nativeSubrole != nil ) {
+ [ nativeSubrole release ];
+ }
+ if ( title != nil ) {
+ [ title release ];
+ }
+ if ( attributeNames != nil ) {
+ [ attributeNames release ];
+ }
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
+ return [ [ NSArray alloc ] init ];
+ }
+}
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ MacOSBOOL isSettable = NO;
+ if ( [ self accessibleText ] != nil ) {
+ isSettable = [ AquaA11yTextWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ if ( ! isSettable && [ self accessibleComponent ] != nil ) {
+ isSettable = [ AquaA11yComponentWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ if ( ! isSettable && [ self accessibleSelection ] != nil ) {
+ isSettable = [ AquaA11ySelectionWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ if ( ! isSettable && [ self accessibleValue ] != nil ) {
+ isSettable = [ AquaA11yValueWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ return isSettable; // TODO: to be completed
+}
+
+-(NSArray *)accessibilityParameterizedAttributeNames {
+ NSMutableArray * attributeNames = [ [ NSMutableArray alloc ] init ];
+ // Special Attributes depending on interface
+ if ( [ self accessibleText ] != nil ) {
+ [ AquaA11yTextWrapper addParameterizedAttributeNamesTo: attributeNames ];
+ }
+ return attributeNames; // TODO: to be completed
+}
+
+-(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
+ SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: YES ];
+ if ( [ self respondsToSelector: methodSelector ] ) {
+ return [ self performSelector: methodSelector withObject: parameter ];
+ }
+ return nil; // TODO: to be completed
+}
+
+-(MacOSBOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute {
+ return NO; // TODO
+}
+
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
+ SEL methodSelector = [ self selectorForAttribute: attribute asGetter: NO withGetterParameter: NO ];
+ if ( [ AquaA11yComponentWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11yComponentWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+ if ( [ AquaA11yTextWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11yTextWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+ if ( [ AquaA11ySelectionWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11ySelectionWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+ if ( [ AquaA11yValueWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11yValueWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+}
+
+-(id)accessibilityFocusedUIElement {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+
+ // as this seems to be the first API call on a newly created SalFrameView object,
+ // make sure self gets registered in the repository ..
+ [ self accessibleContext ];
+
+ AquaA11yWrapper * focusedUIElement = AquaA11yFocusListener::get()->getFocusedUIElement();
+// AquaA11yWrapper * ancestor = focusedUIElement;
+
+ // Make sure the focused object is a descendant of self
+// do {
+// if( self == ancestor )
+ return focusedUIElement;
+
+// ancestor = [ ancestor accessibilityAttributeValue: NSAccessibilityParentAttribute ];
+// } while( nil != ancestor );
+
+ return self;
+}
+
+// TODO: hard-coded like the role descriptions. is there a better way?
+-(NSString *)accessibilityActionDescription:(NSString *)action {
+ if ( [ action isEqualToString: NSAccessibilityConfirmAction ] ) {
+ return @"confirm";
+ } else if ( [ action isEqualToString: NSAccessibilityDecrementAction ] ) {
+ return @"decrement";
+ } else if ( [ action isEqualToString: NSAccessibilityDeleteAction ] ) {
+ return @"delete";
+ } else if ( [ action isEqualToString: NSAccessibilityIncrementAction ] ) {
+ return @"increment";
+ } else if ( [ action isEqualToString: NSAccessibilityPickAction ] ) {
+ return @"pick";
+ } else if ( [ action isEqualToString: NSAccessibilityPressAction ] ) {
+ return @"press";
+ } else if ( [ action isEqualToString: NSAccessibilityCancelAction ] ) {
+ return @"cancel";
+ } else if ( [ action isEqualToString: NSAccessibilityRaiseAction ] ) {
+ return @"raise";
+ } else if ( [ action isEqualToString: NSAccessibilityShowMenuAction ] ) {
+ return @"show menu";
+ } else {
+ return [ NSString string ];
+ }
+}
+
+-(AquaA11yWrapper *)actionResponder {
+ AquaA11yWrapper * wrapper = nil;
+ // get some information
+ NSString * role = (NSString *) [ self accessibilityAttributeValue: NSAccessibilityRoleAttribute ];
+ id enabledAttr = [ self enabledAttribute ];
+ MacOSBOOL enabled = [ enabledAttr boolValue ];
+ NSView * parent = (NSView *) [ self accessibilityAttributeValue: NSAccessibilityParentAttribute ];
+ AquaA11yWrapper * parentAsWrapper = nil;
+ if ( [ parent isKindOfClass: [ AquaA11yWrapper class ] ] ) {
+ parentAsWrapper = (AquaA11yWrapper *) parent;
+ }
+ NSString * parentRole = (NSString *) [ parent accessibilityAttributeValue: NSAccessibilityRoleAttribute ];
+ // if we are a textarea inside a combobox, then the combobox is the action responder
+ if ( enabled
+ && [ role isEqualToString: NSAccessibilityTextAreaRole ]
+ && [ parentRole isEqualToString: NSAccessibilityComboBoxRole ]
+ && parentAsWrapper != nil ) {
+ wrapper = parentAsWrapper;
+ } else if ( enabled && [ self accessibleAction ] != nil ) {
+ wrapper = self ;
+ }
+ [ parentRole release ];
+ [ enabledAttr release ];
+ [ role release ];
+ return wrapper;
+}
+
+-(void)accessibilityPerformAction:(NSString *)action {
+ AquaA11yWrapper * actionResponder = [ self actionResponder ];
+ if ( actionResponder != nil ) {
+ [ AquaA11yActionWrapper doAction: action ofElement: actionResponder ];
+ }
+}
+
+-(NSArray *)accessibilityActionNames {
+ NSArray * actionNames = nil;
+ AquaA11yWrapper * actionResponder = [ self actionResponder ];
+ if ( actionResponder != nil ) {
+ actionNames = [ AquaA11yActionWrapper actionNamesForElement: actionResponder ];
+ } else {
+ actionNames = [ [ NSArray alloc ] init ];
+ }
+ return actionNames;
+}
+
+#pragma mark -
+#pragma mark Hit Test
+
+-(MacOSBOOL)isViewElement:(NSObject *)viewElement hitByPoint:(NSPoint)point {
+ MacOSBOOL hit = NO;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ NSValue * position = [ viewElement accessibilityAttributeValue: NSAccessibilityPositionAttribute ];
+ NSValue * size = [ viewElement accessibilityAttributeValue: NSAccessibilitySizeAttribute ];
+ if ( position != nil && size != nil ) {
+ float minX = [ position pointValue ].x;
+ float minY = [ position pointValue ].y;
+ float maxX = minX + [ size sizeValue ].width;
+ float maxY = minY + [ size sizeValue ].height;
+ if ( minX < point.x && maxX > point.x && minY < point.y && maxY > point.y ) {
+ hit = YES;
+ }
+ }
+ [ pool release ];
+ return hit;
+}
+
+Reference < XAccessibleContext > hitTestRunner ( com::sun::star::awt::Point point,
+ Reference < XAccessibleContext > rxAccessibleContext ) {
+ Reference < XAccessibleContext > hitChild;
+ Reference < XAccessibleContext > emptyReference;
+ try {
+ Reference < XAccessibleComponent > rxAccessibleComponent ( rxAccessibleContext, UNO_QUERY );
+ if ( rxAccessibleComponent.is() ) {
+ com::sun::star::awt::Point location = rxAccessibleComponent -> getLocationOnScreen();
+ com::sun::star::awt::Point hitPoint ( point.X - location.X , point.Y - location.Y);
+ Reference < XAccessible > rxAccessible = rxAccessibleComponent -> getAccessibleAtPoint ( hitPoint );
+ if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
+ if ( rxAccessible -> getAccessibleContext() -> getAccessibleChildCount() > 0 ) {
+ hitChild = hitTestRunner ( point, rxAccessible -> getAccessibleContext() );
+ if ( ! hitChild.is() ) {
+ hitChild = rxAccessible -> getAccessibleContext();
+ }
+ } else {
+ hitChild = rxAccessible -> getAccessibleContext();
+ }
+ }
+ }
+ if ( !hitChild.is() && rxAccessibleContext -> getAccessibleChildCount() > 0 ) { // special treatment for e.g. comboboxes
+ for ( int i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
+ Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
+ if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
+ Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
+ if ( myHitChild.is() ) {
+ hitChild = myHitChild;
+ break;
+ }
+ }
+ }
+ }
+ } catch ( RuntimeException ) {
+ return emptyReference;
+ }
+ return hitChild;
+}
+
+-(id)accessibilityHitTest:(NSPoint)point {
+ static id wrapper = nil;
+ if ( nil != wrapper ) {
+ [ wrapper release ];
+ wrapper = nil;
+ }
+ Reference < XAccessibleContext > hitChild;
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ com::sun::star::awt::Point hitPoint ( static_cast<long>(point.x) , static_cast<long>(screenRect.size.height - point.y) );
+ // check child windows first
+ NSWindow * window = (NSWindow *) [ self accessibilityAttributeValue: NSAccessibilityWindowAttribute ];
+ NSArray * childWindows = [ window childWindows ];
+ if ( [ childWindows count ] > 0 ) {
+ NSWindow * element = nil;
+ NSEnumerator * enumerator = [ childWindows objectEnumerator ];
+ while ( ( element = [ enumerator nextObject ] ) && hitChild == nil ) {
+ if ( [ element isKindOfClass: [ SalFrameWindow class ] ] && [ self isViewElement: element hitByPoint: point ] ) {
+ // we have a child window that is hit
+ Reference < XAccessibleRelationSet > relationSet = [ ( ( SalFrameWindow * ) element ) accessibleContext ] -> getAccessibleRelationSet();
+ if ( relationSet.is() && relationSet -> containsRelation ( AccessibleRelationType::SUB_WINDOW_OF )) {
+ // we have a valid relation to the parent element
+ AccessibleRelation relation = relationSet -> getRelationByType ( AccessibleRelationType::SUB_WINDOW_OF );
+ for ( int i = 0; i < relation.TargetSet.getLength() && !hitChild.is(); i++ ) {
+ Reference < XAccessible > rxAccessible ( relation.TargetSet [ i ], UNO_QUERY );
+ if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
+ // hit test for children of parent
+ hitChild = hitTestRunner ( hitPoint, rxAccessible -> getAccessibleContext() );
+ }
+ }
+ }
+ }
+ }
+ }
+ // nothing hit yet, so check ourself
+ if ( ! hitChild.is() ) {
+ if ( mpReferenceWrapper == nil ) {
+ [ self setDefaults: [ self accessibleContext ] ];
+ }
+ hitChild = hitTestRunner ( hitPoint, mpReferenceWrapper -> rAccessibleContext );
+ }
+ if ( hitChild.is() ) {
+ wrapper = [ AquaA11yFactory wrapperForAccessibleContext: hitChild ];
+ }
+ if ( wrapper != nil ) {
+ [ wrapper retain ]; // TODO: retain only when transient ?
+ }
+ return wrapper;
+}
+
+#pragma mark -
+#pragma mark Access Methods
+
+-(XAccessibleAction *)accessibleAction {
+ return mpReferenceWrapper -> rAccessibleAction.get();
+}
+
+-(XAccessibleContext *)accessibleContext {
+ return mpReferenceWrapper -> rAccessibleContext.get();
+}
+
+-(XAccessibleComponent *)accessibleComponent {
+ return mpReferenceWrapper -> rAccessibleComponent.get();
+}
+
+-(XAccessibleExtendedComponent *)accessibleExtendedComponent {
+ return mpReferenceWrapper -> rAccessibleExtendedComponent.get();
+}
+
+-(XAccessibleSelection *)accessibleSelection {
+ return mpReferenceWrapper -> rAccessibleSelection.get();
+}
+
+-(XAccessibleTable *)accessibleTable {
+ return mpReferenceWrapper -> rAccessibleTable.get();
+}
+
+-(XAccessibleText *)accessibleText {
+ return mpReferenceWrapper -> rAccessibleText.get();
+}
+
+-(XAccessibleEditableText *)accessibleEditableText {
+ return mpReferenceWrapper -> rAccessibleEditableText.get();
+}
+
+-(XAccessibleValue *)accessibleValue {
+ return mpReferenceWrapper -> rAccessibleValue.get();
+}
+
+-(XAccessibleTextAttributes *)accessibleTextAttributes {
+ return mpReferenceWrapper -> rAccessibleTextAttributes.get();
+}
+
+-(XAccessibleMultiLineText *)accessibleMultiLineText {
+ return mpReferenceWrapper -> rAccessibleMultiLineText.get();
+}
+
+-(NSView *)viewElementForParent {
+ return self;
+}
+
+// These four are for AXTextAreas only. They are needed, because bold and italic
+// attributes have to be bound to a font on the Mac. Our UNO-API instead handles
+// and reports them independently. When they occur we bundle them to a font with
+// this information here to create a according NSFont.
+-(void)setDefaultFontname:(NSString *)fontname {
+ if ( mpDefaultFontname != nil ) {
+ [ mpDefaultFontname release ];
+ }
+ mpDefaultFontname = fontname;
+}
+
+-(NSString *)defaultFontname {
+ return mpDefaultFontname;
+}
+
+-(void)setDefaultFontsize:(float)fontsize {
+ mDefaultFontsize = fontsize;
+}
+
+-(float)defaultFontsize {
+ return mDefaultFontsize;
+}
+
+-(void)setActsAsRadioGroup:(MacOSBOOL)actsAsRadioGroup {
+ mActsAsRadioGroup = actsAsRadioGroup;
+}
+
+-(MacOSBOOL)actsAsRadioGroup {
+ return mActsAsRadioGroup;
+}
+
++(void)setPopupMenuOpen:(MacOSBOOL)popupMenuOpen {
+ isPopupMenuOpen = popupMenuOpen;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperbutton.h b/vcl/aqua/source/a11y/aqua11ywrapperbutton.h
new file mode 100644
index 000000000000..aa35062d15c4
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperbutton.h
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERBUTTON_H
+#define _SV_AQUA11WRAPPERBUTTON_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperButton : AquaA11yWrapper
+{
+}
+-(id)valueAttribute;
+-(id)descriptionAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERBUTTON_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperbutton.mm b/vcl/aqua/source/a11y/aqua11ywrapperbutton.mm
new file mode 100644
index 000000000000..48f1804c58a2
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperbutton.mm
@@ -0,0 +1,61 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperbutton.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXButton role
+
+@implementation AquaA11yWrapperButton : AquaA11yWrapper
+
+-(id)valueAttribute {
+ return [ NSString string ]; // we propagate AXTitle, that's enough
+}
+
+-(id)descriptionAttribute {
+ return [ NSString string ]; // we propagate AXTitle, that's enough
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ if ( [ attributeNames containsObject: NSAccessibilityTitleAttribute ] ) {
+ [ attributeNames removeObject: NSAccessibilityDescriptionAttribute ];
+ } else {
+ [ attributeNames addObject: NSAccessibilityTitleAttribute ];
+ }
+ // Remove text-specific attributes
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercheckbox.h b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.h
new file mode 100644
index 000000000000..95fee9a3ec4b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.h
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERCHECKBOX_H
+#define _SV_AQUA11WRAPPERCHECKBOX_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperCheckBox : AquaA11yWrapper
+{
+}
+-(id)valueAttribute;
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERCHECKOBOX_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm
new file mode 100644
index 000000000000..c4ac34dc5bce
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrappercheckbox.h"
+#include "aqua11yvaluewrapper.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXCheckbox role
+
+@implementation AquaA11yWrapperCheckBox : AquaA11yWrapper
+
+-(id)valueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper valueAttributeForElement: self ];
+ }
+ return [ NSNumber numberWithInt: 0 ];
+}
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) {
+ return NO;
+ }
+ return [ super accessibilityIsAttributeSettable: attribute ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Remove text-specific attributes
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames addObject: NSAccessibilityValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityMinValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityMaxValueAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercombobox.h b/vcl/aqua/source/a11y/aqua11ywrappercombobox.h
new file mode 100644
index 000000000000..7ed76d607176
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercombobox.h
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERCOMBOBOX_H
+#define _SV_AQUA11WRAPPERCOMBOBOX_H
+
+#include "aqua11ywrapper.h"
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+@interface AquaA11yWrapperComboBox : AquaA11yWrapper
+{
+ AquaA11yWrapper * textArea;
+}
+-(id)initWithAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) anAccessibleContext;
+-(id)valueAttribute;
+-(id)numberOfCharactersAttribute;
+-(id)selectedTextAttribute;
+-(id)selectedTextRangeAttribute;
+-(id)visibleCharacterRangeAttribute;
+// Accessibility Protocol
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERCOMBOBOX_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercombobox.mm b/vcl/aqua/source/a11y/aqua11ywrappercombobox.mm
new file mode 100644
index 000000000000..85aed320e470
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercombobox.mm
@@ -0,0 +1,161 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrappercombobox.h"
+#include "aqua11yrolehelper.h"
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+// Wrapper for AXCombobox role
+
+@implementation AquaA11yWrapperComboBox : AquaA11yWrapper
+
+#pragma mark -
+#pragma mark Specialized Init Method
+
+-(id)initWithAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ self = [ super initWithAccessibleContext: rxAccessibleContext ];
+ if ( self != nil )
+ {
+ textArea = nil;
+ }
+ return self;
+}
+
+#pragma mark -
+#pragma mark Private Helper Method
+
+-(AquaA11yWrapper *)textArea {
+ // FIXME: May cause problems when stored. Then get dynamically each time (bad performance!)
+ if ( textArea == nil ) {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ NSArray * elementChildren = [ super childrenAttribute ];
+ if ( [ elementChildren count ] > 0 ) {
+ NSEnumerator * enumerator = [ elementChildren objectEnumerator ];
+ id child;
+ while ( ( child = [ enumerator nextObject ] ) ) {
+ AquaA11yWrapper * element = ( AquaA11yWrapper * ) child;
+ if ( [ [ AquaA11yRoleHelper getNativeRoleFrom: [ element accessibleContext ] ] isEqualToString: NSAccessibilityTextAreaRole ] ) {
+ textArea = element;
+ break;
+ }
+ }
+ }
+ [ pool release ];
+ }
+ return textArea;
+}
+
+#pragma mark -
+#pragma mark Wrapped Attributes From Contained Text Area
+
+-(id)valueAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] valueAttribute ];
+ }
+ return @"";
+}
+
+-(id)numberOfCharactersAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] numberOfCharactersAttribute ];
+ }
+ return [ NSNumber numberWithInt: 0 ];
+}
+
+-(id)selectedTextAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] selectedTextAttribute ];
+ }
+ return @"";
+}
+
+-(id)selectedTextRangeAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] selectedTextRangeAttribute ];
+ }
+ return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ];
+}
+
+-(id)visibleCharacterRangeAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] visibleCharacterRangeAttribute ];
+ }
+ return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ];
+}
+
+#pragma mark -
+#pragma mark Accessibility Protocol
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ if ( [ self textArea ] != nil && (
+ [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
+ || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) ) {
+ return [ [ self textArea ] accessibilityIsAttributeSettable: attribute ];
+ }
+ return [ super accessibilityIsAttributeSettable: attribute ];
+}
+
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
+ if ( [ self textArea ] != nil && (
+ [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
+ || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) ) {
+ return [ [ self textArea ] accessibilitySetValue: value forAttribute: attribute ];
+ }
+ return [ super accessibilitySetValue: value forAttribute: attribute ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ NSArray arrayWithObjects:
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityChildrenAttribute,
+ nil ]
+ ];
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilityExpandedAttribute,
+ NSAccessibilityValueAttribute,
+ NSAccessibilityNumberOfCharactersAttribute,
+ NSAccessibilitySelectedTextAttribute,
+ NSAccessibilitySelectedTextRangeAttribute,
+ NSAccessibilityVisibleCharacterRangeAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappergroup.h b/vcl/aqua/source/a11y/aqua11ywrappergroup.h
new file mode 100644
index 000000000000..7757e067ee22
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappergroup.h
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERGROUP_H
+#define _SV_AQUA11WRAPPERGROUP_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperGroup : AquaA11yWrapper
+{
+}
+-(id)titleUIElementAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappergroup.mm b/vcl/aqua/source/a11y/aqua11ywrappergroup.mm
new file mode 100644
index 000000000000..42298f9c745b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappergroup.mm
@@ -0,0 +1,57 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrappergroup.h"
+
+// Wrapper for AXGroup role
+
+@implementation AquaA11yWrapperGroup : AquaA11yWrapper
+
+-(id)titleUIElementAttribute {
+ return self; // TODO
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ NSArray arrayWithObjects:
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilitySelectedChildrenAttribute,
+ nil ]
+ ];
+ [ attributeNames addObject: NSAccessibilityContentsAttribute ];
+ [ attributeNames addObject: NSAccessibilityTitleUIElementAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperlist.h b/vcl/aqua/source/a11y/aqua11ywrapperlist.h
new file mode 100644
index 000000000000..95df8323467b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperlist.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERLIST_H
+#define _SV_AQUA11WRAPPERLIST_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperList : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERLIST_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperlist.mm b/vcl/aqua/source/a11y/aqua11ywrapperlist.mm
new file mode 100644
index 000000000000..eeb210d70e65
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperlist.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperlist.h"
+
+using namespace ::com::sun::star::accessibility;
+
+// Wrapper for AXList role
+
+@implementation AquaA11yWrapperList : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObject: NSAccessibilityOrientationAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h
new file mode 100644
index 000000000000..13ceee6f826f
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERRADIOBUTTON_H
+#define _SV_AQUA11WRAPPERRADIOBUTTON_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperRadioButton : AquaA11yWrapper
+{
+}
+-(id)valueAttribute;
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERRADIOGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm
new file mode 100644
index 000000000000..54d6edac619a
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperradiobutton.h"
+#include "aqua11ytextwrapper.h"
+#include "aqua11yvaluewrapper.h"
+
+// Wrapper for AXRadioButton role
+
+@implementation AquaA11yWrapperRadioButton : AquaA11yWrapper
+
+-(id)valueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper valueAttributeForElement: self ];
+ }
+ return [ NSNumber numberWithInt: 0 ];
+}
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) {
+ return NO;
+ }
+ return [ super accessibilityIsAttributeSettable: attribute ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames addObject: NSAccessibilityMinValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityMaxValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityValueAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h
new file mode 100644
index 000000000000..544b709223b3
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERRADIOGROUP_H
+#define _SV_AQUA11WRAPPERRADIOGROUP_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperRadioGroup : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERRADIOGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm
new file mode 100644
index 000000000000..f89ac78b044c
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperradiogroup.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXRadioGroup role
+
+@implementation AquaA11yWrapperRadioGroup : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperrow.h b/vcl/aqua/source/a11y/aqua11ywrapperrow.h
new file mode 100644
index 000000000000..252af6f5987f
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperrow.h
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERROW_H
+#define _SV_AQUA11WRAPPERROW_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperRow : AquaA11yWrapper
+{
+}
+-(id)disclosingAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERROW_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperrow.mm b/vcl/aqua/source/a11y/aqua11ywrapperrow.mm
new file mode 100644
index 000000000000..d49e229218bf
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperrow.mm
@@ -0,0 +1,56 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperrow.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXRow role
+
+@implementation AquaA11yWrapperRow : AquaA11yWrapper
+
+-(id)disclosingAttribute {
+ return NO; // TODO
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ [ attributeNames removeObject: NSAccessibilityEnabledAttribute ];
+ [ attributeNames removeObject: NSAccessibilityFocusedAttribute ];
+ [ attributeNames addObject: NSAccessibilitySelectedAttribute ];
+ [ attributeNames addObject: NSAccessibilityDisclosingAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h
new file mode 100644
index 000000000000..2c206fd0904b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERSCROLLAREA_H
+#define _SV_AQUA11WRAPPERSCROLLAREA_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperScrollArea : AquaA11yWrapper
+{
+}
+-(id)verticalScrollBarAttribute;
+-(id)horizontalScrollBarAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSCROLLAREA_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm
new file mode 100644
index 000000000000..f375e5ce788d
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm
@@ -0,0 +1,84 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperscrollarea.h"
+#include "aqua11ywrapperscrollbar.h"
+#include "aqua11yrolehelper.h"
+
+// Wrapper for AXScrollArea role
+
+@implementation AquaA11yWrapperScrollArea : AquaA11yWrapper
+
+-(id)scrollBarWithOrientation:(NSString *)orientation {
+ AquaA11yWrapper * theScrollBar = nil;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ NSArray * elementChildren = [ self accessibilityAttributeValue: NSAccessibilityChildrenAttribute ];
+ if ( [ elementChildren count ] > 0 ) {
+ NSEnumerator * enumerator = [ elementChildren objectEnumerator ];
+ id child;
+ while ( ( child = [ enumerator nextObject ] ) ) {
+ AquaA11yWrapper * element = ( AquaA11yWrapper * ) child;
+ if ( [ element isKindOfClass: [ AquaA11yWrapperScrollBar class ] ] ) {
+ AquaA11yWrapperScrollBar * scrollBar = (AquaA11yWrapperScrollBar *) element;
+ if ( [ [ scrollBar orientationAttribute ] isEqualToString: orientation ] ) {
+ theScrollBar = scrollBar;
+ break;
+ }
+ }
+ }
+ }
+ [ pool release ];
+ return theScrollBar;
+}
+
+-(id)verticalScrollBarAttribute {
+ return [ self scrollBarWithOrientation: NSAccessibilityVerticalOrientationValue ];
+}
+
+-(id)horizontalScrollBarAttribute {
+ return [ self scrollBarWithOrientation: NSAccessibilityHorizontalOrientationValue ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObject: NSAccessibilityEnabledAttribute ];
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilityContentsAttribute,
+ NSAccessibilityVerticalScrollBarAttribute,
+ NSAccessibilityHorizontalScrollBarAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h
new file mode 100644
index 000000000000..1070c682cd5e
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERSCROLLBAR_H
+#define _SV_AQUA11WRAPPERSCROLLBAR_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperScrollBar : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSCROLLBAR_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm
new file mode 100644
index 000000000000..826da647055b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperscrollbar.h"
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+
+// Wrapper for AXScrollBar role
+
+@implementation AquaA11yWrapperScrollBar : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObject: NSAccessibilityOrientationAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappersplitter.h b/vcl/aqua/source/a11y/aqua11ywrappersplitter.h
new file mode 100644
index 000000000000..084a72ea7a18
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappersplitter.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERSPLITTER_H
+#define _SV_AQUA11WRAPPERSPLITTER_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperSplitter : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSPLITTER_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappersplitter.mm b/vcl/aqua/source/a11y/aqua11ywrappersplitter.mm
new file mode 100644
index 000000000000..4dc645c006c8
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappersplitter.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrappersplitter.h"
+
+using namespace ::com::sun::star::accessibility;
+
+// Wrapper for AXSplitter role
+
+@implementation AquaA11yWrapperSplitter : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObject: NSAccessibilityOrientationAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperstatictext.h b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.h
new file mode 100644
index 000000000000..c21e5573d125
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.h
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERSTATICTEXT_H
+#define _SV_AQUA11WRAPPERSTATICTEXT_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperStaticText : AquaA11yWrapper
+{
+}
+-(id)titleAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSTATICTEXT_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm
new file mode 100644
index 000000000000..7192e64b2e7c
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm
@@ -0,0 +1,56 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperstatictext.h"
+
+// Wrapper for AXStaticText role
+
+@implementation AquaA11yWrapperStaticText : AquaA11yWrapper
+
+-(id)titleAttribute {
+ NSString * title = [ super titleAttribute ];
+ if ( [ title isEqualToString: [ super valueAttribute ] ] ) {
+ return [ NSString string ];
+ }
+ return title;
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ [ attributeNames removeObject: NSAccessibilitySharedTextUIElementsAttribute ];
+ [ attributeNames removeObject: NSAccessibilitySharedCharacterRangeAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertabgroup.h b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.h
new file mode 100644
index 000000000000..be72b9e27396
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERTABGROUP_H
+#define _SV_AQUA11WRAPPERTABGROUP_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperTabGroup : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERTABGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm
new file mode 100644
index 000000000000..708ae5440c4f
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrappertabgroup.h"
+
+// Wrapper for AXTabGroup role
+
+@implementation AquaA11yWrapperTabGroup : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilityContentsAttribute,
+ NSAccessibilityTabsAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertextarea.h b/vcl/aqua/source/a11y/aqua11ywrappertextarea.h
new file mode 100644
index 000000000000..724f85994053
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertextarea.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERTEXTAREA_H
+#define _SV_AQUA11WRAPPERTEXTAREA_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperTextArea : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERTEXTAREA_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertextarea.mm b/vcl/aqua/source/a11y/aqua11ywrappertextarea.mm
new file mode 100644
index 000000000000..9a425eb2b893
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertextarea.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrappertextarea.h"
+
+// Wrapper for AXTextArea role
+
+@implementation AquaA11yWrapperTextArea : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ [ attributeNames removeObject: NSAccessibilityEnabledAttribute ];
+ [ attributeNames addObject: NSAccessibilityChildrenAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertoolbar.h b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.h
new file mode 100644
index 000000000000..e7ac0a25acec
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERTOOLBAR_H
+#define _SV_AQUA11WRAPPERTOOLBAR_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperToolbar : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERTOOLBAR_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm
new file mode 100644
index 000000000000..28990355af55
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrappertoolbar.h"
+
+// Wrapper for AXToolbar role
+
+@implementation AquaA11yWrapperToolbar : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ NSArray arrayWithObjects:
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityEnabledAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/documentfocuslistener.cxx b/vcl/aqua/source/a11y/documentfocuslistener.cxx
new file mode 100644
index 000000000000..02a7337ce397
--- /dev/null
+++ b/vcl/aqua/source/a11y/documentfocuslistener.cxx
@@ -0,0 +1,253 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "documentfocuslistener.hxx"
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTBROADCASTER_HPP_
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEEVENTID_HPP_
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLESTATETYPE_HPP_
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#endif
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+
+//------------------------------------------------------------------------------
+
+DocumentFocusListener::DocumentFocusListener(AquaA11yFocusTracker& rTracker) :
+ m_aFocusTracker(rTracker)
+{
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+DocumentFocusListener::disposing( const EventObject& aEvent )
+ throw (RuntimeException)
+{
+ // Unref the object here, but do not remove as listener since the object
+ // might no longer be in a state that safely allows this.
+ if( aEvent.Source.is() )
+ m_aRefList.erase(aEvent.Source);
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+DocumentFocusListener::notifyEvent( const AccessibleEventObject& aEvent )
+ throw( RuntimeException )
+{
+ switch( aEvent.EventId )
+ {
+ case AccessibleEventId::STATE_CHANGED:
+ try
+ {
+ sal_Int16 nState = AccessibleStateType::INVALID;
+ aEvent.NewValue >>= nState;
+
+ if( AccessibleStateType::FOCUSED == nState )
+ m_aFocusTracker.setFocusedObject( getAccessible(aEvent) );
+ }
+ catch(IndexOutOfBoundsException e)
+ {
+ OSL_TRACE("Focused object has invalid index in parent");
+ }
+ break;
+
+ case AccessibleEventId::CHILD:
+ {
+ Reference< XAccessible > xChild;
+ if( (aEvent.OldValue >>= xChild) && xChild.is() )
+ detachRecursive(xChild);
+
+ if( (aEvent.NewValue >>= xChild) && xChild.is() )
+ attachRecursive(xChild);
+ }
+ break;
+
+ case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+ {
+ Reference< XAccessible > xAccessible( getAccessible(aEvent) );
+ detachRecursive(xAccessible);
+ attachRecursive(xAccessible);
+ }
+
+ OSL_TRACE( "Invalidate all children called\n" );
+ break;
+ default:
+ break;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+Reference< XAccessible > DocumentFocusListener::getAccessible(const EventObject& aEvent )
+ throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessible > xAccessible(aEvent.Source, UNO_QUERY);
+
+ if( xAccessible.is() )
+ return xAccessible;
+
+ Reference< XAccessibleContext > xContext(aEvent.Source, UNO_QUERY);
+
+ if( xContext.is() )
+ {
+ Reference< XAccessible > xParent( xContext->getAccessibleParent() );
+ if( xParent.is() )
+ {
+ Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if( xParentContext.is() )
+ {
+ return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
+ }
+ }
+ }
+
+ return Reference< XAccessible >();
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::attachRecursive(const Reference< XAccessible >& xAccessible)
+ throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ attachRecursive(xAccessible, xContext);
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::attachRecursive(
+ const Reference< XAccessible >& xAccessible,
+ const Reference< XAccessibleContext >& xContext
+) throw (IndexOutOfBoundsException, RuntimeException)
+{
+ if( xContext.is() )
+ {
+ Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ attachRecursive(xAccessible, xContext, xStateSet);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::attachRecursive(
+ const Reference< XAccessible >& xAccessible,
+ const Reference< XAccessibleContext >& xContext,
+ const Reference< XAccessibleStateSet >& xStateSet
+) throw (IndexOutOfBoundsException,RuntimeException)
+{
+ if( xStateSet->contains(AccessibleStateType::FOCUSED ) )
+ m_aFocusTracker.setFocusedObject( xAccessible );
+
+ Reference< XAccessibleEventBroadcaster > xBroadcaster =
+ Reference< XAccessibleEventBroadcaster >(xContext, UNO_QUERY);
+
+ // If not already done, add the broadcaster to the list and attach as listener.
+ if( xBroadcaster.is() && m_aRefList.insert(xBroadcaster).second )
+ {
+ xBroadcaster->addEventListener(static_cast< XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ attachRecursive(xChild);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::detachRecursive(const Reference< XAccessible >& xAccessible)
+ throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ detachRecursive(xAccessible, xContext);
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::detachRecursive(
+ const Reference< XAccessible >& xAccessible,
+ const Reference< XAccessibleContext >& xContext
+) throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ detachRecursive(xAccessible, xContext, xStateSet);
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::detachRecursive(
+ const Reference< XAccessible >&,
+ const Reference< XAccessibleContext >& xContext,
+ const Reference< XAccessibleStateSet >& xStateSet
+) throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleEventBroadcaster > xBroadcaster =
+ Reference< XAccessibleEventBroadcaster >(xContext, UNO_QUERY);
+
+ if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
+ {
+ xBroadcaster->removeEventListener(static_cast< XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ detachRecursive(xChild);
+ }
+ }
+ }
+}
diff --git a/vcl/aqua/source/a11y/documentfocuslistener.hxx b/vcl/aqua/source/a11y/documentfocuslistener.hxx
new file mode 100644
index 000000000000..863bc59d173f
--- /dev/null
+++ b/vcl/aqua/source/a11y/documentfocuslistener.hxx
@@ -0,0 +1,101 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DOCUMENTFOCUSLISTENER_HXX_
+#define _DOCUMENTFOCUSLISTENER_HXX_
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTLISTENER_HPP_
+#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
+#endif
+
+#ifndef _CPPUHELPER_IMPLBASE1_HXX_
+#include <cppuhelper/implbase1.hxx>
+#endif
+
+#include "aqua11yfocustracker.hxx"
+#include <set>
+
+// -------------------------
+// - DocumentFocusListener -
+// -------------------------
+
+class DocumentFocusListener :
+ public ::cppu::WeakImplHelper1< ::com::sun::star::accessibility::XAccessibleEventListener >
+{
+
+public:
+
+ DocumentFocusListener(AquaA11yFocusTracker& rTracker);
+
+ void attachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void attachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void attachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void detachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void detachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void detachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ static ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessible(const ::com::sun::star::lang::EventObject& aEvent )
+ throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source )
+ throw (::com::sun::star::uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void SAL_CALL notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+private:
+ std::set< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > m_aRefList;
+
+ AquaA11yFocusTracker& m_aFocusTracker;
+};
+
+#endif // _DOCUMENTFOCUSLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/source/a11y/makefile.mk b/vcl/aqua/source/a11y/makefile.mk
new file mode 100644
index 000000000000..0a16281e5a69
--- /dev/null
+++ b/vcl/aqua/source/a11y/makefile.mk
@@ -0,0 +1,88 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=sala11y
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= \
+ $(SLO)$/aqua11ywrapper.obj \
+ $(SLO)$/aqua11yfactory.obj \
+ $(SLO)$/aqua11yfocuslistener.obj \
+ $(SLO)$/aqua11yfocustracker.obj \
+ $(SLO)$/aqua11ylistener.obj \
+ $(SLO)$/aqua11yrolehelper.obj \
+ $(SLO)$/aqua11yactionwrapper.obj \
+ $(SLO)$/aqua11ycomponentwrapper.obj \
+ $(SLO)$/aqua11yselectionwrapper.obj \
+ $(SLO)$/aqua11ytablewrapper.obj \
+ $(SLO)$/aqua11ytextattributeswrapper.obj \
+ $(SLO)$/aqua11ytextwrapper.obj \
+ $(SLO)$/aqua11yutil.obj \
+ $(SLO)$/aqua11yvaluewrapper.obj \
+ $(SLO)$/aqua11ywrapperbutton.obj \
+ $(SLO)$/aqua11ywrappercheckbox.obj \
+ $(SLO)$/aqua11ywrappercombobox.obj \
+ $(SLO)$/aqua11ywrappergroup.obj \
+ $(SLO)$/aqua11ywrapperlist.obj \
+ $(SLO)$/aqua11ywrapperradiobutton.obj \
+ $(SLO)$/aqua11ywrapperradiogroup.obj \
+ $(SLO)$/aqua11ywrapperrow.obj \
+ $(SLO)$/aqua11ywrapperscrollarea.obj \
+ $(SLO)$/aqua11ywrapperscrollbar.obj \
+ $(SLO)$/aqua11ywrappersplitter.obj \
+ $(SLO)$/aqua11ywrapperstatictext.obj \
+ $(SLO)$/aqua11ywrappertabgroup.obj \
+ $(SLO)$/aqua11ywrappertextarea.obj \
+ $(SLO)$/aqua11ywrappertoolbar.obj \
+ $(SLO)$/documentfocuslistener.obj
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/aqua/source/a11y/readme.txt b/vcl/aqua/source/a11y/readme.txt
new file mode 100644
index 000000000000..19e80ab1a162
--- /dev/null
+++ b/vcl/aqua/source/a11y/readme.txt
@@ -0,0 +1,8 @@
+Naming scheme:
+
+aqua11yXYZhelper: Helper class providing static methods
+
+aqua11yXYZwrapper: Wrapper around one (or two) UNO-interfaces
+
+aqua11ywrapperXYZ: Subclass of aqua11ywrapper for a specific AXRole
+
diff --git a/vcl/aqua/source/app/makefile.mk b/vcl/aqua/source/app/makefile.mk
new file mode 100644
index 000000000000..a0ddcbc02226
--- /dev/null
+++ b/vcl/aqua/source/app/makefile.mk
@@ -0,0 +1,63 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=salapp
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= $(SLO)$/salinst.obj \
+ $(SLO)$/saldata.obj \
+ $(SLO)$/vclnsapp.obj \
+ $(SLO)$/saltimer.obj \
+ $(SLO)$/salnstimer.obj \
+ $(SLO)$/salsys.obj
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/aqua/source/app/saldata.cxx b/vcl/aqua/source/app/saldata.cxx
new file mode 100644
index 000000000000..3cb878636ad3
--- /dev/null
+++ b/vcl/aqua/source/app/saldata.cxx
@@ -0,0 +1,293 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "saldata.hxx"
+#include "salnsmenu.h"
+#include "salinst.h"
+#import "apple_remote/RemoteMainController.h"
+
+oslThreadKey SalData::s_aAutoReleaseKey = 0;
+
+static void SAL_CALL releasePool( void* pPool )
+{
+ if( pPool )
+ [(NSAutoreleasePool*)pPool release];
+}
+
+SalData::SalData()
+:
+ mpTimerProc( NULL ),
+ mpFirstInstance( NULL ),
+ mpFirstObject( NULL ),
+ mpFirstVD( NULL ),
+ mpFirstPrinter( NULL ),
+ mpFontList( NULL ),
+ mpStatusItem( nil ),
+ mxRGBSpace( CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) ),
+ mxGraySpace( CGColorSpaceCreateWithName(kCGColorSpaceGenericGray) ),
+ mxP50Space( NULL ),
+ mxP50Pattern( NULL ),
+ maCursors( POINTER_COUNT, INVALID_CURSOR_PTR ),
+ mbIsScrollbarDoubleMax( false ),
+ mnSystemVersion( VER_TIGER ),
+ mpMainController( NULL ),
+ mpDockIconClickHandler( nil ),
+ mnDPIX( 0 ),
+ mnDPIY( 0 )
+{
+ if( s_aAutoReleaseKey == 0 )
+ s_aAutoReleaseKey = osl_createThreadKey( releasePool );
+}
+
+SalData::~SalData()
+{
+ CGPatternRelease( mxP50Pattern );
+ CGColorSpaceRelease( mxP50Space );
+ CGColorSpaceRelease( mxRGBSpace );
+ CGColorSpaceRelease( mxGraySpace );
+ for( unsigned int i = 0; i < maCursors.size(); i++ )
+ {
+ NSCursor* pCurs = maCursors[i];
+ if( pCurs && pCurs != INVALID_CURSOR_PTR )
+ [pCurs release];
+ }
+ if( s_aAutoReleaseKey )
+ {
+ // release the last pool
+ NSAutoreleasePool* pPool = nil;
+ pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
+ if( pPool )
+ {
+ osl_setThreadKeyData( s_aAutoReleaseKey, NULL );
+ [pPool release];
+ }
+
+ osl_destroyThreadKey( s_aAutoReleaseKey );
+ s_aAutoReleaseKey = 0;
+ }
+ if ( mpMainController )
+ [mpMainController release];
+}
+
+void SalData::ensureThreadAutoreleasePool()
+{
+ NSAutoreleasePool* pPool = nil;
+ if( s_aAutoReleaseKey )
+ {
+ pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
+ if( ! pPool )
+ {
+ pPool = [[NSAutoreleasePool alloc] init];
+ osl_setThreadKeyData( s_aAutoReleaseKey, pPool );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no autorelease key" );
+ }
+}
+
+void SalData::drainThreadAutoreleasePool()
+{
+ NSAutoreleasePool* pPool = nil;
+ if( s_aAutoReleaseKey )
+ {
+ pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
+ if( pPool )
+ {
+ // osl_setThreadKeyData( s_aAutoReleaseKey, NULL );
+ // [pPool release];
+ [pPool drain];
+ }
+ else
+ {
+ pPool = [[NSAutoreleasePool alloc] init];
+ osl_setThreadKeyData( s_aAutoReleaseKey, pPool );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no autorelease key" );
+ }
+}
+
+
+struct curs_ent
+{
+ const char* pBaseName;
+ const NSPoint aHotSpot;
+}
+const aCursorTab[ POINTER_COUNT ] =
+{
+{ NULL, { 0, 0 } }, //POINTER_ARROW
+{ "nullptr", { 16, 16 } }, //POINTER_NULL
+{ "hourglass", { 15, 15 } }, //POINTER_WAIT
+{ NULL, { 0, 0 } }, //POINTER_TEXT
+{ "help", { 0, 0 } }, //POINTER_HELP
+{ NULL, { 0, 0 } }, //POINTER_CROSS
+{ NULL, { 0, 0 } }, //POINTER_MOVE
+{ NULL, { 0, 0 } }, //POINTER_NSIZE
+{ NULL, { 0, 0 } }, //POINTER_SSIZE
+{ NULL, { 0, 0 } }, //POINTER_WSIZE
+{ NULL, { 0, 0 } }, //POINTER_ESIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_NWSIZE
+{ "neswsize", { 15, 15 } }, //POINTER_NESIZE
+{ "neswsize", { 15, 15 } }, //POINTER_SWSIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_SESIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_NSIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_SSIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_WSIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_ESIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_WINDOW_NWSIZE
+{ "neswsize", { 15, 15 } }, //POINTER_WINDOW_NESIZE
+{ "neswsize", { 15, 15 } }, //POINTER_WINDOW_SWSIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_WINDOW_SESIZE
+{ NULL, { 0, 0 } }, //POINTER_HSPLIT
+{ NULL, { 0, 0 } }, //POINTER_VSPLIT
+{ NULL, { 0, 0 } }, //POINTER_HSIZEBAR
+{ NULL, { 0, 0 } }, //POINTER_VSIZEBAR
+{ NULL, { 0, 0 } }, //POINTER_HAND
+{ NULL, { 0, 0 } }, //POINTER_REFHAND
+{ "pen", { 3, 27 } }, //POINTER_PEN
+{ "magnify", { 12, 13 } }, //POINTER_MAGNIFY
+{ "fill", { 10, 22 } }, //POINTER_FILL
+{ "rotate", { 15, 15 } }, //POINTER_ROTATE
+{ "hshear", { 15, 15 } }, //POINTER_HSHEAR
+{ "vshear", { 15, 15 } }, //POINTER_VSHEAR
+{ "mirror", { 14, 12 } }, //POINTER_MIRROR
+{ "crook", { 15, 14 } }, //POINTER_CROOK
+{ "crop", { 9, 9 } }, //POINTER_CROP
+{ "movept", { 0, 0 } }, //POINTER_MOVEPOINT
+{ "movebw", { 0, 0 } }, //POINTER_MOVEBEZIERWEIGHT
+{ "movedata", { 0, 0 } }, //POINTER_MOVEDATA
+{ "copydata", { 0, 0 } }, //POINTER_COPYDATA
+{ "linkdata", { 0, 0 } }, //POINTER_LINKDATA
+{ "movedlnk", { 0, 0 } }, //POINTER_MOVEDATALINK
+{ "copydlnk", { 0, 0 } }, //POINTER_COPYDATALINK
+{ "movef", { 8, 8 } }, //POINTER_MOVEFILE
+{ "copyf", { 8, 8 } }, //POINTER_COPYFILE
+{ "linkf", { 8, 8 } }, //POINTER_LINKFILE
+{ "moveflnk", { 8, 8 } }, //POINTER_MOVEFILELINK
+{ "copyflnk", { 8, 8 } }, //POINTER_COPYFILELINK
+{ "movef2", { 7, 8 } }, //POINTER_MOVEFILES
+{ "copyf2", { 7, 8 } }, //POINTER_COPYFILES
+{ "notallow", { 15, 15 } }, //POINTER_NOTALLOWED
+{ "dline", { 8, 8 } }, //POINTER_DRAW_LINE
+{ "drect", { 8, 8 } }, //POINTER_DRAW_RECT
+{ "dpolygon", { 8, 8 } }, //POINTER_DRAW_POLYGON
+{ "dbezier", { 8, 8 } }, //POINTER_DRAW_BEZIER
+{ "darc", { 8, 8 } }, //POINTER_DRAW_ARC
+{ "dpie", { 8, 8 } }, //POINTER_DRAW_PIE
+{ "dcirccut", { 8, 8 } }, //POINTER_DRAW_CIRCLECUT
+{ "dellipse", { 8, 8 } }, //POINTER_DRAW_ELLIPSE
+{ "dfree", { 8, 8 } }, //POINTER_DRAW_FREEHAND
+{ "dconnect", { 8, 8 } }, //POINTER_DRAW_CONNECT
+{ "dtext", { 8, 8 } }, //POINTER_DRAW_TEXT
+{ "dcapt", { 8, 8 } }, //POINTER_DRAW_CAPTION
+{ "chart", { 15, 16 } }, //POINTER_CHART
+{ "detectiv", { 12, 13 } }, //POINTER_DETECTIVE
+{ "pivotcol", { 7, 5 } }, //POINTER_PIVOT_COL
+{ "pivotrow", { 8, 7 } }, //POINTER_PIVOT_ROW
+{ "pivotfld", { 8, 7 } }, //POINTER_PIVOT_FIELD
+{ "chain", { 0, 2 } }, //POINTER_CHAIN
+{ "chainnot", { 2, 2 } }, //POINTER_CHAIN_NOTALLOWED
+{ "timemove", { 16, 16 } }, //POINTER_TIMEEVENT_MOVE
+{ "timesize", { 16, 17 } }, //POINTER_TIMEEVENT_SIZE
+{ "asn", { 16, 12 } }, //POINTER_AUTOSCROLL_N
+{ "ass", { 15, 19 } }, //POINTER_AUTOSCROLL_S
+{ "asw", { 12, 15 } }, //POINTER_AUTOSCROLL_W
+{ "ase", { 19, 16 } }, //POINTER_AUTOSCROLL_E
+{ "asnw", { 10, 10 } }, //POINTER_AUTOSCROLL_NW
+{ "asne", { 21, 10 } }, //POINTER_AUTOSCROLL_NE
+{ "assw", { 21, 21 } }, //POINTER_AUTOSCROLL_SW
+{ "asse", { 21, 21 } }, //POINTER_AUTOSCROLL_SE
+{ "asns", { 15, 15 } }, //POINTER_AUTOSCROLL_NS
+{ "aswe", { 15, 15 } }, //POINTER_AUTOSCROLL_WE
+{ "asnswe", { 15, 15 } }, //POINTER_AUTOSCROLL_NSWE
+{ "airbrush", { 5, 22 } }, //POINTER_AIRBRUSH
+{ "vtext", { 15, 15 } }, //POINTER_TEXT_VERTICAL
+{ "pivotdel", { 18, 15 } }, //POINTER_PIVOT_DELETE
+{ "tblsels", { 15, 30 } }, //POINTER_TAB_SELECT_S
+{ "tblsele", { 30, 16 } }, //POINTER_TAB_SELECT_E
+{ "tblselse", { 30, 30 } }, //POINTER_TAB_SELECT_SE
+{ "tblselw", { 1, 16 } }, //POINTER_TAB_SELECT_W
+{ "tblselsw", { 1, 30 } }, //POINTER_TAB_SELECT_SW
+{ "pntbrsh", { 9, 16 } } //POINTER_PAINTBRUSH
+};
+
+NSCursor* SalData::getCursor( PointerStyle i_eStyle )
+{
+ if( i_eStyle >= POINTER_COUNT )
+ return nil;
+
+ NSCursor* pCurs = maCursors[ i_eStyle ];
+ if( pCurs == INVALID_CURSOR_PTR )
+ {
+ pCurs = nil;
+ if( aCursorTab[ i_eStyle ].pBaseName )
+ {
+ NSPoint aHotSpot = aCursorTab[ i_eStyle ].aHotSpot;
+ CFStringRef pCursorName =
+ CFStringCreateWithCStringNoCopy(
+ kCFAllocatorDefault,
+ aCursorTab[ i_eStyle ].pBaseName,
+ kCFStringEncodingASCII,
+ kCFAllocatorNull );
+ CFBundleRef hMain = CFBundleGetMainBundle();
+ CFURLRef hURL = CFBundleCopyResourceURL( hMain, pCursorName, CFSTR("png"), CFSTR("cursors") );
+ if( hURL )
+ {
+ pCurs = [[NSCursor alloc] initWithImage: [[NSImage alloc] initWithContentsOfURL: (NSURL*)hURL] hotSpot: aHotSpot];
+ CFRelease( hURL );
+ }
+ CFRelease( pCursorName );
+ }
+ maCursors[ i_eStyle ] = pCurs;
+ }
+ return pCurs;
+}
+
+NSStatusItem* SalData::getStatusItem()
+{
+ SalData* pData = GetSalData();
+ if( ! pData->mpStatusItem )
+ {
+ NSStatusBar* pStatBar =[NSStatusBar systemStatusBar];
+ if( pStatBar )
+ {
+ pData->mpStatusItem = [pStatBar statusItemWithLength: NSVariableStatusItemLength];
+ [pData->mpStatusItem retain];
+ OOStatusItemView* pView = [[OOStatusItemView alloc] init];
+ [pData->mpStatusItem setView: pView ];
+ [pView display];
+ }
+ }
+ return pData->mpStatusItem;
+}
diff --git a/vcl/aqua/source/app/salinst.cxx b/vcl/aqua/source/app/salinst.cxx
new file mode 100644
index 000000000000..b8a2261ed9db
--- /dev/null
+++ b/vcl/aqua/source/app/salinst.cxx
@@ -0,0 +1,1313 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+
+#include "tools/fsys.hxx"
+#include "tools/getprocessworkingdir.hxx"
+#include "osl/process.h"
+#include "rtl/ustrbuf.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/print.h"
+#include "vcl/salimestatus.hxx"
+#include "vcl/window.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/impbmp.hxx"
+
+#include "saldata.hxx"
+#include "salinst.h"
+#include "salframe.h"
+#include "salobj.h"
+#include "salsys.h"
+#include "salvd.h"
+#include "salbmp.h"
+#include "salprn.h"
+#include "saltimer.h"
+#include "vclnsapp.h"
+
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
+#include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include "premac.h"
+#include <Foundation/Foundation.h>
+#include <ApplicationServices/ApplicationServices.h>
+#import "apple_remote/RemoteMainController.h"
+#include "apple_remote/RemoteControl.h"
+#include "postmac.h"
+#include <tools/solarmutex.hxx>
+
+using namespace std;
+using namespace ::com::sun::star;
+
+extern BOOL ImplSVMain();
+
+static BOOL* gpbInit = 0;
+static NSMenu* pDockMenu = nil;
+static bool bNoSVMain = true;
+static bool bLeftMain = false;
+// -----------------------------------------------------------------------
+
+class AquaDelayedSettingsChanged : public Timer
+{
+ bool mbInvalidate;
+ public:
+ AquaDelayedSettingsChanged( bool bInvalidate ) :
+ mbInvalidate( bInvalidate )
+ {
+ }
+
+ virtual void Timeout()
+ {
+ SalData* pSalData = GetSalData();
+ if( ! pSalData->maFrames.empty() )
+ pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
+
+ if( mbInvalidate )
+ {
+ for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
+ it != pSalData->maFrames.end(); ++it )
+ {
+ if( (*it)->mbShown )
+ (*it)->SendPaintEvent( NULL );
+ }
+ }
+ Stop();
+ delete this;
+ }
+};
+
+void AquaSalInstance::delayedSettingsChanged( bool bInvalidate )
+{
+ vos::OGuard aGuard( *mpSalYieldMutex );
+ AquaDelayedSettingsChanged* pTimer = new AquaDelayedSettingsChanged( bInvalidate );
+ pTimer->SetTimeout( 50 );
+ pTimer->Start();
+}
+
+
+// the AppEventList must be available before any SalData/SalInst/etc. objects are ready
+typedef std::list<const ApplicationEvent*> AppEventList;
+AppEventList AquaSalInstance::aAppEventList;
+
+NSMenu* AquaSalInstance::GetDynamicDockMenu()
+{
+ if( ! pDockMenu && ! bLeftMain )
+ pDockMenu = [[NSMenu alloc] initWithTitle: @""];
+ return pDockMenu;
+}
+
+bool AquaSalInstance::isOnCommandLine( const rtl::OUString& rArg )
+{
+ sal_uInt32 nArgs = osl_getCommandArgCount();
+ for( sal_uInt32 i = 0; i < nArgs; i++ )
+ {
+ rtl::OUString aArg;
+ osl_getCommandArg( i, &aArg.pData );
+ if( aArg.equals( rArg ) )
+ return true;
+ }
+ return false;
+}
+
+
+// initialize the cocoa VCL_NSApplication object
+// returns an NSAutoreleasePool that must be released when the event loop begins
+static void initNSApp()
+{
+ // create our cocoa NSApplication
+ [VCL_NSApplication sharedApplication];
+
+ SalData::ensureThreadAutoreleasePool();
+
+ // put cocoa into multithreaded mode
+ [NSThread detachNewThreadSelector:@selector(enableCocoaThreads:) toTarget:[[CocoaThreadEnabler alloc] init] withObject:nil];
+
+ // activate our delegate methods
+ [NSApp setDelegate: NSApp];
+
+ [[NSNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(systemColorsChanged:)
+ name: NSSystemColorsDidChangeNotification
+ object: nil ];
+ [[NSNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(screenParametersChanged:)
+ name: NSApplicationDidChangeScreenParametersNotification
+ object: nil ];
+ // add observers for some settings changes that affect vcl's settings
+ // scrollbar variant
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(scrollbarVariantChanged:)
+ name: @"AppleAquaScrollBarVariantChanged"
+ object: nil ];
+ // scrollbar page behavior ("jump to here" or not)
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(scrollbarSettingsChanged:)
+ name: @"AppleNoRedisplayAppearancePreferenceChanged"
+ object: nil ];
+
+ // get System Version and store the value in GetSalData()->mnSystemVersion
+ OSErr err = noErr;
+ SInt32 systemVersion = VER_TIGER; // Initialize with minimal requirement
+ if( (err = Gestalt(gestaltSystemVersion, &systemVersion)) == noErr )
+ {
+ GetSalData()->mnSystemVersion = systemVersion;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "System Version %x\n", (unsigned int)systemVersion);
+#endif
+ }
+ else
+ NSLog(@"Unable to obtain system version: %ld", (long)err);
+
+ // Initialize Apple Remote
+ GetSalData()->mpMainController = [[MainController alloc] init];
+
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(applicationWillBecomeActive:)
+ name: @"AppleRemoteWillBecomeActive"
+ object: nil ];
+
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(applicationWillResignActive:)
+ name: @"AppleRemoteWillResignActive"
+ object: nil ];
+
+ if( ImplGetSVData()->mbIsTestTool )
+ [NSApp activateIgnoringOtherApps: YES];
+}
+
+BOOL ImplSVMainHook( BOOL * pbInit )
+{
+ gpbInit = pbInit;
+
+ bNoSVMain = false;
+ initNSApp();
+
+ NSPoint aPt = { 0, 0 };
+ NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
+ location: aPt
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: 0
+ context: nil
+ subtype: AquaSalInstance::AppExecuteSVMain
+ data1: 0
+ data2: 0 ];
+ if( pEvent )
+ {
+ [NSApp postEvent: pEvent atStart: NO];
+
+ rtl::OUString aExeURL, aExe;
+ osl_getExecutableFile( &aExeURL.pData );
+ osl_getSystemPathFromFileURL( aExeURL.pData, &aExe.pData );
+ rtl::OString aByteExe( rtl::OUStringToOString( aExe, osl_getThreadTextEncoding() ) );
+
+#ifdef DEBUG
+ aByteExe += OString ( " NSAccessibilityDebugLogLevel 1" );
+ const char* pArgv[] = { aByteExe.getStr(), NULL };
+ NSApplicationMain( 3, pArgv );
+#else
+ const char* pArgv[] = { aByteExe.getStr(), NULL };
+ NSApplicationMain( 1, pArgv );
+#endif
+ }
+ else
+ {
+ DBG_ERROR( "NSApplication initialization could not be done" );
+ }
+
+ return TRUE; // indicate that ImplSVMainHook is implemented
+}
+
+// =======================================================================
+
+void SalAbort( const XubString& rErrorText )
+{
+ if( !rErrorText.Len() )
+ fprintf( stderr, "Application Error " );
+ else
+ fprintf( stderr, "%s ",
+ ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
+ abort();
+}
+
+// -----------------------------------------------------------------------
+
+void InitSalData()
+{
+ SalData *pSalData = new SalData;
+ SetSalData( pSalData );
+}
+
+// -----------------------------------------------------------------------
+
+const ::rtl::OUString& SalGetDesktopEnvironment()
+{
+ static OUString aDesktopEnvironment(RTL_CONSTASCII_USTRINGPARAM( "MacOSX" ));
+ return aDesktopEnvironment;
+}
+
+// -----------------------------------------------------------------------
+
+void DeInitSalData()
+{
+ SalData *pSalData = GetSalData();
+ if( pSalData->mpStatusItem )
+ {
+ [pSalData->mpStatusItem release];
+ pSalData->mpStatusItem = nil;
+ }
+ delete pSalData;
+ SetSalData( NULL );
+}
+
+// -----------------------------------------------------------------------
+
+extern "C" {
+#include <crt_externs.h>
+}
+
+// -----------------------------------------------------------------------
+
+void InitSalMain()
+{
+ rtl::OUString urlWorkDir;
+ rtl_uString *sysWorkDir = NULL;
+ if (tools::getProcessWorkingDir(&urlWorkDir))
+ {
+ oslFileError err2 = osl_getSystemPathFromFileURL(urlWorkDir.pData, &sysWorkDir);
+ if (err2 == osl_File_E_None)
+ {
+ ByteString aPath( getenv( "PATH" ) );
+ ByteString aResPath( getenv( "STAR_RESOURCEPATH" ) );
+ ByteString aLibPath( getenv( "DYLD_LIBRARY_PATH" ) );
+ ByteString aCmdPath( OUStringToOString(OUString(sysWorkDir), RTL_TEXTENCODING_UTF8).getStr() );
+ ByteString aTmpPath;
+ // Get absolute path of command's directory
+ if ( aCmdPath.Len() ) {
+ DirEntry aCmdDirEntry( aCmdPath );
+ aCmdDirEntry.ToAbs();
+ aCmdPath = ByteString( aCmdDirEntry.GetPath().GetFull(), RTL_TEXTENCODING_ASCII_US );
+ }
+ // Assign to PATH environment variable
+ if ( aCmdPath.Len() )
+ {
+ aTmpPath = ByteString( "PATH=" );
+ aTmpPath += aCmdPath;
+ if ( aPath.Len() )
+ aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
+ aTmpPath += aPath;
+ putenv( (char*)aTmpPath.GetBuffer() );
+ }
+ // Assign to STAR_RESOURCEPATH environment variable
+ if ( aCmdPath.Len() )
+ {
+ aTmpPath = ByteString( "STAR_RESOURCEPATH=" );
+ aTmpPath += aCmdPath;
+ if ( aResPath.Len() )
+ aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
+ aTmpPath += aResPath;
+ putenv( (char*)aTmpPath.GetBuffer() );
+ }
+ // Assign to DYLD_LIBRARY_PATH environment variable
+ if ( aCmdPath.Len() )
+ {
+ aTmpPath = ByteString( "DYLD_LIBRARY_PATH=" );
+ aTmpPath += aCmdPath;
+ if ( aLibPath.Len() )
+ aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
+ aTmpPath += aLibPath;
+ putenv( (char*)aTmpPath.GetBuffer() );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DeInitSalMain()
+{
+}
+
+// =======================================================================
+
+SalYieldMutex::SalYieldMutex()
+{
+ mnCount = 0;
+ mnThreadId = 0;
+}
+
+void SalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+}
+
+void SalYieldMutex::release()
+{
+ if ( mnThreadId == NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ }
+ OMutex::release();
+}
+
+sal_Bool SalYieldMutex::tryToAcquire()
+{
+ if ( OMutex::tryToAcquire() )
+ {
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+// some convenience functions regarding the yield mutex, aka solar mutex
+
+BOOL ImplSalYieldMutexTryToAcquire()
+{
+ AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
+ if ( pInst )
+ return pInst->mpSalYieldMutex->tryToAcquire();
+ else
+ return FALSE;
+}
+
+void ImplSalYieldMutexAcquire()
+{
+ AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->acquire();
+}
+
+void ImplSalYieldMutexRelease()
+{
+ AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->release();
+}
+
+// =======================================================================
+
+SalInstance* CreateSalInstance()
+{
+ // this is the case for not using SVMain
+ // not so good
+ if( bNoSVMain )
+ initNSApp();
+
+ SalData* pSalData = GetSalData();
+ DBG_ASSERT( pSalData->mpFirstInstance == NULL, "more than one instance created" );
+ AquaSalInstance* pInst = new AquaSalInstance;
+
+ // init instance (only one instance in this version !!!)
+ pSalData->mpFirstInstance = pInst;
+ // this one is for outside AquaSalInstance::Yield
+ SalData::ensureThreadAutoreleasePool();
+ // no focus rects on NWF aqua
+ ImplGetSVData()->maNWFData.mbNoFocusRects = true;
+ ImplGetSVData()->maNWFData.mbNoBoldTabFocus = true;
+ ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise = true;
+ ImplGetSVData()->maNWFData.mbCenteredTabs = true;
+ ImplGetSVData()->maNWFData.mbProgressNeedsErase = true;
+ ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase = true;
+ ImplGetSVData()->maGDIData.mbPrinterPullModel = true;
+ ImplGetSVData()->maGDIData.mbNoXORClipping = true;
+ ImplGetSVData()->maWinData.mbNoSaveBackground = true;
+
+ return pInst;
+}
+
+// -----------------------------------------------------------------------
+
+void DestroySalInstance( SalInstance* pInst )
+{
+ delete pInst;
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalInstance::AquaSalInstance()
+{
+ mpSalYieldMutex = new SalYieldMutex;
+ mpSalYieldMutex->acquire();
+ ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
+ maMainThread = vos::OThread::getCurrentIdentifier();
+ mbWaitingYield = false;
+ maUserEventListMutex = osl_createMutex();
+ mnActivePrintJobs = 0;
+ maWaitingYieldCond = osl_createCondition();
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalInstance::~AquaSalInstance()
+{
+ ::tools::SolarMutex::SetSolarMutex( 0 );
+ mpSalYieldMutex->release();
+ delete mpSalYieldMutex;
+ osl_destroyMutex( maUserEventListMutex );
+ osl_destroyCondition( maWaitingYieldCond );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::wakeupYield()
+{
+ // wakeup :Yield
+ if( mbWaitingYield )
+ {
+ SalData::ensureThreadAutoreleasePool();
+ NSPoint aPt = { 0, 0 };
+ NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
+ location: aPt
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: 0
+ context: nil
+ subtype: AquaSalInstance::YieldWakeupEvent
+ data1: 0
+ data2: 0 ];
+ if( pEvent )
+ [NSApp postEvent: pEvent atStart: NO];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, USHORT nType, void* pData )
+{
+ osl_acquireMutex( maUserEventListMutex );
+ maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) );
+ osl_releaseMutex( maUserEventListMutex );
+
+ // notify main loop that an event has arrived
+ wakeupYield();
+}
+
+// -----------------------------------------------------------------------
+
+vos::IMutex* AquaSalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalInstance::ReleaseYieldMutex()
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ if ( pYieldMutex->GetThreadId() ==
+ NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ ULONG nCount = pYieldMutex->GetAcquireCount();
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::AcquireYieldMutex( ULONG nCount )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalInstance::isNSAppThread() const
+{
+ return vos::OThread::getCurrentIdentifier() == maMainThread;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent )
+{
+ switch( [pEvent subtype] )
+ {
+ case AppStartTimerEvent:
+ AquaSalTimer::handleStartTimerEvent( pEvent );
+ break;
+ case AppEndLoopEvent:
+ [NSApp stop: NSApp];
+ break;
+ case AppExecuteSVMain:
+ {
+ BOOL bResult = ImplSVMain();
+ if( gpbInit )
+ *gpbInit = bResult;
+ [NSApp stop: NSApp];
+ bLeftMain = true;
+ if( pDockMenu )
+ {
+ [pDockMenu release];
+ pDockMenu = nil;
+ }
+ }
+ break;
+ case AppleRemoteEvent:
+ {
+ sal_Int16 nCommand = 0;
+ SalData* pSalData = GetSalData();
+ bool bIsFullScreenMode = false;
+
+ std::list<AquaSalFrame*>::iterator it = pSalData->maFrames.begin();
+ while( (*it) && ( (it != pSalData->maFrames.end() ) || ( (*it)->mbFullScreen == false ) ) )
+ {
+ if ( ((*it)->mbFullScreen == true) )
+ bIsFullScreenMode = true;
+ it++;
+ }
+
+ switch ([pEvent data1])
+ {
+ case kRemoteButtonPlay:
+ nCommand = ( bIsFullScreenMode == true ) ? MEDIA_COMMAND_PLAY_PAUSE : MEDIA_COMMAND_PLAY;
+ break;
+
+ // kept for experimentation purpose (scheduled for future implementation)
+ // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break;
+
+ case kRemoteButtonPlus: nCommand = MEDIA_COMMAND_VOLUME_UP; break;
+
+ case kRemoteButtonMinus: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break;
+
+ case kRemoteButtonRight: nCommand = MEDIA_COMMAND_NEXTTRACK; break;
+
+ case kRemoteButtonRight_Hold: nCommand = MEDIA_COMMAND_NEXTTRACK_HOLD; break;
+
+ case kRemoteButtonLeft: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break;
+
+ case kRemoteButtonLeft_Hold: nCommand = MEDIA_COMMAND_REWIND; break;
+
+ case kRemoteButtonPlay_Hold: nCommand = MEDIA_COMMAND_PLAY_HOLD; break;
+
+ case kRemoteButtonMenu_Hold: nCommand = MEDIA_COMMAND_STOP; break;
+
+ // FIXME : not detected
+ case kRemoteButtonPlus_Hold:
+ case kRemoteButtonMinus_Hold:
+ break;
+
+ default:
+ break;
+ }
+ AquaSalFrame* pFrame = pSalData->maFrames.front();
+ Window * pWindow = pFrame->GetWindow() ? pSalData->maFrames.front()->GetWindow() : NULL;
+
+ if( pWindow )
+ {
+ const Point aPoint;
+ CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand );
+ NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
+
+ if ( !ImplCallPreNotify( aNCmdEvt ) )
+ pWindow->Command( aCEvt );
+ }
+
+ }
+ break;
+
+ case YieldWakeupEvent:
+ // do nothing, fall out of Yield
+ break;
+
+ default:
+ DBG_ERROR( "unhandled NSApplicationDefined event" );
+ break;
+ };
+}
+
+// -----------------------------------------------------------------------
+
+class ReleasePoolHolder
+{
+ NSAutoreleasePool* mpPool;
+ public:
+ ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {}
+ ~ReleasePoolHolder() { [mpPool release]; }
+};
+
+void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ // ensure that the per thread autorelease pool is top level and
+ // will therefore not be destroyed by cocoa implicitly
+ SalData::ensureThreadAutoreleasePool();
+
+ // NSAutoreleasePool documentation suggests we should have
+ // an own pool for each yield level
+ ReleasePoolHolder aReleasePool;
+
+ // Release all locks so that we don't deadlock when we pull pending
+ // events from the event queue
+ bool bDispatchUser = true;
+ while( bDispatchUser )
+ {
+ ULONG nCount = ReleaseYieldMutex();
+
+ // get one user event
+ osl_acquireMutex( maUserEventListMutex );
+ SalUserEvent aEvent( NULL, NULL, 0 );
+ if( ! maUserEvents.empty() )
+ {
+ aEvent = maUserEvents.front();
+ maUserEvents.pop_front();
+ }
+ else
+ bDispatchUser = false;
+ osl_releaseMutex( maUserEventListMutex );
+
+ AcquireYieldMutex( nCount );
+
+ // dispatch it
+ if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) )
+ {
+ aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData );
+ osl_setCondition( maWaitingYieldCond );
+ // return if only one event is asked for
+ if( ! bHandleAllCurrentEvents )
+ return;
+ }
+ }
+
+ // handle cocoa event queue
+ // cocoa events mye be only handled in the thread the NSApp was created
+ if( isNSAppThread() && mnActivePrintJobs == 0 )
+ {
+ // we need to be woken up by a cocoa-event
+ // if a user event should be posted by the event handling below
+ bool bOldWaitingYield = mbWaitingYield;
+ mbWaitingYield = bWait;
+
+ // handle available events
+ NSEvent* pEvent = nil;
+ bool bHadEvent = false;
+ do
+ {
+ ULONG nCount = ReleaseYieldMutex();
+
+ pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil
+ inMode: NSDefaultRunLoopMode dequeue: YES];
+ if( pEvent )
+ {
+ [NSApp sendEvent: pEvent];
+ bHadEvent = true;
+ }
+ [NSApp updateWindows];
+
+ AcquireYieldMutex( nCount );
+ } while( bHandleAllCurrentEvents && pEvent );
+
+ // if we had no event yet, wait for one if requested
+ if( bWait && ! bHadEvent )
+ {
+ ULONG nCount = ReleaseYieldMutex();
+
+ NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture];
+ pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt
+ inMode: NSDefaultRunLoopMode dequeue: YES];
+ if( pEvent )
+ [NSApp sendEvent: pEvent];
+ [NSApp updateWindows];
+
+ AcquireYieldMutex( nCount );
+
+ // #i86581#
+ // FIXME: sometimes the NSTimer will never fire. Firing it by hand then
+ // fixes the problem even seems to set the correct next firing date
+ // Why oh why ?
+ if( ! pEvent && AquaSalTimer::pRunningTimer )
+ {
+ // this cause crashes on MacOSX 10.4
+ // [AquaSalTimer::pRunningTimer fire];
+ ImplGetSVData()->mpSalTimer->CallCallback();
+ }
+ }
+
+ mbWaitingYield = bOldWaitingYield;
+
+ // collect update rectangles
+ const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames );
+ for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() )
+ {
+ (*it)->Flush( (*it)->maInvalidRect );
+ (*it)->maInvalidRect.SetEmpty();
+ }
+ }
+ osl_setCondition( maWaitingYieldCond );
+ }
+ else if( bWait )
+ {
+ // #i103162#
+ // wait until any thread (most likely the main thread)
+ // has dispatched an event, cop out at 200 ms
+ osl_resetCondition( maWaitingYieldCond );
+ TimeValue aVal = { 0, 200000000 };
+ ULONG nCount = ReleaseYieldMutex();
+ osl_waitCondition( maWaitingYieldCond, &aVal );
+ AcquireYieldMutex( nCount );
+ }
+
+ // we get some apple events way too early
+ // before the application is ready to handle them,
+ // so their corresponding application events need to be delayed
+ // now is a good time to handle at least one of them
+ if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute )
+ {
+ // make sure that only one application event is active at a time
+ static bool bInAppEvent = false;
+ if( !bInAppEvent )
+ {
+ bInAppEvent = true;
+ // get the next delayed application event
+ const ApplicationEvent* pAppEvent = aAppEventList.front();
+ aAppEventList.pop_front();
+ // handle one application event (no recursion)
+ const ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpApp->AppEvent( *pAppEvent );
+ delete pAppEvent;
+ // allow the next delayed application event
+ bInAppEvent = false;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalInstance::AnyInput( USHORT nType )
+{
+ if( nType & INPUT_APPEVENT )
+ {
+ if( ! aAppEventList.empty() )
+ return true;
+ if( nType == INPUT_APPEVENT )
+ return false;
+ }
+
+ if( nType & INPUT_TIMER )
+ {
+ if( AquaSalTimer::pRunningTimer )
+ {
+ NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate];
+ if( pDt && [pDt timeIntervalSinceNow] < 0 )
+ {
+ return true;
+ }
+ }
+ }
+
+ unsigned/*NSUInteger*/ nEventMask = 0;
+ if( nType & INPUT_MOUSE)
+ nEventMask |=
+ NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask |
+ NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask |
+ NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask |
+ NSScrollWheelMask |
+ // NSMouseMovedMask |
+ NSMouseEnteredMask | NSMouseExitedMask;
+ if( nType & INPUT_KEYBOARD)
+ nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask;
+ if( nType & INPUT_OTHER)
+ nEventMask |= NSTabletPoint;
+ // TODO: INPUT_PAINT / more INPUT_OTHER
+ if( !nType)
+ return false;
+
+ NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil
+ inMode: NSDefaultRunLoopMode dequeue: NO];
+ return (pEvent != NULL);
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, ULONG nSalFrameStyle )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, ULONG nSalFrameStyle )
+{
+ SalData::ensureThreadAutoreleasePool();
+
+ SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle );
+ return pFrame;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ delete pFrame;
+}
+
+// -----------------------------------------------------------------------
+
+SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, BOOL /* bShow */ )
+{
+ // SystemWindowData is meaningless on Mac OS X
+ AquaSalObject *pObject = NULL;
+
+ if ( pParent )
+ pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) );
+
+ return pObject;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyObject( SalObject* pObject )
+{
+ delete ( pObject );
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ NSArray* pNames = [NSPrinter printerNames];
+ NSArray* pTypes = [NSPrinter printerTypes];
+ unsigned int nNameCount = pNames ? [pNames count] : 0;
+ unsigned int nTypeCount = pTypes ? [pTypes count] : 0;
+ DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" );
+ for( unsigned int i = 0; i < nNameCount; i++ )
+ {
+ NSString* pName = [pNames objectAtIndex: i];
+ NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil;
+ if( pName )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = GetOUString( pName );
+ if( pType )
+ pInfo->maDriver = GetOUString( pType );
+ pInfo->mnStatus = 0;
+ pInfo->mnJobs = 0;
+ pInfo->mpSysData = NULL;
+
+ pList->Add( pInfo );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalInstance::GetDefaultPrinter()
+{
+ if( ! maDefaultPrinter.getLength() )
+ {
+ NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo];
+ DBG_ASSERT( pPI, "no print info" );
+ if( pPI )
+ {
+ NSPrinter* pPr = [pPI printer];
+ DBG_ASSERT( pPr, "no printer in default info" );
+ if( pPr )
+ {
+ NSString* pDefName = [pPr name];
+ DBG_ASSERT( pDefName, "printer has no name" );
+ maDefaultPrinter = GetOUString( pDefName );
+ }
+ }
+ }
+ return maDefaultPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData )
+{
+ SalInfoPrinter* pNewInfoPrinter = NULL;
+ if( pQueueInfo )
+ {
+ pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo );
+ if( pSetupData )
+ pNewInfoPrinter->SetPrinterData( pSetupData );
+ }
+
+ return pNewInfoPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalSystem* AquaSalInstance::CreateSystem()
+{
+ return new AquaSalSystem();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroySystem( SalSystem* pSystem )
+{
+ delete pSystem;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::SetEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::SetErrorEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ rReturnedBytes = 1;
+ rReturnedType = AsciiCString;
+ return (void*)"";
+}
+
+// We need to re-encode file urls because osl_getFileURLFromSystemPath converts
+// to UTF-8 before encoding non ascii characters, which is not what other apps expect.
+static rtl::OUString translateToExternalUrl(const rtl::OUString& internalUrl)
+{
+ rtl::OUString extUrl;
+
+ uno::Reference< lang::XMultiServiceFactory > sm = comphelper::getProcessServiceFactory();
+ if (sm.is())
+ {
+ uno::Reference< beans::XPropertySet > pset;
+ sm->queryInterface( getCppuType( &pset )) >>= pset;
+ if (pset.is())
+ {
+ uno::Reference< uno::XComponentContext > context;
+ static const rtl::OUString DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) );
+ pset->getPropertyValue(DEFAULT_CONTEXT) >>= context;
+ if (context.is())
+ extUrl = uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl);
+ }
+ }
+ return extUrl;
+}
+
+// #i104525# many versions of OSX have problems with some URLs:
+// when an app requests OSX to add one of these URLs to the "Recent Items" list
+// then this app gets killed (TextEdit, Preview, etc. and also OOo)
+static bool isDangerousUrl( const rtl::OUString& rUrl )
+{
+ // use a heuristic that detects all known cases since there is no official comment
+ // on the exact impact and root cause of the OSX bug
+ const int nLen = rUrl.getLength();
+ const sal_Unicode* p = rUrl.getStr();
+ for( int i = 0; i < nLen-3; ++i, ++p ) {
+ if( p[0] != '%' )
+ continue;
+ // escaped percent?
+ if( (p[1] == '2') && (p[2] == '5') )
+ return true;
+ // escapes are considered to be UTF-8 encoded
+ // => check for invalid UTF-8 leading byte
+ if( (p[1] != 'f') && (p[1] != 'F') )
+ continue;
+ int cLowNibble = p[2];
+ if( (cLowNibble >= '0' ) && (cLowNibble <= '9'))
+ return false;
+ if( cLowNibble >= 'a' )
+ cLowNibble -= 'a' - 'A';
+ if( (cLowNibble < 'A') || (cLowNibble >= 'C'))
+ return true;
+ }
+
+ return false;
+}
+
+void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/)
+{
+ // Convert file URL for external use (see above)
+ rtl::OUString externalUrl = translateToExternalUrl(rFileUrl);
+ if( 0 == externalUrl.getLength() )
+ externalUrl = rFileUrl;
+
+ if( externalUrl.getLength() && !isDangerousUrl( externalUrl ) )
+ {
+ NSString* pString = CreateNSString( externalUrl );
+ NSURL* pURL = [NSURL URLWithString: pString];
+
+ if( pURL )
+ {
+ NSDocumentController* pCtrl = [NSDocumentController sharedDocumentController];
+ [pCtrl noteNewRecentDocumentURL: pURL];
+ }
+ if( pString )
+ [pString release];
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+SalTimer* AquaSalInstance::CreateSalTimer()
+{
+ return new AquaSalTimer();
+}
+
+// -----------------------------------------------------------------------
+
+SalSystem* AquaSalInstance::CreateSalSystem()
+{
+ return new AquaSalSystem();
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* AquaSalInstance::CreateSalBitmap()
+{
+ return new AquaSalBitmap();
+}
+
+// -----------------------------------------------------------------------
+
+SalSession* AquaSalInstance::CreateSalSession()
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+class MacImeStatus : public SalI18NImeStatus
+{
+public:
+ MacImeStatus() {}
+ virtual ~MacImeStatus() {}
+
+ // asks whether there is a status window available
+ // to toggle into menubar
+ virtual bool canToggle() { return false; }
+ virtual void toggle() {}
+};
+
+// -----------------------------------------------------------------------
+
+SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus()
+{
+ return new MacImeStatus();
+}
+
+// YieldMutexReleaser
+YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
+{
+ SalData* pSalData = GetSalData();
+ if( ! pSalData->mpFirstInstance->isNSAppThread() )
+ {
+ SalData::ensureThreadAutoreleasePool();
+ mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex();
+ }
+}
+
+YieldMutexReleaser::~YieldMutexReleaser()
+{
+ if( mnCount != 0 )
+ GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount );
+}
+
+//////////////////////////////////////////////////////////////
+rtl::OUString GetOUString( CFStringRef rStr )
+{
+ if( rStr == 0 )
+ return rtl::OUString();
+ CFIndex nLength = CFStringGetLength( rStr );
+ if( nLength == 0 )
+ return rtl::OUString();
+ const UniChar* pConstStr = CFStringGetCharactersPtr( rStr );
+ if( pConstStr )
+ return rtl::OUString( pConstStr, nLength );
+ UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) );
+ CFRange aRange = { 0, nLength };
+ CFStringGetCharacters( rStr, aRange, pStr );
+ rtl::OUString aRet( pStr, nLength );
+ rtl_freeMemory( pStr );
+ return aRet;
+}
+
+rtl::OUString GetOUString( NSString* pStr )
+{
+ if( ! pStr )
+ return rtl::OUString();
+ int nLen = [pStr length];
+ if( nLen == 0 )
+ return rtl::OUString();
+
+ rtl::OUStringBuffer aBuf( nLen+1 );
+ aBuf.setLength( nLen );
+ [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())];
+ return aBuf.makeStringAndClear();
+}
+
+CFStringRef CreateCFString( const rtl::OUString& rStr )
+{
+ return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() );
+}
+
+NSString* CreateNSString( const rtl::OUString& rStr )
+{
+ return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()];
+}
+
+CGImageRef CreateCGImage( const Image& rImage )
+{
+ BitmapEx aBmpEx( rImage.GetBitmapEx() );
+ Bitmap aBmp( aBmpEx.GetBitmap() );
+
+ if( ! aBmp || ! aBmp.ImplGetImpBitmap() )
+ return NULL;
+
+ // simple case, no transparency
+ AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap());
+
+ if( ! pSalBmp )
+ return NULL;
+
+ CGImageRef xImage = NULL;
+ if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) )
+ xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ else if( aBmpEx.IsAlpha() )
+ {
+ AlphaMask aAlphaMask( aBmpEx.GetAlpha() );
+ Bitmap aMask( aAlphaMask.GetBitmap() );
+ AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
+ if( pMaskBmp )
+ xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ else
+ xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ }
+ else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP )
+ {
+ Bitmap aMask( aBmpEx.GetMask() );
+ AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
+ if( pMaskBmp )
+ xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ else
+ xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ }
+ else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR )
+ {
+ Color aTransColor( aBmpEx.GetTransparentColor() );
+ SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() );
+ xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor );
+ }
+
+ return xImage;
+}
+
+NSImage* CreateNSImage( const Image& rImage )
+{
+ CGImageRef xImage = CreateCGImage( rImage );
+
+ if( ! xImage )
+ return nil;
+
+ Size aSize( rImage.GetSizePixel() );
+ NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )];
+ if( pImage )
+ {
+ [pImage setFlipped: YES];
+ [pImage lockFocus];
+
+ NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
+ CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
+
+ const CGRect aDstRect = { {0, 0}, { aSize.Width(), aSize.Height() } };
+ CGContextDrawImage( rCGContext, aDstRect, xImage );
+
+ [pImage unlockFocus];
+ }
+
+ CGImageRelease( xImage );
+
+ return pImage;
+}
diff --git a/vcl/aqua/source/app/salnstimer.mm b/vcl/aqua/source/app/salnstimer.mm
new file mode 100755
index 000000000000..73e49fd99c61
--- /dev/null
+++ b/vcl/aqua/source/app/salnstimer.mm
@@ -0,0 +1,56 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "saltimer.h"
+#include "salnstimer.h"
+#include "salinst.h"
+#include "saldata.hxx"
+
+#include "vcl/svdata.hxx"
+
+@implementation TimerCallbackCaller
+-(void)timerElapsed:(NSTimer*)pTimer
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( AquaSalTimer::bDispatchTimer )
+ {
+ if( pSVData->mpSalTimer )
+ {
+ YIELD_GUARD;
+ pSVData->mpSalTimer->CallCallback();
+
+ // NSTimer does not end nextEventMatchingMask of NSApplication
+ // so we need to wakeup a waiting Yield to inform it something happened
+ GetSalData()->mpFirstInstance->wakeupYield();
+ }
+ }
+}
+@end
+
diff --git a/vcl/aqua/source/app/salsys.cxx b/vcl/aqua/source/app/salsys.cxx
new file mode 100644
index 000000000000..3b548099feef
--- /dev/null
+++ b/vcl/aqua/source/app/salsys.cxx
@@ -0,0 +1,131 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "tools/rc.hxx"
+#include "vcl/svids.hrc"
+
+#include "salsys.h"
+#include "saldata.hxx"
+#include "rtl/ustrbuf.hxx"
+
+using namespace rtl;
+
+// =======================================================================
+
+AquaSalSystem::~AquaSalSystem()
+{
+}
+
+unsigned int AquaSalSystem::GetDisplayScreenCount()
+{
+ NSArray* pScreens = [NSScreen screens];
+ return pScreens ? [pScreens count] : 1;
+}
+
+bool AquaSalSystem::IsMultiDisplay()
+{
+ return false;
+}
+
+unsigned int AquaSalSystem::GetDefaultDisplayNumber()
+{
+ return 0;
+}
+
+Rectangle AquaSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ NSArray* pScreens = [NSScreen screens];
+ Rectangle aRet;
+ NSScreen* pScreen = nil;
+ if( pScreens && nScreen < [pScreens count] )
+ pScreen = [pScreens objectAtIndex: nScreen];
+ else
+ pScreen = [NSScreen mainScreen];
+
+ if( pScreen )
+ {
+ NSRect aFrame = [pScreen frame];
+ aRet = Rectangle( Point( static_cast<long int>(aFrame.origin.x), static_cast<long int>(aFrame.origin.y) ),
+ Size( static_cast<long int>(aFrame.size.width), static_cast<long int>(aFrame.size.height) ) );
+ }
+ return aRet;
+}
+
+Rectangle AquaSalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ NSArray* pScreens = [NSScreen screens];
+ Rectangle aRet;
+ NSScreen* pScreen = nil;
+ if( pScreens && nScreen < [pScreens count] )
+ pScreen = [pScreens objectAtIndex: nScreen];
+ else
+ pScreen = [NSScreen mainScreen];
+
+ if( pScreen )
+ {
+ NSRect aFrame = [pScreen visibleFrame];
+ aRet = Rectangle( Point( static_cast<long int>(aFrame.origin.x), static_cast<long int>(aFrame.origin.y) ),
+ Size( static_cast<long int>(aFrame.size.width), static_cast<long int>(aFrame.size.height) ) );
+ }
+ return aRet;
+}
+
+rtl::OUString AquaSalSystem::GetScreenName( unsigned int nScreen )
+{
+ NSArray* pScreens = [NSScreen screens];
+ OUString aRet;
+ if( nScreen < [pScreens count] )
+ {
+ ResMgr* pMgr = ImplGetResMgr();
+ if( pMgr )
+ {
+ String aScreenName( ResId( SV_MAC_SCREENNNAME, *pMgr ) );
+ aScreenName.SearchAndReplaceAllAscii( "%d", String::CreateFromInt32( nScreen ) );
+ aRet = aScreenName;
+ }
+ }
+ return aRet;
+}
+
+int AquaSalSystem::ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton )
+{
+ return 0;
+}
+
+int AquaSalSystem::ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton)
+{
+ return 0;
+}
diff --git a/vcl/aqua/source/app/saltimer.cxx b/vcl/aqua/source/app/saltimer.cxx
new file mode 100644
index 000000000000..724857e92a0c
--- /dev/null
+++ b/vcl/aqua/source/app/saltimer.cxx
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "saltimer.h"
+#include "salnstimer.h"
+#include "saldata.hxx"
+#include "salframe.h"
+#include "salinst.h"
+
+// =======================================================================
+
+NSTimer* AquaSalTimer::pRunningTimer = nil;
+bool AquaSalTimer::bDispatchTimer = false;
+
+
+void ImplSalStartTimer( ULONG nMS )
+{
+ SalData* pSalData = GetSalData();
+ if( pSalData->mpFirstInstance->isNSAppThread() )
+ {
+ AquaSalTimer::bDispatchTimer = true;
+ NSTimeInterval aTI = double(nMS)/1000.0;
+ if( AquaSalTimer::pRunningTimer != nil )
+ {
+ if( [AquaSalTimer::pRunningTimer timeInterval] == aTI )
+ // set new fire date
+ [AquaSalTimer::pRunningTimer setFireDate: [NSDate dateWithTimeIntervalSinceNow: aTI]];
+ else
+ {
+ [AquaSalTimer::pRunningTimer invalidate];
+ AquaSalTimer::pRunningTimer = nil;
+ }
+ }
+ if( AquaSalTimer::pRunningTimer == nil )
+ {
+ AquaSalTimer::pRunningTimer = [NSTimer scheduledTimerWithTimeInterval: aTI
+ target: [[[TimerCallbackCaller alloc] init] autorelease]
+ selector: @selector(timerElapsed:)
+ userInfo: nil
+ repeats: YES];
+ /* #i84055# add timer to tracking run loop mode,
+ so they also elapse while e.g. life resize
+ */
+ [[NSRunLoop currentRunLoop] addTimer: AquaSalTimer::pRunningTimer forMode: NSEventTrackingRunLoopMode];
+ }
+ }
+ else
+ {
+ SalData::ensureThreadAutoreleasePool();
+ // post an event so we can get into the main thread
+ NSPoint aPt = { 0, 0 };
+ NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
+ location: aPt
+ modifierFlags: 0
+ timestamp: [NSDate timeIntervalSinceReferenceDate]
+ windowNumber: 0
+ context: nil
+ subtype: AquaSalInstance::AppStartTimerEvent
+ data1: (int)nMS
+ data2: 0 ];
+ if( pEvent )
+ [NSApp postEvent: pEvent atStart: YES];
+ }
+}
+
+void ImplSalStopTimer()
+{
+ AquaSalTimer::bDispatchTimer = false;
+}
+
+void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpSalTimer )
+ {
+ NSTimeInterval posted = [pEvent timestamp] + NSTimeInterval([pEvent data1])/1000.0;
+ NSTimeInterval current = [NSDate timeIntervalSinceReferenceDate];
+ if( (posted - current) <= 0.0 )
+ {
+ YIELD_GUARD;
+ // timer already elapsed since event posted
+ pSVData->mpSalTimer->CallCallback();
+ }
+ ImplSalStartTimer( ULONG( [pEvent data1] ) );
+ }
+
+}
+
+AquaSalTimer::AquaSalTimer( )
+{
+}
+
+AquaSalTimer::~AquaSalTimer()
+{
+ ImplSalStopTimer();
+}
+
+void AquaSalTimer::Start( ULONG nMS )
+{
+ ImplSalStartTimer( nMS );
+}
+
+void AquaSalTimer::Stop()
+{
+ ImplSalStopTimer();
+}
+
+
diff --git a/vcl/aqua/source/app/vclnsapp.mm b/vcl/aqua/source/app/vclnsapp.mm
new file mode 100755
index 000000000000..f33599fa086e
--- /dev/null
+++ b/vcl/aqua/source/app/vclnsapp.mm
@@ -0,0 +1,518 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+ // MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vclnsapp.h"
+#include "salinst.h"
+#include "saldata.hxx"
+#include "salframe.h"
+#include "salframeview.h"
+
+#include "vcl/window.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/cmdevt.hxx"
+#include "rtl/ustrbuf.hxx"
+
+#include "premac.h"
+#import "Carbon/Carbon.h"
+#import "apple_remote/RemoteControl.h"
+#include "postmac.h"
+
+
+@implementation CocoaThreadEnabler
+-(void)enableCocoaThreads:(id)param
+{
+ // do nothing, this is just to start an NSThread and therefore put
+ // Cocoa into multithread mode
+}
+@end
+
+@implementation VCL_NSApplication
+-(void)sendEvent:(NSEvent*)pEvent
+{
+ NSEventType eType = [pEvent type];
+ if( eType == NSApplicationDefined )
+ GetSalData()->mpFirstInstance->handleAppDefinedEvent( pEvent );
+ else if( eType == NSKeyDown && ([pEvent modifierFlags] & NSCommandKeyMask) != 0 )
+ {
+ NSWindow* pKeyWin = [NSApp keyWindow];
+ if( pKeyWin && [pKeyWin isKindOfClass: [SalFrameWindow class]] )
+ {
+ AquaSalFrame* pFrame = [(SalFrameWindow*)pKeyWin getSalFrame];
+ // handle Cmd-W
+ // FIXME: the correct solution would be to handle this in framework
+ // in the menu code
+ // however that is currently being revised, so let's use a preliminary solution here
+ // this hack is based on assumption
+ // a) Cmd-W is the same in all languages in OOo's menu conig
+ // b) Cmd-W is the same in all languages in on MacOS
+ // for now this seems to be true
+ unsigned int nModMask = ([pEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask));
+ if( (pFrame->mnStyleMask & NSClosableWindowMask) != 0 )
+ {
+ if( nModMask == NSCommandKeyMask
+ && [[pEvent charactersIgnoringModifiers] isEqualToString: @"w"] )
+ {
+ [pFrame->getWindow() windowShouldClose: nil];
+ return;
+ }
+ }
+
+ /*
+ * #i98949# - Cmd-M miniaturize window, Cmd-Option-M miniaturize all windows
+ */
+ if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"m"] )
+ {
+ if ( nModMask == NSCommandKeyMask && ([pFrame->getWindow() styleMask] & NSMiniaturizableWindowMask) )
+ {
+ [pFrame->getWindow() performMiniaturize: nil];
+ return;
+ }
+
+ if ( nModMask == ( NSCommandKeyMask | NSAlternateKeyMask ) )
+ {
+ [NSApp miniaturizeAll: nil];
+ return;
+ }
+ }
+
+ // #i90083# handle frame switching
+ // FIXME: lousy workaround
+ if( (nModMask & (NSControlKeyMask|NSAlternateKeyMask)) == 0 )
+ {
+ if( [[pEvent characters] isEqualToString: @"<"] ||
+ [[pEvent characters] isEqualToString: @"~"] )
+ {
+ [self cycleFrameForward: pFrame];
+ return;
+ }
+ else if( [[pEvent characters] isEqualToString: @">"] ||
+ [[pEvent characters] isEqualToString: @"`"] )
+ {
+ [self cycleFrameBackward: pFrame];
+ return;
+ }
+ }
+
+ // get information whether the event was handled; keyDown returns nothing
+ GetSalData()->maKeyEventAnswer[ pEvent ] = false;
+ bool bHandled = false;
+
+ // dispatch to view directly to avoid the key event being consumed by the menubar
+ // popup windows do not get the focus, so they don't get these either
+ // simplest would be dispatch this to the key window always if it is without parent
+ // however e.g. in document we want the menu shortcut if e.g. the stylist has focus
+ if( pFrame->mpParent && (pFrame->mnStyle & SAL_FRAME_STYLE_FLOAT) == 0 )
+ {
+ [[pKeyWin contentView] keyDown: pEvent];
+ bHandled = GetSalData()->maKeyEventAnswer[ pEvent ];
+ }
+
+ // see whether the main menu consumes this event
+ // if not, we want to dispatch it ourselves. Unless we do this "trick"
+ // the main menu just beeps for an unknown or disabled key equivalent
+ // and swallows the event wholesale
+ NSMenu* pMainMenu = [NSApp mainMenu];
+ if( ! bHandled && (pMainMenu == 0 || ! [pMainMenu performKeyEquivalent: pEvent]) )
+ {
+ [[pKeyWin contentView] keyDown: pEvent];
+ bHandled = GetSalData()->maKeyEventAnswer[ pEvent ];
+ }
+ else
+ bHandled = true; // event handled already or main menu just handled it
+
+ GetSalData()->maKeyEventAnswer.erase( pEvent );
+ if( bHandled )
+ return;
+ }
+ else if( pKeyWin )
+ {
+ // #i94601# a window not of vcl's making has the focus.
+ // Since our menus do not invoke the usual commands
+ // try to play nice with native windows like the file dialog
+ // and emulate them
+ // precondition: this ONLY works because CMD-V (paste), CMD-C (copy) and CMD-X (cut) are
+ // NOT localized, that is the same in all locales. Should this be
+ // different in any locale, this hack will fail.
+ unsigned int nModMask = ([pEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask));
+ if( nModMask == NSCommandKeyMask )
+ {
+
+ if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"v"] )
+ {
+ if( [NSApp sendAction: @selector(paste:) to: nil from: nil] )
+ return;
+ }
+ else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"c"] )
+ {
+ if( [NSApp sendAction: @selector(copy:) to: nil from: nil] )
+ return;
+ }
+ else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"x"] )
+ {
+ if( [NSApp sendAction: @selector(cut:) to: nil from: nil] )
+ return;
+ }
+ }
+ }
+ }
+ else if( eType == NSScrollWheel && ( GetSalData()->mnSystemVersion < VER_LEOPARD /* fixed in Leopard and above */ ) )
+ {
+
+ NSWindow* pWin = [pEvent window];
+ // on Tiger wheel events do not reach non key windows
+ // which probably should be considered a bug
+ if( [pWin isKindOfClass: [SalFrameWindow class]] && [pWin canBecomeKeyWindow] == NO )
+ {
+ [[pWin contentView] scrollWheel: pEvent];
+ return;
+ }
+ }
+ [super sendEvent: pEvent];
+}
+
+-(void)sendSuperEvent:(NSEvent*)pEvent
+{
+ [super sendEvent: pEvent];
+}
+
+-(void)cycleFrameForward: (AquaSalFrame*)pCurFrame
+{
+ // find current frame in list
+ std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames );
+ std::list< AquaSalFrame* >::iterator it = rFrames.begin();
+ for( ; it != rFrames.end() && *it != pCurFrame; ++it )
+ ;
+ if( it != rFrames.end() )
+ {
+ // now find the next frame (or end)
+ do
+ {
+ ++it;
+ if( it != rFrames.end() )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ }
+ } while( it != rFrames.end() );
+ // cycle around, find the next up to pCurFrame
+ it = rFrames.begin();
+ while( *it != pCurFrame )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ ++it;
+ }
+ }
+}
+
+-(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame
+{
+ // do the same as cycleFrameForward only with a reverse iterator
+
+ // find current frame in list
+ std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames );
+ std::list< AquaSalFrame* >::reverse_iterator it = rFrames.rbegin();
+ for( ; it != rFrames.rend() && *it != pCurFrame; ++it )
+ ;
+ if( it != rFrames.rend() )
+ {
+ // now find the next frame (or end)
+ do
+ {
+ ++it;
+ if( it != rFrames.rend() )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ }
+ } while( it != rFrames.rend() );
+ // cycle around, find the next up to pCurFrame
+ it = rFrames.rbegin();
+ while( *it != pCurFrame )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ ++it;
+ }
+ }
+}
+
+-(NSMenu*)applicationDockMenu:(NSApplication *)sender
+{
+ return AquaSalInstance::GetDynamicDockMenu();
+}
+
+-(MacOSBOOL)application: (NSApplication*)app openFile: (NSString*)pFile
+{
+ const rtl::OUString aFile( GetOUString( pFile ) );
+ if( ! AquaSalInstance::isOnCommandLine( aFile ) )
+ {
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_OPEN_STRING, aFile );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ }
+ return YES;
+}
+
+-(void)application: (NSApplication*) app openFiles: (NSArray*)files
+{
+ rtl::OUStringBuffer aFileList( 256 );
+
+ NSEnumerator* it = [files objectEnumerator];
+ NSString* pFile = nil;
+
+ while( (pFile = [it nextObject]) != nil )
+ {
+ const rtl::OUString aFile( GetOUString( pFile ) );
+ if( ! AquaSalInstance::isOnCommandLine( aFile ) )
+ {
+ if( aFileList.getLength() > 0 )
+ aFileList.append( sal_Unicode( APPEVENT_PARAM_DELIMITER ) );
+ aFileList.append( aFile );
+ }
+ }
+
+ if( aFileList.getLength() )
+ {
+ // we have no back channel here, we have to assume success, in which case
+ // replyToOpenOrPrint does not need to be called according to documentation
+ // [app replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_OPEN_STRING, aFileList.makeStringAndClear() );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ }
+}
+
+-(MacOSBOOL)application: (NSApplication*)app printFile: (NSString*)pFile
+{
+ const rtl::OUString aFile( GetOUString( pFile ) );
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_PRINT_STRING, aFile );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ return YES;
+}
+-(NSApplicationPrintReply)application: (NSApplication *) app printFiles:(NSArray *)files withSettings: (NSDictionary *)printSettings showPrintPanels:(MacOSBOOL)bShowPrintPanels
+{
+ // currently ignores print settings an bShowPrintPanels
+ rtl::OUStringBuffer aFileList( 256 );
+
+ NSEnumerator* it = [files objectEnumerator];
+ NSString* pFile = nil;
+
+ while( (pFile = [it nextObject]) != nil )
+ {
+ if( aFileList.getLength() > 0 )
+ aFileList.append( sal_Unicode( APPEVENT_PARAM_DELIMITER ) );
+ aFileList.append( GetOUString( pFile ) );
+ }
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_PRINT_STRING, aFileList.makeStringAndClear() );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ // we have no back channel here, we have to assume success
+ // correct handling would be NSPrintingReplyLater and then send [app replyToOpenOrPrint]
+ return NSPrintingSuccess;
+}
+
+-(NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *) app
+{
+ SalData* pSalData = GetSalData();
+ #if 1 // currently do some really bad hack
+ if( ! pSalData->maFrames.empty() )
+ {
+ /* #i92766# something really weird is going on with the retain count of
+ our windows; sometimes we get a duplicate free before exit on one of our
+ NSWindows. The reason is unclear; to avoid this currently we retain them once more
+
+ FIXME: this is a really bad hack, relying on the system to catch the leaked
+ resources. Find out what really goes on here and fix it !
+ */
+ std::vector< NSWindow* > aHackRetainedWindows;
+ for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
+ it != pSalData->maFrames.end(); ++it )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ Window* pWin = (*it)->GetWindow();
+ String aTitle = pWin->GetText();
+ Window* pClient = pWin->ImplGetClientWindow();
+ fprintf( stderr, "retaining %p (old count %d) windowtype=%s clienttyp=%s title=%s\n",
+ (*it)->mpWindow, [(*it)->mpWindow retainCount],
+ typeid(*pWin).name(), pClient ? typeid(*pClient).name() : "<nil>",
+ rtl::OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr()
+ );
+ #endif
+ [(*it)->mpWindow retain];
+ aHackRetainedWindows.push_back( (*it)->mpWindow );
+ }
+ if( pSalData->maFrames.front()->CallCallback( SALEVENT_SHUTDOWN, NULL ) )
+ {
+ for( std::vector< NSWindow* >::iterator it = aHackRetainedWindows.begin();
+ it != aHackRetainedWindows.end(); ++it )
+ {
+ // clean up the retaing count again from the shutdown workaround
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "releasing %p\n", (*it) );
+ #endif
+ [(*it) release];
+ }
+ return NSTerminateCancel;
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
+ it != pSalData->maFrames.end(); ++it )
+ {
+ Window* pWin = (*it)->GetWindow();
+ String aTitle = pWin->GetText();
+ Window* pClient = pWin->ImplGetClientWindow();
+ fprintf( stderr, "frame still alive: NSWindow %p windowtype=%s clienttyp=%s title=%s\n",
+ (*it)->mpWindow, typeid(*pWin).name(), pClient ? typeid(*pClient).name() : "<nil>",
+ rtl::OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr()
+ );
+ }
+ #endif
+ }
+ #else // the clean version follows
+ return pSalData->maFrames.front()->CallCallback( SALEVENT_SHUTDOWN, NULL ) ? NSTerminateCancel : NSTerminateNow;
+ #endif
+ return NSTerminateNow;
+}
+
+-(void)systemColorsChanged: (NSNotification*) pNotification
+{
+ const SalData* pSalData = GetSalData();
+ if( !pSalData->maFrames.empty() )
+ pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
+}
+
+-(void)screenParametersChanged: (NSNotification*) pNotification
+{
+ SalData* pSalData = GetSalData();
+ std::list< AquaSalFrame* >::iterator it;
+ for( it = pSalData->maFrames.begin(); it != pSalData->maFrames.end(); ++it )
+ {
+ (*it)->screenParametersChanged();
+ }
+}
+
+-(void)scrollbarVariantChanged: (NSNotification*) pNotification
+{
+ GetSalData()->mpFirstInstance->delayedSettingsChanged( true );
+}
+
+-(void)scrollbarSettingsChanged: (NSNotification*) pNotification
+{
+ GetSalData()->mpFirstInstance->delayedSettingsChanged( false );
+}
+
+-(void)addFallbackMenuItem: (NSMenuItem*)pNewItem
+{
+ AquaSalMenu::addFallbackMenuItem( pNewItem );
+}
+
+-(void)removeFallbackMenuItem: (NSMenuItem*)pItem
+{
+ AquaSalMenu::removeFallbackMenuItem( pItem );
+}
+
+-(void)addDockMenuItem: (NSMenuItem*)pNewItem
+{
+ NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
+ [pDock insertItem: pNewItem atIndex: [pDock numberOfItems]];
+}
+
+// for Apple Remote implementation
+
+#pragma mark -
+#pragma mark NSApplication Delegates
+- (void)applicationWillBecomeActive:(NSNotification *)aNotification {
+ if (GetSalData()->mpMainController->remoteControl) {
+
+ // [remoteControl startListening: self];
+ // does crash because the right thing to do is
+ // [GetSalData()->mpMainController->remoteControl startListening: self];
+ // but the instance variable 'remoteControl' is declared protected
+ // workaround : declare remoteControl instance variable as public in RemoteMainController.m
+
+ [GetSalData()->mpMainController->remoteControl startListening: self];
+#ifdef DEBUG
+ NSLog(@"Apple Remote will become active - Using remote controls");
+#endif
+ }
+}
+
+- (void)applicationWillResignActive:(NSNotification *)aNotification {
+ if (GetSalData()->mpMainController->remoteControl) {
+
+ // [remoteControl stopListening: self];
+ // does crash because the right thing to do is
+ // [GetSalData()->mpMainController->remoteControl stopListening: self];
+ // but the instance variable 'remoteControl' is declared protected
+ // workaround : declare remoteControl instance variable as public in RemoteMainController.m
+
+ [GetSalData()->mpMainController->remoteControl stopListening: self];
+#ifdef DEBUG
+ NSLog(@"Apple Remote will resign active - Releasing remote controls");
+#endif
+ }
+}
+
+- (MacOSBOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (MacOSBOOL) bWinVisible
+{
+ NSObject* pHdl = GetSalData()->mpDockIconClickHandler;
+ if( pHdl && [pHdl respondsToSelector: @selector(dockIconClicked:)] )
+ {
+ [pHdl performSelector:@selector(dockIconClicked:) withObject: self];
+ }
+ return YES;
+}
+
+-(void)setDockIconClickHandler: (NSObject*)pHandler
+{
+ GetSalData()->mpDockIconClickHandler = pHandler;
+}
+
+
+@end
+
diff --git a/vcl/aqua/source/dtrans/DataFlavorMapping.cxx b/vcl/aqua/source/dtrans/DataFlavorMapping.cxx
new file mode 100644
index 000000000000..e0a95a532bf8
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DataFlavorMapping.cxx
@@ -0,0 +1,732 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "vcl/unohelp.hxx"
+#include <DataFlavorMapping.hxx>
+#include "HtmlFmtFlt.hxx"
+#include "PictToBmpFlt.hxx"
+#include "com/sun/star/datatransfer/UnsupportedFlavorException.hpp"
+#include "com/sun/star/datatransfer/XMimeContentType.hpp"
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/uno/Sequence.hxx"
+
+#include <rtl/ustring.hxx>
+#include <rtl/memory.h>
+#include <osl/endian.h>
+
+#include <vector>
+#include <stdio.h>
+
+#include <premac.h>
+#include <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+using namespace ::com::sun::star::datatransfer;
+using namespace rtl;
+using namespace ::com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace cppu;
+using namespace std;
+
+namespace // private
+{
+ const Type CPPUTYPE_SEQINT8 = getCppuType((Sequence<sal_Int8>*)0);
+ const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 );
+
+ /* Determine whether or not a DataFlavor is valid.
+ */
+ bool isValidFlavor(const DataFlavor& aFlavor)
+ {
+ size_t len = aFlavor.MimeType.getLength();
+ Type dtype = aFlavor.DataType;
+ return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING)));
+ }
+
+ typedef vector<sal_Unicode> UnicodeBuffer;
+
+ OUString NSStringToOUString(NSString* cfString)
+ {
+ BOOST_ASSERT(cfString && "Invalid parameter");
+
+ const char* utf8Str = [cfString UTF8String];
+ unsigned int len = rtl_str_getLength(utf8Str);
+
+ return OUString(utf8Str, len, RTL_TEXTENCODING_UTF8);
+ }
+
+ NSString* OUStringToNSString(const OUString& ustring)
+ {
+ OString utf8Str = OUStringToOString(ustring, RTL_TEXTENCODING_UTF8);
+ return [NSString stringWithCString: utf8Str.getStr() encoding: NSUTF8StringEncoding];
+ }
+
+
+ const NSString* PBTYPE_UT16 = @"CorePasteboardFlavorType 0x75743136";
+ const NSString* PBTYPE_PICT = @"CorePasteboardFlavorType 0x50494354";
+ const NSString* PBTYPE_HTML = @"CorePasteboardFlavorType 0x48544D4C";
+ const NSString* PBTYPE_SODX = @"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
+ const NSString* PBTYPE_SESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const NSString* PBTYPE_SLSDX = @"application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"";
+ const NSString* PBTYPE_ESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const NSString* PBTYPE_LSX = @"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
+ const NSString* PBTYPE_EOX = @"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
+ const NSString* PBTYPE_SVXB = @"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
+ const NSString* PBTYPE_GDIMF = @"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
+ const NSString* PBTYPE_WMF = @"application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
+ const NSString* PBTYPE_EMF = @"application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
+
+ const NSString* PBTYPE_DUMMY_INTERNAL = @"application/x-openoffice-internal";
+
+ const char* FLAVOR_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
+ const char* FLAVOR_SESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const char* FLAVOR_SLSDX = "application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"";
+ const char* FLAVOR_ESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const char* FLAVOR_LSX = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
+ const char* FLAVOR_EOX = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
+ const char* FLAVOR_SVXB = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
+ const char* FLAVOR_GDIMF = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
+ const char* FLAVOR_WMF = "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
+ const char* FLAVOR_EMF = "application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
+
+ const char* FLAVOR_DUMMY_INTERNAL = "application/x-openoffice-internal";
+
+
+ struct FlavorMap
+ {
+ NSString* SystemFlavor;
+ const char* OOoFlavor;
+ const char* HumanPresentableName;
+ Type DataType;
+ };
+
+ /* At the moment it appears as if only MS Office pastes "public.html" to the clipboard.
+ */
+ FlavorMap flavorMap[] =
+ {
+ { NSStringPboardType, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", CPPUTYPE_OUSTRING },
+ { NSRTFPboardType, "text/richtext", "Rich Text Format", CPPUTYPE_SEQINT8 },
+ { NSTIFFPboardType, "image/bmp", "Windows Bitmap", CPPUTYPE_SEQINT8 },
+ { NSPICTPboardType, "image/bmp", "Windows Bitmap", CPPUTYPE_SEQINT8 },
+ { NSHTMLPboardType, "text/html", "Plain Html", CPPUTYPE_SEQINT8 },
+ { NSFilenamesPboardType, "application/x-openoffice-filelist;windows_formatname=\"FileList\"", "FileList", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SESX, FLAVOR_SESX, "Star Embed Source (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SLSDX, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_ESX, FLAVOR_ESX, "Star Embed Source (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_LSX, FLAVOR_LSX, "Star Link Source (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_EOX, FLAVOR_EOX, "Star Embedded Object (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SVXB, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", CPPUTYPE_SEQINT8 },
+ { PBTYPE_GDIMF, FLAVOR_GDIMF, "GDIMetaFile", CPPUTYPE_SEQINT8 },
+ { PBTYPE_WMF, FLAVOR_WMF, "Windows MetaFile", CPPUTYPE_SEQINT8 },
+ { PBTYPE_EMF, FLAVOR_EMF, "Windows Enhanced MetaFile", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SODX, FLAVOR_SODX, "Star Object Descriptor (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_DUMMY_INTERNAL, FLAVOR_DUMMY_INTERNAL, "internal data",CPPUTYPE_SEQINT8 }
+ };
+
+
+ #define SIZE_FLAVOR_MAP (sizeof(flavorMap)/sizeof(FlavorMap))
+
+
+ inline bool isByteSequenceType(const Type& theType)
+ {
+ return (theType == CPPUTYPE_SEQINT8);
+ }
+
+ inline bool isOUStringType(const Type& theType)
+ {
+ return (theType == CPPUTYPE_OUSTRING);
+ }
+
+} // namespace private
+
+
+//###########################
+
+/* A base class for other data provider.
+ */
+class DataProviderBaseImpl : public DataProvider
+{
+public:
+ DataProviderBaseImpl(const Any& data);
+ DataProviderBaseImpl(id data);
+ virtual ~DataProviderBaseImpl();
+
+protected:
+ Any mData;
+ //NSData* mSystemData;
+ id mSystemData;
+};
+
+DataProviderBaseImpl::DataProviderBaseImpl(const Any& data) :
+ mData(data),
+ mSystemData(nil)
+{
+}
+
+DataProviderBaseImpl::DataProviderBaseImpl(id data) :
+ mSystemData(data)
+{
+ [mSystemData retain];
+}
+
+
+DataProviderBaseImpl::~DataProviderBaseImpl()
+{
+ if (mSystemData)
+ {
+ [mSystemData release];
+ }
+}
+
+//#################################
+
+class UniDataProvider : public DataProviderBaseImpl
+{
+public:
+ UniDataProvider(const Any& data);
+
+ UniDataProvider(NSData* data);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+UniDataProvider::UniDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+UniDataProvider::UniDataProvider(NSData* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+NSData* UniDataProvider::getSystemData()
+{
+ OUString ustr;
+ mData >>= ustr;
+
+ OString strUtf8;
+ ustr.convertToString(&strUtf8, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
+
+ return [NSData dataWithBytes: strUtf8.getStr() length: strUtf8.getLength()];
+}
+
+Any UniDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ oOOData = makeAny(OUString(reinterpret_cast<const sal_Char*>([mSystemData bytes]),
+ [mSystemData length],
+ RTL_TEXTENCODING_UTF8));
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//###########################
+
+class ByteSequenceDataProvider : public DataProviderBaseImpl
+{
+public:
+ ByteSequenceDataProvider(const Any& data);
+
+ ByteSequenceDataProvider(NSData* data);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+
+NSData* ByteSequenceDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> rawData;
+ mData >>= rawData;
+
+ return [NSData dataWithBytes: rawData.getArray() length: rawData.getLength()];
+}
+
+Any ByteSequenceDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> byteSequence;
+ byteSequence.realloc(flavorDataLength);
+ memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength);
+ oOOData = makeAny(byteSequence);
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+
+//###########################
+
+class HTMLFormatDataProvider : public DataProviderBaseImpl
+{
+public:
+ HTMLFormatDataProvider(const Any& data);
+
+ HTMLFormatDataProvider(NSData* data);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+HTMLFormatDataProvider::HTMLFormatDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+NSData* HTMLFormatDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> textHtmlData;
+ mData >>= textHtmlData;
+
+ Sequence<sal_Int8> htmlFormatData = TextHtmlToHTMLFormat(textHtmlData);
+
+ return [NSData dataWithBytes: htmlFormatData.getArray() length: htmlFormatData.getLength()];
+}
+
+Any HTMLFormatDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> unkHtmlData;
+
+ unkHtmlData.realloc(flavorDataLength);
+ memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength);
+
+ Sequence<sal_Int8>* pPlainHtml = &unkHtmlData;
+ Sequence<sal_Int8> plainHtml;
+
+ if (isHTMLFormat(unkHtmlData))
+ {
+ plainHtml = HTMLFormatToTextHtml(unkHtmlData);
+ pPlainHtml = &plainHtml;
+ }
+
+ oOOData = makeAny(*pPlainHtml);
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//###########################
+
+class BMPDataProvider : public DataProviderBaseImpl
+{
+ NSBitmapImageFileType meImageType;
+public:
+ BMPDataProvider(const Any& data, NSBitmapImageFileType eImageType );
+
+ BMPDataProvider(NSData* data, NSBitmapImageFileType eImageType);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+BMPDataProvider::BMPDataProvider(const Any& data, NSBitmapImageFileType eImageType) :
+ DataProviderBaseImpl(data),
+ meImageType( eImageType )
+{
+}
+
+BMPDataProvider::BMPDataProvider(NSData* data, NSBitmapImageFileType eImageType) :
+ DataProviderBaseImpl(data),
+ meImageType( eImageType )
+{
+}
+
+NSData* BMPDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> bmpData;
+ mData >>= bmpData;
+
+ Sequence<sal_Int8> pictData;
+ NSData* sysData = NULL;
+
+ if (BMPToImage(bmpData, pictData, meImageType))
+ {
+ sysData = [NSData dataWithBytes: pictData.getArray() length: pictData.getLength()];
+ }
+
+ return sysData;
+}
+
+/* At the moment the OOo 'PCT' filter is not good enough to be used
+ and there is no flavor defined for exchanging 'PCT' with OOo so
+ we will at the moment convert 'PCT' to a Windows BMP and provide
+ this to OOo
+*/
+Any BMPDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> pictData(flavorDataLength);
+
+ memcpy(pictData.getArray(), [mSystemData bytes], flavorDataLength);
+
+ Sequence<sal_Int8> bmpData;
+
+ if (ImageToBMP(pictData, bmpData, meImageType))
+ {
+ oOOData = makeAny(bmpData);
+ }
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//######################
+
+class FileListDataProvider : public DataProviderBaseImpl
+{
+public:
+ FileListDataProvider(const Any& data);
+ FileListDataProvider(NSArray* data);
+
+ virtual NSData* getSystemData();
+ virtual Any getOOoData();
+};
+
+FileListDataProvider::FileListDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+FileListDataProvider::FileListDataProvider(NSArray* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+NSData* FileListDataProvider::getSystemData()
+{
+ return [NSData data];
+}
+
+Any FileListDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ size_t length = [mSystemData count];
+ size_t lenSeqRequired = 0;
+
+ for (size_t i = 0; i < length; i++)
+ {
+ NSString* fname = [mSystemData objectAtIndex: i];
+ lenSeqRequired += [fname maximumLengthOfBytesUsingEncoding: NSUnicodeStringEncoding] + sizeof(unichar);
+ }
+
+ Sequence<sal_Int8> oOOFileList(lenSeqRequired);
+ unichar* pBuffer = reinterpret_cast<unichar*>(oOOFileList.getArray());
+ rtl_zeroMemory(pBuffer, lenSeqRequired);
+
+ for (size_t i = 0; i < length; i++)
+ {
+ NSString* fname = [mSystemData objectAtIndex: i];
+ [fname getCharacters: pBuffer];
+ size_t l = [fname length];
+ pBuffer += l + 1;
+ }
+
+ oOOData = makeAny(oOOFileList);
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//###########################
+
+DataFlavorMapper::DataFlavorMapper()
+{
+ Reference<XMultiServiceFactory> mrServiceManager = vcl::unohelper::GetMultiServiceFactory();
+ mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceManager->createInstance(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory"))), UNO_QUERY);
+
+ if (!mrXMimeCntFactory.is())
+ throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")), NULL);
+}
+
+DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor(NSString* systemDataFlavor) const
+{
+ DataFlavor oOOFlavor;
+
+ for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
+ {
+ if ([systemDataFlavor caseInsensitiveCompare: flavorMap[i].SystemFlavor] == NSOrderedSame)
+ {
+ oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor);
+ oOOFlavor.HumanPresentableName = OUString(RTL_CONSTASCII_USTRINGPARAM(flavorMap[i].HumanPresentableName));
+ oOOFlavor.DataType = flavorMap[i].DataType;
+ return oOOFlavor;
+ }
+ } // for
+
+ return oOOFlavor;
+}
+
+NSString* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor& oOOFlavor) const
+{
+ NSString* sysFlavor = NULL;
+
+ for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
+ {
+ if (oOOFlavor.MimeType.compareToAscii(flavorMap[i].OOoFlavor, strlen(flavorMap[i].OOoFlavor)) == 0)
+ {
+ sysFlavor = flavorMap[i].SystemFlavor;
+ }
+ }
+
+ return sysFlavor;
+}
+
+NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard) const
+{
+ NSArray *supportedTypes = [NSArray arrayWithObjects: NSTIFFPboardType, NSPICTPboardType, nil];
+ NSString *sysFlavor = [pPasteboard availableTypeFromArray:supportedTypes];
+ return sysFlavor;
+}
+
+DataProviderPtr_t DataFlavorMapper::getDataProvider(NSString* systemFlavor, Reference<XTransferable> rTransferable) const
+{
+ DataProviderPtr_t dp;
+
+ try
+ {
+ DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor);
+
+ Any data = rTransferable->getTransferData(oOOFlavor);
+
+ if (isByteSequenceType(data.getValueType()))
+ {
+ if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new HTMLFormatDataProvider(data));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSPICTPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(data, PICTImageFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSTIFFPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(data, NSTIFFFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new FileListDataProvider(data));
+ }
+ else
+ {
+ dp = DataProviderPtr_t(new ByteSequenceDataProvider(data));
+ }
+ }
+ else // Must be OUString type
+ {
+ BOOST_ASSERT(isOUStringType(data.getValueType()));
+ dp = DataProviderPtr_t(new UniDataProvider(data));
+ }
+ }
+ catch(UnsupportedFlavorException&)
+ {
+ // Somebody violates the contract of the clipboard
+ // interface @see XTransferable
+ }
+
+ return dp;
+}
+
+DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor, NSArray* systemData) const
+{
+ return DataProviderPtr_t(new FileListDataProvider(systemData));
+}
+
+DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor, NSData* systemData) const
+{
+ DataProviderPtr_t dp;
+
+ if ([systemFlavor caseInsensitiveCompare: NSStringPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new UniDataProvider(systemData));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSPICTPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(systemData, PICTImageFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSTIFFPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(systemData, NSTIFFFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
+ {
+ //dp = DataProviderPtr_t(new FileListDataProvider(systemData));
+ }
+ else
+ {
+ dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData));
+ }
+
+ return dp;
+}
+
+bool DataFlavorMapper::isValidMimeContentType(const rtl::OUString& contentType) const
+{
+ bool result = true;
+
+ try
+ {
+ Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType));
+ }
+ catch( IllegalArgumentException& )
+ {
+ result = false;
+ }
+
+ return result;
+}
+
+NSArray* DataFlavorMapper::flavorSequenceToTypesArray(const com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor>& flavors) const
+{
+ sal_uInt32 nFlavors = flavors.getLength();
+ NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: 1];
+
+ for (sal_uInt32 i = 0; i < nFlavors; i++)
+ {
+ if( flavors[i].MimeType.compareToAscii( "image/bmp", 9 ) == 0 )
+ {
+ [array addObject: NSTIFFPboardType];
+ [array addObject: NSPICTPboardType];
+ }
+ else
+ {
+ NSString* str = openOfficeToSystemFlavor(flavors[i]);
+
+ if (str != NULL)
+ {
+ [array addObject: str];
+ }
+ }
+ }
+
+ // #i89462# #i90747#
+ // in case no system flavor was found to report
+ // report at least one so D&D between OOo targets works
+ if( [array count] == 0 )
+ {
+ [array addObject: PBTYPE_DUMMY_INTERNAL];
+ }
+
+ return [array autorelease];
+}
+
+com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor> DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const
+{
+ int nFormats = [types count];
+ Sequence<DataFlavor> flavors;
+
+ for (int i = 0; i < nFormats; i++)
+ {
+ NSString* sysFormat = [types objectAtIndex: i];
+ DataFlavor oOOFlavor = systemToOpenOfficeFlavor(sysFormat);
+
+ if (isValidFlavor(oOOFlavor))
+ {
+ flavors.realloc(flavors.getLength() + 1);
+ flavors[flavors.getLength() - 1] = oOOFlavor;
+ }
+ }
+
+ return flavors;
+}
+
+
+NSArray* DataFlavorMapper::getAllSupportedPboardTypes() const
+{
+ NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: SIZE_FLAVOR_MAP];
+
+ for (sal_uInt32 i = 0; i < SIZE_FLAVOR_MAP; i++)
+ {
+ [array addObject: flavorMap[i].SystemFlavor];
+ }
+
+ return [array autorelease];
+}
diff --git a/vcl/aqua/source/dtrans/DataFlavorMapping.hxx b/vcl/aqua/source/dtrans/DataFlavorMapping.hxx
new file mode 100644
index 000000000000..9847fcbd3987
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DataFlavorMapping.hxx
@@ -0,0 +1,143 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DATAFLAVORMAPPING_HXX_
+#define INCLUDED_DATAFLAVORMAPPING_HXX_
+
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+#include <memory>
+#include <boost/shared_ptr.hpp>
+
+
+/* An interface to get the clipboard data in either
+ system or OOo format.
+ */
+class DataProvider
+{
+public:
+ virtual ~DataProvider() {};
+
+ /* Get the clipboard data in the system format.
+ The caller has to retain/release the returned
+ CFDataRef on demand.
+ */
+ virtual NSData* getSystemData() = 0;
+
+ /* Get the clipboard data in OOo format.
+ */
+ virtual com::sun::star::uno::Any getOOoData() = 0;
+};
+
+typedef std::auto_ptr<DataProvider> DataProviderPtr_t;
+
+
+//################################
+
+
+class DataFlavorMapper
+{
+public:
+ /* Initialialize a DataFavorMapper instance. Throws a RuntimeException in case the XMimeContentTypeFactory service
+ cannot be created.
+ */
+ DataFlavorMapper();
+
+
+ /* Map a system data flavor to an OpenOffice data flavor.
+ Return an empty string if there is not suiteable
+ mapping from a system data flavor to a OpenOffice data
+ flavor.
+ */
+ com::sun::star::datatransfer::DataFlavor systemToOpenOfficeFlavor(NSString* systemDataFlavor) const;
+
+
+ /* Map an OpenOffice data flavor to a system data flavor.
+ If there is no suiteable mapping available NULL will
+ be returned.
+ */
+ NSString* openOfficeToSystemFlavor(const com::sun::star::datatransfer::DataFlavor& oooDataFlavor) const;
+
+ /* Select the best available image data type
+ If there is no suiteable mapping available NULL will
+ be returned.
+ */
+ NSString* openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard) const;
+
+ /* Get a data provider which is able to provide the data 'rTransferable' offers in a format that can
+ be put on to the system clipboard.
+ */
+ DataProviderPtr_t getDataProvider(NSString* systemFlavor,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > rTransferable) const;
+
+
+
+ /* Get a data provider which is able to provide 'systemData' in the OOo expected format.
+ */
+ DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSArray* systemData) const;
+
+
+ /* Get a data provider which is able to provide 'systemData' in the OOo expected format.
+ */
+ DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSData* systemData) const;
+
+
+ /* Translate a sequence of DataFlavors into a NSArray of system types.
+ Only those DataFlavors for which a suitable mapping to a system
+ type exist will be contained in the returned types array.
+ */
+ NSArray* flavorSequenceToTypesArray(const com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor>& flavors) const;
+
+ /* Translate a NSArray of system types into a sequence of DataFlavors.
+ Only those types for which a suitable mapping to a DataFlavor
+ exist will be contained in the new DataFlavor Sequence.
+ */
+ com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor> typesArrayToFlavorSequence(NSArray* types) const;
+
+ /* Returns an NSArray containing all pasteboard types supported by OOo
+ */
+ NSArray* DataFlavorMapper::getAllSupportedPboardTypes() const;
+
+private:
+ /* Determines if the provided Mime content type is valid.
+ */
+ bool isValidMimeContentType(const rtl::OUString& contentType) const;
+
+private:
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory;
+};
+
+typedef boost::shared_ptr<DataFlavorMapper> DataFlavorMapperPtr_t;
+
+#endif
diff --git a/vcl/aqua/source/dtrans/DragActionConversion.cxx b/vcl/aqua/source/dtrans/DragActionConversion.cxx
new file mode 100644
index 000000000000..06ce57e8748f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragActionConversion.cxx
@@ -0,0 +1,92 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "DragActionConversion.hxx"
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+
+
+using namespace com::sun::star::datatransfer::dnd;
+
+
+/* Convert office drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>
+ into system conform drag actions.
+ */
+unsigned int OfficeToSystemDragActions(sal_Int8 dragActions)
+{
+ unsigned int actions = NSDragOperationNone;
+
+ if (dragActions & DNDConstants::ACTION_COPY)
+ {
+ actions |= NSDragOperationCopy;
+ }
+
+ if (dragActions & DNDConstants::ACTION_MOVE)
+ {
+ actions |= NSDragOperationMove;
+ }
+
+ if (dragActions & DNDConstants::ACTION_LINK)
+ {
+ actions |= NSDragOperationLink;
+ }
+
+ return actions;
+}
+
+/* Convert system conform drag actions into office conform
+ drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>.
+ */
+sal_Int8 SystemToOfficeDragActions(unsigned int dragActions)
+{
+ sal_Int8 actions = DNDConstants::ACTION_NONE;
+
+ if (dragActions & NSDragOperationCopy)
+ {
+ actions |= DNDConstants::ACTION_COPY;
+ }
+
+ if (dragActions & NSDragOperationMove)
+ {
+ actions |= DNDConstants::ACTION_MOVE;
+ }
+
+ if (dragActions & NSDragOperationLink)
+ {
+ actions |= DNDConstants::ACTION_LINK;
+ }
+
+ // We map NSDragOperationGeneric to ACTION_DEFAULT to
+ // signal that we have to decide for a drag action
+ if (dragActions & NSDragOperationGeneric)
+ {
+ actions |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ return actions;
+}
diff --git a/vcl/aqua/source/dtrans/DragActionConversion.hxx b/vcl/aqua/source/dtrans/DragActionConversion.hxx
new file mode 100644
index 000000000000..7facfef794b6
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragActionConversion.hxx
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+#include <sal/types.h>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+
+/* Convert office drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>
+ into system conform drag actions.
+ */
+unsigned int OfficeToSystemDragActions(sal_Int8 dragActions);
+
+/* Convert system conform drag actions into office conform
+ drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>.
+ */
+sal_Int8 SystemToOfficeDragActions(unsigned int dragActions);
diff --git a/vcl/aqua/source/dtrans/DragSource.cxx b/vcl/aqua/source/dtrans/DragSource.cxx
new file mode 100644
index 000000000000..adb247d70711
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSource.cxx
@@ -0,0 +1,363 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <rtl/unload.h>
+
+#include "comphelper/makesequence.hxx"
+
+#include "DragSource.hxx"
+#include "DragSourceContext.hxx"
+#include "aqua_clipboard.hxx"
+#include "DragActionConversion.hxx"
+
+#include <rtl/ustring.h>
+#include <memory>
+
+
+using namespace rtl;
+using namespace cppu;
+using namespace osl;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt::MouseButton;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::lang;
+using namespace comphelper;
+using namespace std;
+
+
+// For OOo internal D&D we provide the Transferable without NSDragPboard
+// interference as a shortcut
+Reference<XTransferable> DragSource::g_XTransferable = Reference<XTransferable>();
+NSView* DragSource::g_DragSourceView = nil;
+bool DragSource::g_DropSuccessSet = false;
+bool DragSource::g_DropSuccess = false;
+
+
+OUString dragSource_getImplementationName()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDragSource_V1"));
+}
+
+Sequence<OUString> dragSource_getSupportedServiceNames()
+{
+ return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource")));
+}
+
+
+@implementation DragSourceHelper;
+
+-(DragSourceHelper*)initWithDragSource: (DragSource*) pds
+{
+ self = [super init];
+
+ if (self)
+ {
+ mDragSource = pds;
+ }
+
+ return self;
+}
+
+
+-(void)mouseDown: (NSEvent*)theEvent
+{
+ mDragSource->saveMouseEvent(theEvent);
+}
+
+
+-(void)mouseDragged: (NSEvent*)theEvent
+{
+ mDragSource->saveMouseEvent(theEvent);
+}
+
+
+-(unsigned int)draggingSourceOperationMaskForLocal: (MacOSBOOL)isLocal
+{
+ return mDragSource->getSupportedDragOperations(isLocal);
+}
+
+
+-(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint
+{
+ DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
+ new DragSourceContext(mDragSource),
+ mDragSource,
+ DNDConstants::ACTION_COPY,
+ DNDConstants::ACTION_COPY);
+
+ mDragSource->mXDragSrcListener->dragEnter(dsde);
+}
+
+
+-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
+{
+ // an internal drop can accept the drop but fail with dropComplete( false )
+ // this is different than the Cocoa API
+ bool bDropSuccess = operation != NSDragOperationNone;
+ if( DragSource::g_DropSuccessSet )
+ bDropSuccess = DragSource::g_DropSuccess;
+
+ DragSourceDropEvent dsde(static_cast<OWeakObject*>(mDragSource),
+ new DragSourceContext(mDragSource),
+ static_cast< XDragSource* >(mDragSource),
+ SystemToOfficeDragActions(operation),
+ bDropSuccess );
+
+ mDragSource->mXDragSrcListener->dragDropEnd(dsde);
+ mDragSource->mXDragSrcListener = Reference<XDragSourceListener>();
+}
+
+
+-(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint
+{
+ DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
+ new DragSourceContext(mDragSource),
+ mDragSource,
+ DNDConstants::ACTION_COPY,
+ DNDConstants::ACTION_COPY);
+
+ mDragSource->mXDragSrcListener->dragOver(dsde);
+}
+
+@end
+
+
+DragSource::DragSource():
+ WeakComponentImplHelper3<XDragSource, XInitialization, XServiceInfo>(m_aMutex),
+ mView(NULL),
+ mLastMouseEventBeforeStartDrag(nil),
+ m_MouseButton(0)
+{
+}
+
+
+DragSource::~DragSource()
+{
+ [(id <MouseEventListener>)mView unregisterMouseEventListener: mDragSourceHelper];
+ [mDragSourceHelper release];
+}
+
+
+void SAL_CALL DragSource::initialize(const Sequence< Any >& aArguments)
+ throw(Exception)
+{
+ if (aArguments.getLength() < 2)
+ {
+ throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Not enough parameter.")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ Any pNSView = aArguments[1];
+ sal_uInt64 tmp = 0;
+ pNSView >>= tmp;
+ mView = (NSView*)tmp;
+
+ /* All SalFrameView the base class for all VCL system views inherits from
+ NSView in order to get mouse and other events. This is the only way to
+ get these events. In order to start a drag operation we need to provide
+ the mouse event which was the trigger. SalFrameView therefor implements
+ a hook mechanism so that we can get mouse events for our purpose.
+ */
+ if (![mView respondsToSelector: @selector(registerMouseEventListener:)] ||
+ ![mView respondsToSelector: @selector(unregisterMouseEventListener:)])
+ {
+ throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Provided view doesn't support mouse listener")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ mDragSourceHelper = [[DragSourceHelper alloc] initWithDragSource: this];
+
+ if (mDragSourceHelper == nil)
+ {
+ throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Cannot initialize DragSource")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ [(id <MouseEventListener>)mView registerMouseEventListener: mDragSourceHelper];
+}
+
+
+//----------------------------------------------------
+// XDragSource
+//----------------------------------------------------
+
+sal_Bool SAL_CALL DragSource::isDragImageSupported( )
+ throw(RuntimeException)
+{
+ return true;
+}
+
+
+sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ )
+ throw( IllegalArgumentException, RuntimeException)
+{
+ return 0;
+}
+
+
+void SAL_CALL DragSource::startDrag(const DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32 cursor,
+ sal_Int32 image,
+ const Reference<XTransferable >& transferable,
+ const Reference<XDragSourceListener >& listener )
+ throw( RuntimeException)
+{
+ MutexGuard guard(m_aMutex);
+
+ OSL_ASSERT(listener.is() && "DragSource::startDrag: No XDragSourceListener provided\n");
+ OSL_ASSERT(transferable.is() && "DragSource::startDrag: No transferable provided\n");
+
+ trigger.Event >>= mMouseEvent;
+ m_MouseButton= mMouseEvent.Buttons;
+ mXDragSrcListener = listener;
+ mXCurrentContext = static_cast<XDragSourceContext*>(new DragSourceContext(this));
+ auto_ptr<AquaClipboard> clipb(new AquaClipboard(NULL, false));
+ g_XTransferable = transferable;
+ clipb->setContents(g_XTransferable, Reference<XClipboardOwner>());
+ mDragSourceActions = sourceActions;
+ g_DragSourceView = mView;
+
+ NSSize sz;
+ sz.width = 5;
+ sz.height = 5;
+
+ NSImage* dragImage;
+ dragImage = [[NSImage alloc] initWithSize: sz];
+
+ NSRect bounds;
+ bounds.origin = NSMakePoint(0,0);
+ bounds.size = sz;
+
+ [dragImage lockFocus];
+ [[NSColor blackColor] set];
+ [NSBezierPath fillRect: bounds];
+ [dragImage unlockFocus];
+
+ NSPoint pInWnd = [mLastMouseEventBeforeStartDrag locationInWindow];
+ NSPoint p;
+ p = [mView convertPoint: pInWnd fromView: nil];
+ p.x = p.x - sz.width/2;
+ p.y = p.y - sz.height/2;
+
+ // reset drop success flags
+ g_DropSuccessSet = false;
+ g_DropSuccess = false;
+
+ [mView dragImage: dragImage
+ at: p
+ offset: NSMakeSize(0,0)
+ event: mLastMouseEventBeforeStartDrag
+ pasteboard: clipb->getPasteboard()
+ source: mDragSourceHelper
+ slideBack: 1];
+
+ [dragImage release];
+
+ g_XTransferable = Reference<XTransferable>();
+ g_DragSourceView = nil;
+
+ // reset drop success flags
+ g_DropSuccessSet = false;
+ g_DropSuccess = false;
+}
+
+
+// In order to initiate a D&D operation we need to
+// provide the triggering mouse event which we get
+// from the SalFrameView that is associated with
+// this DragSource
+void DragSource::saveMouseEvent(NSEvent* theEvent)
+{
+ if (mLastMouseEventBeforeStartDrag != nil)
+ {
+ [mLastMouseEventBeforeStartDrag release];
+ }
+
+ mLastMouseEventBeforeStartDrag = theEvent;
+}
+
+
+/* isLocal indicates whether or not the DnD operation is OOo
+ internal.
+ */
+unsigned int DragSource::getSupportedDragOperations(bool isLocal) const
+{
+ unsigned int srcActions = OfficeToSystemDragActions(mDragSourceActions);
+
+ if (isLocal)
+ {
+ // Support NSDragOperation generic which means we can
+ // decide which D&D operation to choose. We map
+ // NSDragOperationGenric to DNDConstants::ACTION_DEFAULT
+ // in SystemToOfficeDragActions to signal this and
+ // use it in DropTarget::determineDropAction
+ srcActions |= NSDragOperationGeneric;
+ }
+ else
+ {
+ // Mask out link and move operations on external DnD
+ srcActions &= ~(NSDragOperationMove | NSDragOperationLink);
+ }
+
+ return srcActions;
+}
+
+
+//################################
+// XServiceInfo
+//################################
+
+OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException)
+{
+ return dragSource_getImplementationName();
+}
+
+
+sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) throw (RuntimeException)
+{
+ return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource")));
+}
+
+
+Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames() throw (RuntimeException)
+{
+ return dragSource_getSupportedServiceNames();
+}
+
+
+
+
diff --git a/vcl/aqua/source/dtrans/DragSource.hxx b/vcl/aqua/source/dtrans/DragSource.hxx
new file mode 100644
index 000000000000..5d02b9874149
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSource.hxx
@@ -0,0 +1,140 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DRAGSOURCE_HXX_
+#define _DRAGSOURCE_HXX_
+
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <cppuhelper/compbase3.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <osl/thread.h>
+#include <com/sun/star/awt/MouseEvent.hpp>
+
+#include <boost/utility.hpp>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+
+class DragSource;
+
+/* The functions declared in this protocol are actually
+ declared in vcl/aqua/inc/salframe.h. Because we want
+ to avoid importing VCL headers in UNO services and
+ on the other hand want to avoid warnings caused by
+ gcc complaining about unknowness of these functions
+ we declare them in a protocol here and cast at the
+ appropriate places.
+*/
+@protocol MouseEventListener
+-(void)registerMouseEventListener:(id)theHandler;
+-(void)unregisterMouseEventListener:(id)theHandler;
+@end
+
+
+@interface DragSourceHelper : NSObject
+{
+ DragSource* mDragSource;
+}
+
+-(DragSourceHelper*)initWithDragSource: (DragSource*) pds;
+
+-(void)mouseDown: (NSEvent*)theEvent;
+-(void)mouseDragged: (NSEvent*)theEvent;
+
+-(unsigned int)draggingSourceOperationMaskForLocal:(MacOSBOOL)isLocal;
+-(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint;
+-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation;
+-(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint;
+
+@end
+
+
+class DragSource : public ::cppu::BaseMutex,
+ public ::cppu::WeakComponentImplHelper3< com::sun::star::datatransfer::dnd::XDragSource,
+ com::sun::star::lang::XInitialization,
+ com::sun::star::lang::XServiceInfo >,
+ private ::boost::noncopyable
+{
+public:
+ DragSource();
+ virtual ~DragSource();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArguments )
+ throw(com::sun::star::uno::Exception/*, com::sun::star::uno::RuntimeException*/);
+
+ // XDragSource
+ virtual sal_Bool SAL_CALL isDragImageSupported( ) throw(com::sun::star::uno::RuntimeException);
+
+ virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction)
+ throw(com::sun::star::lang::IllegalArgumentException, com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL startDrag( const com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32 cursor,
+ sal_Int32 image,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable >& transferable,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceListener >& listener )
+ throw(com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual rtl::OUString SAL_CALL getImplementationName() throw (com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService(const rtl::OUString& ServiceName) throw (com::sun::star::uno::RuntimeException);
+ virtual com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException);
+
+ virtual void saveMouseEvent(NSEvent* theEvent);
+ virtual unsigned int getSupportedDragOperations(bool isLocal) const;
+
+public:
+ // The context notifies the XDragSourceListeners
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceContext > mXCurrentContext;
+
+ id mView;
+ NSEvent* mLastMouseEventBeforeStartDrag;
+ DragSourceHelper* mDragSourceHelper;
+ com::sun::star::awt::MouseEvent mMouseEvent;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > mXTransferable;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceListener > mXDragSrcListener;
+ // The mouse button that set off the drag and drop operation
+ short m_MouseButton;
+ sal_Int8 mDragSourceActions;
+
+ static com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > g_XTransferable;
+ static NSView* g_DragSourceView;
+ static bool g_DropSuccessSet;
+ static bool g_DropSuccess;
+
+};
+
+
+#endif
diff --git a/vcl/aqua/source/dtrans/DragSourceContext.cxx b/vcl/aqua/source/dtrans/DragSourceContext.cxx
new file mode 100644
index 000000000000..cd70dc55c896
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSourceContext.cxx
@@ -0,0 +1,74 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+
+#include "DragSourceContext.hxx"
+#include <rtl/unload.h>
+
+
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::uno;
+using namespace cppu;
+
+DragSourceContext::DragSourceContext( DragSource* pSource) :
+ WeakComponentImplHelper1<XDragSourceContext>(m_aMutex),
+ m_pDragSource( pSource)
+{
+}
+
+DragSourceContext::~DragSourceContext()
+{
+}
+
+sal_Int32 SAL_CALL DragSourceContext::getCurrentCursor( )
+ throw( RuntimeException)
+{
+ return 0;
+}
+
+void SAL_CALL DragSourceContext::setCursor( sal_Int32 /*cursorId*/ )
+ throw( RuntimeException)
+{
+}
+
+void SAL_CALL DragSourceContext::setImage( sal_Int32 /*imageId*/ )
+ throw( RuntimeException)
+{
+}
+
+void SAL_CALL DragSourceContext::transferablesFlavorsChanged( )
+ throw( RuntimeException)
+{
+}
+
+
diff --git a/vcl/aqua/source/dtrans/DragSourceContext.hxx b/vcl/aqua/source/dtrans/DragSourceContext.hxx
new file mode 100644
index 000000000000..5d84c165d851
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSourceContext.hxx
@@ -0,0 +1,72 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DRAGSOURCECONTEXT_HXX_
+#define _DRAGSOURCECONTEXT_HXX_
+
+#include <cppuhelper/implbase1.hxx>
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <boost/utility.hpp>
+
+#include "DragSource.hxx"
+
+// This class fires events to XDragSourceListener implementations.
+// Of that interface only dragDropEnd and dropActionChanged are called.
+// The functions dragEnter, dragExit and dragOver are not supported
+// currently.
+// An instance of SourceContext only lives as long as the drag and drop
+// operation lasts.
+class DragSourceContext: public cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper1<com::sun::star::datatransfer::dnd::XDragSourceContext>,
+ private ::boost::noncopyable
+{
+public:
+ DragSourceContext(DragSource* pSource);
+ ~DragSourceContext();
+
+ virtual sal_Int32 SAL_CALL getCurrentCursor( )
+ throw( com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL setCursor( sal_Int32 cursorId )
+ throw( com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL setImage( sal_Int32 imageId )
+ throw( com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL transferablesFlavorsChanged( )
+ throw( com::sun::star::uno::RuntimeException);
+
+private:
+ DragSource* m_pDragSource;
+};
+
+
+
+#endif
diff --git a/vcl/aqua/source/dtrans/DropTarget.cxx b/vcl/aqua/source/dtrans/DropTarget.cxx
new file mode 100644
index 000000000000..c928d66e156d
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DropTarget.cxx
@@ -0,0 +1,599 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
+#include <rtl/unload.h>
+
+#ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED
+#include "comphelper/makesequence.hxx"
+#endif
+#include <cppuhelper/interfacecontainer.hxx>
+
+#include "aqua_clipboard.hxx"
+#include "DropTarget.hxx"
+#include "DragActionConversion.hxx"
+
+#include "DragSource.hxx"
+
+#include <rtl/ustring.h>
+#include <stdio.h>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <postmac.h>
+
+
+using namespace rtl;
+using namespace cppu;
+using namespace osl;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace comphelper;
+
+OUString dropTarget_getImplementationName()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"));
+}
+
+
+Sequence<OUString> dropTarget_getSupportedServiceNames()
+{
+ return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
+}
+
+
+namespace /* private */
+{
+ // Cocoa's coordinate system has its origin lower-left, VCL's
+ // coordinate system upper-left hence we need to transform
+ // coordinates
+
+ inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds)
+ {
+ rPoint.y = bounds.size.height - rPoint.y;
+ }
+
+ inline void CocoaToVCL(NSRect& rRect, const NSRect& bounds)
+ {
+ rRect.origin.y = bounds.size.height - (rRect.origin.y + rRect.size.height);
+ }
+}
+
+
+@implementation DropTargetHelper
+
+
+-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt
+{
+ self = [super init];
+
+ if (self)
+ {
+ mDropTarget = pdt;
+ }
+
+ return self;
+}
+
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->draggingEntered(sender);
+}
+
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->draggingUpdated(sender);
+}
+
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ mDropTarget->draggingExited(sender);
+}
+
+
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->prepareForDragOperation(sender);
+}
+
+
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->performDragOperation(sender);
+}
+
+
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
+{
+ mDropTarget->concludeDragOperation(sender);
+}
+
+
+@end
+
+
+DropTarget::DropTarget() :
+ WeakComponentImplHelper5<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(m_aMutex),
+ mDropTargetHelper(nil),
+ mbActive(false),
+ mDragSourceSupportedActions(DNDConstants::ACTION_NONE),
+ mSelectedDropAction(DNDConstants::ACTION_NONE),
+ mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE | DNDConstants::ACTION_LINK | DNDConstants::ACTION_DEFAULT)
+{
+ mDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper());
+}
+
+
+DropTarget::~DropTarget()
+{
+ [(id <DraggingDestinationHandler>)mView unregisterDraggingDestinationHandler:mDropTargetHelper];
+ [mDropTargetHelper release];
+}
+
+
+sal_Int8 DropTarget::determineDropAction(sal_Int8 dropActions, id sender) const
+{
+ sal_Int8 dropAct = dropActions;
+ bool srcAndDestEqual = false;
+
+ if ([sender draggingSource] != nil)
+ {
+ // Internal DnD
+ NSView* destView = [[sender draggingDestinationWindow] contentView];
+ srcAndDestEqual = (DragSource::g_DragSourceView == destView);
+ }
+
+ // If ACTION_DEFAULT is set this means NSDragOperationGeneric
+ // has been set and we map this to ACTION_MOVE or ACTION_COPY
+ // depending on whether or not source and dest are equal,
+ // this hopefully satisfies all parties
+ if( (dropActions == DNDConstants::ACTION_DEFAULT)
+ || ((dropActions == mDragSourceSupportedActions)
+ && !(~mDragSourceSupportedActions & DNDConstants::ACTION_COPY_OR_MOVE ) ) )
+ {
+ dropAct = srcAndDestEqual ? DNDConstants::ACTION_MOVE :
+ DNDConstants::ACTION_COPY;
+ }
+ // if more than one drop actions have been specified
+ // set ACTION_DEFAULT in order to let the drop target
+ // decide which one to use
+ else if (dropActions != DNDConstants::ACTION_NONE &&
+ dropActions != DNDConstants::ACTION_MOVE &&
+ dropActions != DNDConstants::ACTION_COPY &&
+ dropActions != DNDConstants::ACTION_LINK)
+ {
+ if (srcAndDestEqual)
+ {
+ dropAct = dropActions;
+ }
+ else // source and destination are different
+ {
+ if (dropActions & DNDConstants::ACTION_COPY)
+ dropAct = DNDConstants::ACTION_COPY;
+ else if (dropActions & DNDConstants::ACTION_MOVE)
+ dropAct = DNDConstants::ACTION_MOVE;
+ else if (dropActions & DNDConstants::ACTION_LINK)
+ dropAct = DNDConstants::ACTION_LINK;
+ }
+
+ dropAct |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ return dropAct;
+}
+
+
+NSDragOperation DropTarget::draggingEntered(id sender)
+{
+ // Initially when DnD will be started no modifier key can be pressed yet
+ // thus we are getting all actions that the drag source supports, we save
+ // this value because later the system masks the drag source actions if
+ // a modifier key will be pressed
+ mDragSourceSupportedActions = SystemToOfficeDragActions([sender draggingSourceOperationMask]);
+
+ // Only if the drop target is really interessted in the drag actions
+ // supported by the source
+ if (mDragSourceSupportedActions & mDefaultActions)
+ {
+ sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender);
+
+ NSRect bounds = [mView bounds];
+ NSPoint dragLocation = [sender draggedImageLocation];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ NSPasteboard* dragPboard = [sender draggingPasteboard];
+ mXCurrentDragClipboard = new AquaClipboard(dragPboard, false);
+
+ Reference<XTransferable> xTransferable = DragSource::g_XTransferable.is() ?
+ DragSource::g_XTransferable : mXCurrentDragClipboard->getContents();
+
+ DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ currentAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions,
+ xTransferable->getTransferDataFlavors());
+
+ fire_dragEnter(dtdee);
+ }
+
+ return OfficeToSystemDragActions(mSelectedDropAction);
+}
+
+
+NSDragOperation DropTarget::draggingUpdated(id sender)
+{
+ sal_Int8 currentDragSourceActions =
+ SystemToOfficeDragActions([sender draggingSourceOperationMask]);
+ NSDragOperation dragOp = NSDragOperationNone;
+
+ if (currentDragSourceActions & mDefaultActions)
+ {
+ sal_Int8 currentAction = determineDropAction(currentDragSourceActions, sender);
+ NSRect bounds = [mView bounds];
+ NSPoint dragLocation = [sender draggedImageLocation];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ DropTargetDragEvent dtde(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ currentAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions);
+
+ fire_dragOver(dtde);
+
+ // drag over callbacks likely have rendered something
+ [mView setNeedsDisplay: TRUE];
+
+ dragOp = OfficeToSystemDragActions(mSelectedDropAction);
+
+ //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
+ }
+
+ // Weird but it appears as if there is no method in Cocoa
+ // to create a kThemeCopyArrowCursor hence we have to use
+ // Carbon to do it
+ if (dragOp == NSDragOperationNone)
+ SetThemeCursor(kThemeNotAllowedCursor);
+ else if (dragOp == NSDragOperationCopy)
+ SetThemeCursor(kThemeCopyArrowCursor);
+ else
+ SetThemeCursor(kThemeArrowCursor);
+
+ return dragOp;
+}
+
+
+ void DropTarget::draggingExited(id sender)
+ {
+ DropTargetEvent dte(static_cast<OWeakObject*>(this), 0);
+ fire_dragExit(dte);
+ mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ SetThemeCursor(kThemeArrowCursor);
+ }
+
+
+ MacOSBOOL DropTarget::prepareForDragOperation(id sender)
+ {
+ return 1;
+ }
+
+
+MacOSBOOL DropTarget::performDragOperation(id sender)
+{
+ bool bSuccess = false;
+
+ if (mSelectedDropAction != DNDConstants::ACTION_NONE)
+ {
+ Reference<XTransferable> xTransferable = DragSource::g_XTransferable;
+
+ if (!DragSource::g_XTransferable.is())
+ {
+ xTransferable = mXCurrentDragClipboard->getContents();
+ }
+
+ NSRect bounds = [mView bounds];
+ NSPoint dragLocation = [sender draggedImageLocation];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ DropTargetDropEvent dtde(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ mSelectedDropAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions,
+ xTransferable);
+
+ fire_drop(dtde);
+
+ bSuccess = true;
+ }
+
+ return bSuccess;
+}
+
+
+ void DropTarget::concludeDragOperation(id sender)
+ {
+ mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ mXCurrentDragClipboard = Reference<XClipboard>();
+ SetThemeCursor(kThemeArrowCursor);
+ }
+
+
+ // called from WeakComponentImplHelperX::dispose
+ // WeakComponentImplHelper calls disposing before it destroys
+ // itself.
+ void SAL_CALL DropTarget::disposing()
+ {
+ }
+
+
+ void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments)
+ throw(Exception)
+ {
+ if (aArguments.getLength() < 2)
+ {
+ throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ Any pNSView = aArguments[0];
+ sal_uInt64 tmp = 0;
+ pNSView >>= tmp;
+ mView = (id)tmp;
+
+ mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this];
+
+ [(id <DraggingDestinationHandler>)mView registerDraggingDestinationHandler:mDropTargetHelper];
+ [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()];
+
+ id wnd = [mView window];
+ NSWindow* parentWnd = [wnd parentWindow];
+ unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask);
+ unsigned int wndStyles = [wnd styleMask] & topWndStyle;
+
+ if (parentWnd == nil && (wndStyles == topWndStyle))
+ {
+ [wnd registerDraggingDestinationHandler:mDropTargetHelper];
+ [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
+ }
+ }
+
+
+ void SAL_CALL DropTarget::addDropTargetListener(const Reference<XDropTargetListener>& dtl)
+ throw(RuntimeException)
+ {
+ rBHelper.addListener(::getCppuType(&dtl), dtl);
+ }
+
+
+ void SAL_CALL DropTarget::removeDropTargetListener(const Reference<XDropTargetListener>& dtl)
+ throw(RuntimeException)
+ {
+ rBHelper.removeListener(::getCppuType(&dtl), dtl);
+ }
+
+
+ sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException)
+ {
+ return mbActive;
+ }
+
+
+ void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException)
+ {
+ mbActive = active;
+ }
+
+
+ sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException)
+ {
+ return mDefaultActions;
+ }
+
+
+ void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException)
+ {
+ OSL_ENSURE( actions < 8, "No valid default actions");
+ mDefaultActions= actions;
+ }
+
+
+ // XDropTargetDragContext
+
+ void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException)
+ {
+ mSelectedDropAction = dragOperation;
+ }
+
+
+ void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException)
+ {
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ }
+
+
+ //XDropTargetDropContext
+
+ void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException)
+ {
+ mSelectedDropAction = dropOperation;
+ }
+
+
+ void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException)
+ {
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ }
+
+
+ void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException)
+ {
+ // Reset the internal transferable used as shortcut in case this is
+ // an internal D&D operation
+ DragSource::g_XTransferable = Reference<XTransferable>();
+ DragSource::g_DropSuccessSet = true;
+ DragSource::g_DropSuccess = success;
+ }
+
+
+ void DropTarget::fire_drop( const DropTargetDropEvent& dte)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->drop( dte); }
+ catch(RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragEnter( e); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dragExit(const DropTargetEvent& dte)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragExit( dte); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer );
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragOver( dtde); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dropActionChanged( dtde); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ // XServiceInfo
+
+ OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException)
+ {
+ return dropTarget_getImplementationName();
+ }
+
+
+ sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException)
+ {
+ return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
+ }
+
+
+ Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException)
+ {
+ return dropTarget_getSupportedServiceNames();
+ }
+
diff --git a/vcl/aqua/source/dtrans/DropTarget.hxx b/vcl/aqua/source/dtrans/DropTarget.hxx
new file mode 100644
index 000000000000..6baa8bb69d01
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DropTarget.hxx
@@ -0,0 +1,169 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DROPTARGET_HXX_
+#define _DROPTARGET_HXX_
+
+#include "DataFlavorMapping.hxx"
+#include <cppuhelper/compbase5.hxx>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+
+#ifndef _COM_SUN_STAR_DATATRANSFER_DND_XDROPTARGETLISTENR_HPP_
+#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp>
+#endif
+#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <boost/utility.hpp>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+class DropTarget;
+
+/* The functions declared in this protocol are actually
+ declared in vcl/aqua/inc/salframe.h. Because we want
+ to avoid importing VCL headers in UNO services and
+ on the other hand want to avoid warnings caused by
+ gcc complaining about unknowness of these functions
+ we declare them in a protocol here and cast at the
+ appropriate places.
+*/
+@protocol DraggingDestinationHandler
+-(void)registerDraggingDestinationHandler:(id)theHandler;
+-(void)unregisterDraggingDestinationHandler:(id)theHandler;
+@end
+
+
+@interface DropTargetHelper : NSObject
+{
+ DropTarget* mDropTarget;
+}
+
+-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt;
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+-(void)draggingExited:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender;
+
+@end
+
+
+class DropTarget: public cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper5< com::sun::star::lang::XInitialization,
+ com::sun::star::datatransfer::dnd::XDropTarget,
+ com::sun::star::datatransfer::dnd::XDropTargetDragContext,
+ com::sun::star::datatransfer::dnd::XDropTargetDropContext,
+ com::sun::star::lang::XServiceInfo >,
+ private boost::noncopyable
+{
+public:
+ DropTarget();
+ virtual ~DropTarget();
+
+ // Overrides WeakComponentImplHelper::disposing which is called by
+ // WeakComponentImplHelper::dispose
+ // Must be called.
+ virtual void SAL_CALL disposing();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArguments )
+ throw(com::sun::star::uno::Exception);
+
+ // XDropTarget
+ virtual void SAL_CALL addDropTargetListener( const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl )
+ throw(com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL removeDropTargetListener( const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl )
+ throw(com::sun::star::uno::RuntimeException);
+
+ // Default is not active
+ virtual sal_Bool SAL_CALL isActive() throw(com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setActive(sal_Bool isActive) throw(com::sun::star::uno::RuntimeException);
+ virtual sal_Int8 SAL_CALL getDefaultActions() throw(com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setDefaultActions(sal_Int8 actions) throw(com::sun::star::uno::RuntimeException);
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) throw(com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL rejectDrag() throw(com::sun::star::uno::RuntimeException);
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) throw (com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL rejectDrop() throw (com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL dropComplete(sal_Bool success) throw (com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual rtl::OUString SAL_CALL getImplementationName() throw (com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService(const rtl::OUString& ServiceName) throw (com::sun::star::uno::RuntimeException);
+ virtual com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException);
+
+ // NSDraggingDestination protocol functions
+ virtual NSDragOperation draggingEntered(id sender);
+ virtual NSDragOperation draggingUpdated(id sender);
+ virtual void draggingExited(id sender);
+ virtual MacOSBOOL prepareForDragOperation(id sender);
+ virtual MacOSBOOL performDragOperation(id sender);
+ virtual void concludeDragOperation(id sender);
+
+ /* If multiple actions are supported by the drag source and
+ the user did not choose a specific action by pressing a
+ modifier key choose a default action to be proposed to
+ the application.
+ */
+ sal_Int8 determineDropAction(sal_Int8 dropActions, id sender) const;
+
+private:
+ void fire_drop(const com::sun::star::datatransfer::dnd::DropTargetDropEvent& dte);
+ void fire_dragEnter(const com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee);
+ void fire_dragExit(const com::sun::star::datatransfer::dnd::DropTargetEvent& dte);
+ void fire_dragOver(const com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde);
+ void fire_dropActionChanged(const com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde);
+
+private:
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetDragContext > mXCurrentDragContext;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetDropContext > mXCurrentDropContext;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::clipboard::XClipboard > mXCurrentDragClipboard;
+ DataFlavorMapperPtr_t mDataFlavorMapper;
+ id mView;
+ DropTargetHelper* mDropTargetHelper;
+ bool mbActive;
+ sal_Int8 mDragSourceSupportedActions;
+ sal_Int8 mSelectedDropAction;
+ sal_Int8 mDefaultActions;
+};
+
+#endif
diff --git a/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx b/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx
new file mode 100644
index 000000000000..3f558b0a5b4f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx
@@ -0,0 +1,147 @@
+#include "HtmlFmtFlt.hxx"
+
+#include <rtl/string.h>
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <iomanip>
+
+#include <boost/assert.hpp>
+
+using namespace com::sun::star::uno;
+
+//------------------------------------------------------------------------------
+// converts the openoffice text/html clipboard format to the HTML Format
+// well known under MS Windows
+// the MS HTML Format has a header before the real html data
+//
+// Version:1.0 Version number of the clipboard. Staring is 0.9
+// StartHTML: Byte count from the beginning of the clipboard to the start
+// of the context, or -1 if no context
+// EndHTML: Byte count from the beginning of the clipboard to the end
+// of the context, or -1 if no context
+// StartFragment: Byte count from the beginning of the clipboard to the
+// start of the fragment
+// EndFragment: Byte count from the beginning of the clipboard to the
+// end of the fragment
+// StartSelection: Byte count from the beginning of the clipboard to the
+// start of the selection
+// EndSelection: Byte count from the beginning of the clipboard to the
+// end of the selection
+//
+// StartSelection and EndSelection are optional
+// The fragment should be preceded and followed by the HTML comments
+// <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the
+// text
+//------------------------------------------------------------------------------
+
+namespace // private
+{
+std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment)
+{
+ std::ostringstream htmlHeader;
+ htmlHeader << "Version:1.0" << '\r' << '\n';
+ htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n';
+ htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n';
+ htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n';
+ htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n';
+ return htmlHeader.str();
+}
+
+} // namespace private
+
+
+// the office allways writes the start and end html tag in upper cases and
+// without spaces both tags don't allow parameters
+const std::string TAG_HTML = std::string("<HTML>");
+const std::string TAG_END_HTML = std::string("</HTML>");
+
+// The body tag may have parameters so we need to search for the
+// closing '>' manually e.g. <BODY param> #92840#
+const std::string TAG_BODY = std::string("<BODY");
+const std::string TAG_END_BODY = std::string("</BODY");
+
+Sequence<sal_Int8> SAL_CALL TextHtmlToHTMLFormat(Sequence<sal_Int8>& aTextHtml)
+{
+ OSL_ASSERT(aTextHtml.getLength() > 0);
+
+ if (!(aTextHtml.getLength() > 0))
+ return Sequence<sal_Int8>();
+
+ // fill the buffer with dummy values to calc the exact length
+ std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0);
+ size_t lHtmlFormatHeader = dummyHtmlHeader.length();
+
+ std::string textHtml(
+ reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()),
+ reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()) + aTextHtml.getLength());
+
+ std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so
+ std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
+
+ // The body tag may have parameters so we need to search for the
+ // closing '>' manually e.g. <BODY param> #92840#
+ std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1;
+ std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader;
+
+ std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment);
+ htmlFormat += textHtml;
+
+ Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0'
+ rtl_zeroMemory(byteSequence.getArray(), byteSequence.getLength());
+
+ rtl_copyMemory(
+ static_cast<void*>(byteSequence.getArray()),
+ static_cast<const void*>(htmlFormat.c_str()),
+ htmlFormat.length());
+
+ return byteSequence;
+}
+
+const char* HtmlStartTag = "<html";
+
+Sequence<sal_Int8> HTMLFormatToTextHtml(const Sequence<sal_Int8>& aHTMLFormat)
+{
+ BOOST_ASSERT(isHTMLFormat(aHTMLFormat) && "No HTML Format provided");
+
+ Sequence<sal_Int8>& nonconstHTMLFormatRef = const_cast< Sequence<sal_Int8>& >(aHTMLFormat);
+ sal_Char* dataStart = reinterpret_cast<sal_Char*>(nonconstHTMLFormatRef.getArray());
+ sal_Char* dataEnd = dataStart + nonconstHTMLFormatRef.getLength() - 1;
+ const sal_Char* htmlStartTag = strcasestr(dataStart, HtmlStartTag);
+
+ BOOST_ASSERT(htmlStartTag && "Seems to be no HTML at all");
+
+ // It doesn't seem to be HTML? Well then simply return what has been
+ // provided in non-debug builds
+ if (htmlStartTag == NULL)
+ {
+ return aHTMLFormat;
+ }
+
+ sal_Int32 len = dataEnd - htmlStartTag;
+ Sequence<sal_Int8> plainHtmlData(len);
+
+ rtl_copyMemory(static_cast<void*>(plainHtmlData.getArray()), htmlStartTag, len);
+
+ return plainHtmlData;
+}
+
+/* A simple format detection. We are just comparing the first few bytes
+ of the provided byte sequence to see whether or not it is the MS
+ Office Html format. If it shows that this is not reliable enough we
+ can improve this
+*/
+const char HtmlFormatStart[] = "Version:";
+int HtmlFormatStartLen = (sizeof(HtmlFormatStart) - 1);
+
+bool isHTMLFormat(const Sequence<sal_Int8>& aHtmlSequence)
+{
+ if (aHtmlSequence.getLength() < HtmlFormatStartLen)
+ return false;
+
+ return rtl_str_compareIgnoreAsciiCase_WithLength(HtmlFormatStart,
+ HtmlFormatStartLen,
+ reinterpret_cast<const sal_Char*>(aHtmlSequence.getConstArray()),
+ HtmlFormatStartLen) == 0;
+}
diff --git a/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx b/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx
new file mode 100644
index 000000000000..49f0cc70590c
--- /dev/null
+++ b/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx
@@ -0,0 +1,20 @@
+#ifndef INCLUDED_HTMLFMTFLT_HXX
+#define INCLUDED_HTMLFMTFLT_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+/* Transform plain HTML into the format expected by MS Office.
+ */
+com::sun::star::uno::Sequence<sal_Int8> TextHtmlToHTMLFormat(com::sun::star::uno::Sequence<sal_Int8>& aTextHtml);
+
+/* Transform the MS Office HTML format into plain HTML.
+ */
+com::sun::star::uno::Sequence<sal_Int8> HTMLFormatToTextHtml(const com::sun::star::uno::Sequence<sal_Int8>& aHTMLFormat);
+
+/* Detects whether the given byte sequence contains the MS Office Html format.
+
+ @returns True if the MS Office Html format will be detected False otherwise.
+ */
+bool isHTMLFormat (const com::sun::star::uno::Sequence<sal_Int8>& aHtmlSequence);
+
+#endif
diff --git a/vcl/aqua/source/dtrans/OSXTransferable.cxx b/vcl/aqua/source/dtrans/OSXTransferable.cxx
new file mode 100644
index 000000000000..2e6b327de446
--- /dev/null
+++ b/vcl/aqua/source/dtrans/OSXTransferable.cxx
@@ -0,0 +1,215 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <sal/types.h>
+
+#ifndef _TRANSFERABLE_HXX_
+#include "OSXTransferable.hxx"
+#endif
+
+#include "DataFlavorMapping.hxx"
+
+using namespace rtl;
+using namespace std;
+using namespace osl;
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::io;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::container;
+
+const Type CPPUTYPE_SEQINT8 = getCppuType((Sequence<sal_Int8>*)0);
+const Type CPPUTYPE_OUSTRING = getCppuType((OUString*)0);
+
+namespace // private
+{
+ bool isValidFlavor( const DataFlavor& aFlavor )
+ {
+ size_t len = aFlavor.MimeType.getLength();
+ Type dtype = aFlavor.DataType;
+ return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING)));
+ }
+
+} // namespace private
+
+
+OSXTransferable::OSXTransferable(const Reference<XMimeContentTypeFactory> rXMimeCntFactory,
+ DataFlavorMapperPtr_t pDataFlavorMapper,
+ NSPasteboard* pasteboard) :
+ mrXMimeCntFactory(rXMimeCntFactory),
+ mDataFlavorMapper(pDataFlavorMapper),
+ mPasteboard(pasteboard)
+{
+ [mPasteboard retain];
+
+ initClipboardItemList();
+}
+
+
+OSXTransferable::~OSXTransferable()
+{
+ [mPasteboard release];
+}
+
+
+Any SAL_CALL OSXTransferable::getTransferData( const DataFlavor& aFlavor )
+ throw( UnsupportedFlavorException, IOException, RuntimeException )
+{
+ if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor))
+ {
+ throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
+ static_cast<XTransferable*>(this));
+ }
+
+ NSString* sysFormat =
+ (aFlavor.MimeType.compareToAscii( "image/bmp", 9 ) == 0)
+ ? mDataFlavorMapper->openOfficeImageToSystemFlavor( mPasteboard )
+ : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor);
+ DataProviderPtr_t dp;
+
+ if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
+ {
+ NSArray* sysData = [mPasteboard propertyListForType: sysFormat];
+ dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
+ }
+ else
+ {
+ NSData* sysData = [mPasteboard dataForType: sysFormat];
+ dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
+ }
+
+ if (dp.get() == NULL)
+ {
+ throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
+ static_cast<XTransferable*>(this));
+ }
+
+ return dp->getOOoData();
+}
+
+
+bool OSXTransferable::isUnicodeText(const DataFlavor& flavor)
+{
+ return (flavor.DataType == CPPUTYPE_OUSTRING);
+}
+
+
+Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors( )
+ throw( RuntimeException )
+{
+ return mFlavorList;
+}
+
+
+sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor)
+ throw( RuntimeException )
+{
+ for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++)
+ if (compareDataFlavors(aFlavor, mFlavorList[i]))
+ return sal_True;
+
+ return sal_False;
+}
+
+
+void OSXTransferable::initClipboardItemList()
+{
+ NSArray* pboardFormats = [mPasteboard types];
+
+ if (pboardFormats == NULL)
+ {
+ throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot get clipboard data")),
+ static_cast<XTransferable*>(this));
+ }
+
+ mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats);
+}
+
+
+/* Compares two DataFlavors. Returns true if both DataFlavor have the same media type
+ and the number of parameter and all parameter values do match otherwise false
+ is returned.
+ */
+bool OSXTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs )
+{
+ try
+ {
+ Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType));
+ Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType));
+
+ if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) ||
+ !cmpAllContentTypeParameter(xLhs, xRhs))
+ {
+ return false;
+ }
+ }
+ catch( IllegalArgumentException& )
+ {
+ OSL_ENSURE( sal_False, "Invalid content type detected" );
+ return false;
+ }
+
+ return true;
+}
+
+
+bool OSXTransferable::cmpAllContentTypeParameter(const Reference<XMimeContentType> xLhs,
+ const Reference<XMimeContentType> xRhs) const
+{
+ Sequence<OUString> xLhsFlavors = xLhs->getParameters();
+ Sequence<OUString> xRhsFlavors = xRhs->getParameters();
+
+ // Stop here if the number of parameters is different already
+ if (xLhsFlavors.getLength() != xRhsFlavors.getLength())
+ return false;
+
+ try
+ {
+ OUString pLhs;
+ OUString pRhs;
+
+ for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++)
+ {
+ pLhs = xLhs->getParameterValue(xLhsFlavors[i]);
+ pRhs = xRhs->getParameterValue(xLhsFlavors[i]);
+
+ if (!pLhs.equalsIgnoreAsciiCase(pRhs))
+ {
+ return false;
+ }
+ }
+ }
+ catch(IllegalArgumentException&)
+ {
+ return false;
+ }
+
+ return true;
+}
diff --git a/vcl/aqua/source/dtrans/OSXTransferable.hxx b/vcl/aqua/source/dtrans/OSXTransferable.hxx
new file mode 100644
index 000000000000..6601905f1610
--- /dev/null
+++ b/vcl/aqua/source/dtrans/OSXTransferable.hxx
@@ -0,0 +1,100 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+#ifndef _TRANSFERABLE_HXX_
+#define _TRANSFERABLE_HXX_
+
+//------------------------------------------------------------------------
+// includes
+//------------------------------------------------------------------------
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+
+#include "DataFlavorMapping.hxx"
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <vector>
+
+
+class OSXTransferable : public ::cppu::WeakImplHelper1<com::sun::star::datatransfer::XTransferable>,
+ private ::boost::noncopyable
+{
+public:
+ typedef com::sun::star::uno::Sequence< sal_Int8 > ByteSequence_t;
+
+ explicit OSXTransferable(com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> rXMimeCntFactory,
+ DataFlavorMapperPtr_t pDataFlavorMapper,
+ NSPasteboard* pasteboard);
+
+ virtual ~OSXTransferable();
+
+ //------------------------------------------------------------------------
+ // XTransferable
+ //------------------------------------------------------------------------
+
+ virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw( ::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException );
+
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------------------------------
+ // Helper functions not part of the XTransferable interface
+ //------------------------------------------------------------------------
+
+ void initClipboardItemList();
+
+ //com::sun::star::uno::Any getClipboardItemData(ClipboardItemPtr_t clipboardItem);
+
+ bool isUnicodeText(const com::sun::star::datatransfer::DataFlavor& flavor);
+
+ bool compareDataFlavors( const com::sun::star::datatransfer::DataFlavor& lhs,
+ const com::sun::star::datatransfer::DataFlavor& rhs );
+
+ bool cmpAllContentTypeParameter( const com::sun::star::uno::Reference< com::sun::star::datatransfer::XMimeContentType > xLhs,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::XMimeContentType > xRhs ) const;
+
+private:
+ com::sun::star::uno::Sequence< com::sun::star::datatransfer::DataFlavor > mFlavorList;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory;
+ DataFlavorMapperPtr_t mDataFlavorMapper;
+ NSPasteboard* mPasteboard;
+};
+
+#endif
diff --git a/vcl/aqua/source/dtrans/PictToBmpFlt.cxx b/vcl/aqua/source/dtrans/PictToBmpFlt.cxx
new file mode 100644
index 000000000000..1410fc2bd66d
--- /dev/null
+++ b/vcl/aqua/source/dtrans/PictToBmpFlt.cxx
@@ -0,0 +1,201 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: OSXTransferable.hxx,v $
+ * $Revision: 1.4 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/* This is a work-around to prevent 'deprecated' warning for 'KillPicture' API
+ Hopefully we can get rid of this whole code again when the OOo PICT filter
+ are good enough to be used see #i78953 thus this hack would vanish to again.
+ */
+#include <premac.h>
+#include <AvailabilityMacros.h>
+#undef DEPRECATED_ATTRIBUTE
+#define DEPRECATED_ATTRIBUTE
+
+#include <Carbon/Carbon.h>
+#include <QuickTime/QuickTime.h>
+#include <postmac.h>
+
+#include "PictToBmpFlt.hxx"
+
+bool PICTtoBMP(com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp)
+{
+
+ bool result = false;
+
+ ComponentInstance bmpExporter;
+ if (OpenADefaultComponent(GraphicsExporterComponentType,
+ kQTFileTypeBMP,
+ &bmpExporter) != noErr)
+ {
+ return result;
+ }
+
+ Handle hPict;
+ if (PtrToHand(aPict.getArray(), &hPict, aPict.getLength()) != noErr)
+ {
+ return result;
+ }
+
+ Handle hBmp;
+ if ((GraphicsExportSetInputPicture(bmpExporter, (PicHandle)hPict) != noErr) ||
+ ((hBmp = NewHandleClear(0)) == NULL))
+ {
+ CloseComponent(bmpExporter);
+ DisposeHandle(hPict);
+ return result;
+ }
+
+ if ((GraphicsExportSetOutputHandle(bmpExporter, hBmp) == noErr) &&
+ (GraphicsExportDoExport(bmpExporter, NULL) == noErr))
+ {
+ size_t sz = GetHandleSize(hBmp);
+ aBmp.realloc(sz);
+
+ HLock(hBmp);
+ rtl_copyMemory(aBmp.getArray(), ((sal_Int8*)*hBmp), sz);
+ HUnlock(hBmp);
+
+ result = true;
+ }
+
+ DisposeHandle(hPict);
+ DisposeHandle(hBmp);
+ CloseComponent(bmpExporter);
+
+ return result;
+}
+
+bool BMPtoPICT(com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict)
+{
+ bool result = false;
+
+ Handle hBmp;
+ ComponentInstance pictExporter;
+ if ((PtrToHand(aBmp.getArray(), &hBmp, aBmp.getLength()) != noErr))
+ {
+ return result;
+ }
+
+ if (OpenADefaultComponent(GraphicsImporterComponentType,
+ kQTFileTypeBMP,
+ &pictExporter) != noErr)
+ {
+ DisposeHandle(hBmp);
+ return result;
+ }
+
+ if (GraphicsImportSetDataHandle(pictExporter, hBmp) != noErr)
+ {
+ DisposeHandle(hBmp);
+ CloseComponent(pictExporter);
+ return result;
+ }
+
+ PicHandle hPict;
+ if (GraphicsImportGetAsPicture(pictExporter, &hPict) == noErr)
+ {
+ size_t sz = GetHandleSize((Handle)hPict);
+ aPict.realloc(sz);
+
+ HLock((Handle)hPict);
+ rtl_copyMemory(aPict.getArray(), ((sal_Int8*)*hPict), sz);
+ HUnlock((Handle)hPict);
+
+ // Release the data associated with the picture
+ // Note: This function is deprecated in Mac OS X
+ // 10.4.
+ KillPicture(hPict);
+
+ result = true;
+ }
+
+ DisposeHandle(hBmp);
+ CloseComponent(pictExporter);
+
+ return result;
+}
+
+bool ImageToBMP( com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ NSBitmapImageFileType eInFormat)
+{
+ if( eInFormat == PICTImageFileType )
+ return PICTtoBMP( aPict, aBmp );
+
+ bool bResult = false;
+
+ NSData* pData = [NSData dataWithBytesNoCopy: (void*)aPict.getConstArray() length: aPict.getLength() freeWhenDone: 0];
+ if( pData )
+ {
+ NSBitmapImageRep* pRep = [NSBitmapImageRep imageRepWithData: pData];
+ if( pRep )
+ {
+ NSData* pOut = [pRep representationUsingType: NSBMPFileType properties: nil];
+ if( pOut )
+ {
+ aBmp.realloc( [pOut length] );
+ [pOut getBytes: aBmp.getArray() length: aBmp.getLength()];
+ bResult = (aBmp.getLength() != 0);
+ }
+ }
+ }
+
+ return bResult;
+}
+
+bool BMPToImage( com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ NSBitmapImageFileType eOutFormat
+ )
+{
+ if( eOutFormat == PICTImageFileType )
+ return BMPtoPICT( aBmp, aPict );
+
+ bool bResult = false;
+
+ NSData* pData = [NSData dataWithBytesNoCopy: const_cast<sal_Int8*>(aBmp.getConstArray()) length: aBmp.getLength() freeWhenDone: 0];
+ if( pData )
+ {
+ NSBitmapImageRep* pRep = [NSBitmapImageRep imageRepWithData: pData];
+ if( pRep )
+ {
+ NSData* pOut = [pRep representationUsingType: eOutFormat properties: nil];
+ if( pOut )
+ {
+ aPict.realloc( [pOut length] );
+ [pOut getBytes: aPict.getArray() length: aPict.getLength()];
+ bResult = (aPict.getLength() != 0);
+ }
+ }
+ }
+
+ return bResult;
+}
diff --git a/vcl/aqua/source/dtrans/PictToBmpFlt.hxx b/vcl/aqua/source/dtrans/PictToBmpFlt.hxx
new file mode 100644
index 000000000000..12a73452ad7b
--- /dev/null
+++ b/vcl/aqua/source/dtrans/PictToBmpFlt.hxx
@@ -0,0 +1,37 @@
+#ifndef INCLUDED_PICTTOBMPFLT_HXX
+#define INCLUDED_PICTTOBMPFLT_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <premac.h>
+#include <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+/* Transform PICT into the a Window BMP.
+
+ Returns true if the conversion was successful false
+ otherwise.
+ */
+bool PICTtoBMP(com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp);
+
+/* Transform a Windows BMP to a PICT.
+
+ Returns true if the conversion was successful false
+ otherwise.
+ */
+bool BMPtoPICT(com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict);
+
+#define PICTImageFileType ((NSBitmapImageFileType)~0)
+
+bool ImageToBMP( com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ NSBitmapImageFileType eInFormat);
+
+bool BMPToImage( com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ NSBitmapImageFileType eOutFormat
+ );
+
+#endif
diff --git a/vcl/aqua/source/dtrans/aqua_clipboard.cxx b/vcl/aqua/source/dtrans/aqua_clipboard.cxx
new file mode 100644
index 000000000000..52fb13e1e11f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/aqua_clipboard.cxx
@@ -0,0 +1,387 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include "aqua_clipboard.hxx"
+
+#include "DataFlavorMapping.hxx"
+#include "OSXTransferable.hxx"
+
+#include "vcl/unohelp.hxx"
+
+#include "comphelper/makesequence.hxx"
+
+#include <boost/assert.hpp>
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace cppu;
+using namespace osl;
+using namespace rtl;
+using namespace std;
+using namespace comphelper;
+
+
+@implementation EventListener;
+
+-(EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb
+{
+ self = [super init];
+
+ if (self)
+ pAquaClipboard = pcb;
+
+ return self;
+}
+
+-(void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type
+{
+ if( pAquaClipboard )
+ pAquaClipboard->provideDataForType(sender, type);
+}
+
+-(void)applicationDidBecomeActive:(NSNotification*)aNotification
+{
+ if( pAquaClipboard )
+ pAquaClipboard->applicationDidBecomeActive(aNotification);
+}
+
+-(void)disposing
+{
+ pAquaClipboard = NULL;
+}
+
+@end
+
+
+OUString clipboard_getImplementationName()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.AquaClipboard"));
+}
+
+Sequence<OUString> clipboard_getSupportedServiceNames()
+{
+ return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.SystemClipboard")));
+}
+
+
+AquaClipboard::AquaClipboard(NSPasteboard* pasteboard, bool bUseSystemPasteboard) :
+ WeakComponentImplHelper4<XClipboardEx, XClipboardNotifier, XFlushableClipboard, XServiceInfo>(m_aMutex),
+ mIsSystemPasteboard(bUseSystemPasteboard)
+{
+ Reference<XMultiServiceFactory> mrServiceMgr = vcl::unohelper::GetMultiServiceFactory();
+
+ mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceMgr->createInstance(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory"))), UNO_QUERY);
+
+ if (!mrXMimeCntFactory.is())
+ {
+ throw RuntimeException(OUString(
+ RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")),
+ static_cast<XClipboardEx*>(this));
+ }
+
+ mpDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper());
+
+ if (pasteboard != NULL)
+ {
+ mPasteboard = pasteboard;
+ mIsSystemPasteboard = false;
+ }
+ else
+ {
+ mPasteboard = bUseSystemPasteboard ? [NSPasteboard generalPasteboard] :
+ [NSPasteboard pasteboardWithName: NSDragPboard];
+
+ if (mPasteboard == nil)
+ {
+ throw RuntimeException(OUString(
+ RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create Cocoa pasteboard")),
+ static_cast<XClipboardEx*>(this));
+ }
+ }
+
+ [mPasteboard retain];
+
+ mEventListener = [[EventListener alloc] initWithAquaClipboard: this];
+
+ if (mEventListener == nil)
+ {
+ [mPasteboard release];
+
+ throw RuntimeException(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create pasteboard change listener")),
+ static_cast<XClipboardEx*>(this));
+ }
+
+ if (mIsSystemPasteboard)
+ {
+ NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
+
+ [notificationCenter addObserver: mEventListener
+ selector: @selector(applicationDidBecomeActive:)
+ name: @"NSApplicationDidBecomeActiveNotification"
+ object: [NSApplication sharedApplication]];
+ }
+
+ mPasteboardChangeCount = [mPasteboard changeCount];
+}
+
+
+AquaClipboard::~AquaClipboard()
+{
+ if (mIsSystemPasteboard)
+ {
+ [[NSNotificationCenter defaultCenter] removeObserver: mEventListener];
+ }
+
+ [mEventListener disposing];
+ [mEventListener release];
+ [mPasteboard release];
+}
+
+
+Reference<XTransferable> SAL_CALL AquaClipboard::getContents() throw(RuntimeException)
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // Shortcut: If we are clipboard owner already we don't need
+ // to drag the data through the system clipboard
+ if (mXClipboardContent.is())
+ {
+ return mXClipboardContent;
+ }
+
+ return Reference<XTransferable>(new OSXTransferable(mrXMimeCntFactory,
+ mpDataFlavorMapper,
+ mPasteboard));
+}
+
+
+void SAL_CALL AquaClipboard::setContents(const Reference<XTransferable>& xTransferable,
+ const Reference<XClipboardOwner>& xClipboardOwner)
+ throw( RuntimeException )
+{
+ NSArray* types = xTransferable.is() ?
+ mpDataFlavorMapper->flavorSequenceToTypesArray(xTransferable->getTransferDataFlavors()) :
+ [NSArray array];
+
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
+ mXClipboardOwner = xClipboardOwner;
+
+ Reference<XTransferable> oldContent(mXClipboardContent);
+ mXClipboardContent = xTransferable;
+
+ mPasteboardChangeCount = [mPasteboard declareTypes: types owner: mEventListener];
+
+ aGuard.clear();
+
+ // if we are already the owner of the clipboard
+ // then fire lost ownership event
+ if (oldOwner.is())
+ {
+ fireLostClipboardOwnershipEvent(oldOwner, oldContent);
+ }
+
+ fireClipboardChangedEvent();
+}
+
+
+OUString SAL_CALL AquaClipboard::getName() throw( RuntimeException )
+{
+ return OUString();
+}
+
+
+sal_Int8 SAL_CALL AquaClipboard::getRenderingCapabilities() throw( RuntimeException )
+{
+ return 0;
+}
+
+
+void SAL_CALL AquaClipboard::addClipboardListener(const Reference< XClipboardListener >& listener)
+ throw( RuntimeException )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (!listener.is())
+ throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
+ static_cast<XClipboardEx*>(this), 1);
+
+ mClipboardListeners.push_back(listener);
+}
+
+
+void SAL_CALL AquaClipboard::removeClipboardListener(const Reference< XClipboardListener >& listener)
+ throw( RuntimeException )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (!listener.is())
+ throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
+ static_cast<XClipboardEx*>(this), 1);
+
+ mClipboardListeners.remove(listener);
+}
+
+
+void AquaClipboard::applicationDidBecomeActive(NSNotification* aNotification)
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ int currentPboardChgCount = [mPasteboard changeCount];
+
+ if (currentPboardChgCount != mPasteboardChangeCount)
+ {
+ mPasteboardChangeCount = currentPboardChgCount;
+
+ // Clear clipboard content and owner and send lostOwnership
+ // notification to the old clipboard owner as well as
+ // ClipboardChanged notification to any clipboard listener
+ Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
+ mXClipboardOwner = Reference<XClipboardOwner>();
+
+ Reference<XTransferable> oldContent(mXClipboardContent);
+ mXClipboardContent = Reference<XTransferable>();
+
+ aGuard.clear();
+
+ if (oldOwner.is())
+ {
+ fireLostClipboardOwnershipEvent(oldOwner, oldContent);
+ }
+
+ fireClipboardChangedEvent();
+ }
+}
+
+
+void AquaClipboard::fireClipboardChangedEvent()
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ list<Reference< XClipboardListener > > listeners(mClipboardListeners);
+ ClipboardEvent aEvent;
+
+ if (listeners.begin() != listeners.end())
+ {
+ aEvent = ClipboardEvent(static_cast<OWeakObject*>(this), getContents());
+ }
+
+ aGuard.clear();
+
+ while (listeners.begin() != listeners.end())
+ {
+ if (listeners.front().is())
+ {
+ try { listeners.front()->changedContents(aEvent); }
+ catch (RuntimeException&) { }
+ }
+ listeners.pop_front();
+ }
+}
+
+
+void AquaClipboard::fireLostClipboardOwnershipEvent(Reference<XClipboardOwner> oldOwner, Reference<XTransferable> oldContent)
+{
+ BOOST_ASSERT(oldOwner.is());
+
+ try { oldOwner->lostOwnership(static_cast<XClipboardEx*>(this), oldContent); }
+ catch(RuntimeException&) { }
+}
+
+
+void AquaClipboard::provideDataForType(NSPasteboard* sender, NSString* type)
+{
+ DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(type, mXClipboardContent);
+ NSData* pBoardData = NULL;
+
+ if (dp.get() != NULL)
+ {
+ pBoardData = (NSData*)dp->getSystemData();
+ [sender setData: pBoardData forType: type];
+ }
+}
+
+
+//------------------------------------------------
+// XFlushableClipboard
+//------------------------------------------------
+
+void SAL_CALL AquaClipboard::flushClipboard()
+ throw(RuntimeException)
+{
+ if (mXClipboardContent.is())
+ {
+ Sequence<DataFlavor> flavorList = mXClipboardContent->getTransferDataFlavors();
+ sal_uInt32 nFlavors = flavorList.getLength();
+
+ for (sal_uInt32 i = 0; i < nFlavors; i++)
+ {
+ NSString* sysType = mpDataFlavorMapper->openOfficeToSystemFlavor(flavorList[i]);
+
+ if (sysType != NULL)
+ {
+ provideDataForType(mPasteboard, sysType);
+ }
+ }
+ }
+}
+
+
+NSPasteboard* AquaClipboard::getPasteboard() const
+{
+ return mPasteboard;
+}
+
+
+//-------------------------------------------------
+// XServiceInfo
+//-------------------------------------------------
+
+OUString SAL_CALL AquaClipboard::getImplementationName() throw( RuntimeException )
+{
+ return clipboard_getImplementationName();
+}
+
+
+sal_Bool SAL_CALL AquaClipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException )
+{
+ return sal_False;
+}
+
+
+Sequence< OUString > SAL_CALL AquaClipboard::getSupportedServiceNames() throw( RuntimeException )
+{
+ return clipboard_getSupportedServiceNames();
+}
+
diff --git a/vcl/aqua/source/dtrans/aqua_clipboard.hxx b/vcl/aqua/source/dtrans/aqua_clipboard.hxx
new file mode 100644
index 000000000000..8f45f50717f3
--- /dev/null
+++ b/vcl/aqua/source/dtrans/aqua_clipboard.hxx
@@ -0,0 +1,181 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _AQUA_CLIPBOARD_HXX_
+#define _AQUA_CLIPBOARD_HXX_
+
+#include "DataFlavorMapping.hxx"
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <cppuhelper/compbase4.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <boost/utility.hpp>
+#include <list>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+class AquaClipboard;
+
+@interface EventListener : NSObject
+{
+ AquaClipboard* pAquaClipboard;
+}
+
+// Init the pasteboard change listener with a reference to the OfficeClipboard
+// instance
+- (EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb;
+
+// Promiss resolver function
+- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString *)type;
+
+-(void)applicationDidBecomeActive:(NSNotification*)aNotification;
+
+-(void)disposing;
+@end
+
+
+class AquaClipboard : public ::cppu::BaseMutex,
+ public ::cppu::WeakComponentImplHelper4< com::sun::star::datatransfer::clipboard::XClipboardEx,
+ com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ com::sun::star::datatransfer::clipboard::XFlushableClipboard,
+ com::sun::star::lang::XServiceInfo >,
+ private ::boost::noncopyable
+{
+public:
+ /* Create a clipboard instance.
+
+ @param pasteboard
+ If not equal NULL the instance will be instantiated with the provided
+ pasteboard reference and 'bUseSystemClipboard' will be ignored
+
+ @param bUseSystemClipboard
+ If 'pasteboard' is NULL 'bUseSystemClipboard' determines whether the
+ system clipboard will be created (bUseSystemClipboard == true) or if
+ the DragPasteboard if bUseSystemClipboard == false
+ */
+ AquaClipboard(NSPasteboard* pasteboard = NULL,
+ bool bUseSystemClipboard = true);
+
+ ~AquaClipboard();
+
+ //------------------------------------------------
+ // XClipboard
+ //------------------------------------------------
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents()
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual void SAL_CALL setContents( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual ::rtl::OUString SAL_CALL getName()
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XClipboardEx
+ //------------------------------------------------
+
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities()
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XClipboardNotifier
+ //------------------------------------------------
+
+ virtual void SAL_CALL addClipboardListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual void SAL_CALL removeClipboardListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XFlushableClipboard
+ //------------------------------------------------
+
+ virtual void SAL_CALL flushClipboard( ) throw( com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XServiceInfo
+ //------------------------------------------------
+
+ virtual ::rtl::OUString SAL_CALL getImplementationName()
+ throw(::com::sun::star::uno::RuntimeException);
+
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
+ throw(::com::sun::star::uno::RuntimeException);
+
+ /* Get a reference to the used pastboard.
+ */
+ NSPasteboard* getPasteboard() const;
+
+ /* Notify the current clipboard owner that he is no longer the clipboard owner.
+ */
+ void fireLostClipboardOwnershipEvent(::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner> oldOwner,
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > oldContent);
+
+ void pasteboardChangedOwner();
+
+ void provideDataForType(NSPasteboard* sender, NSString* type);
+
+ void applicationDidBecomeActive(NSNotification* aNotification);
+
+private:
+
+ /* Notify all registered XClipboardListener that the clipboard content
+ has changed.
+ */
+ void fireClipboardChangedEvent();
+
+private:
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory > mrXMimeCntFactory;
+ ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > mClipboardListeners;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > mXClipboardContent;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::clipboard::XClipboardOwner > mXClipboardOwner;
+ DataFlavorMapperPtr_t mpDataFlavorMapper;
+ bool mIsSystemPasteboard;
+ NSPasteboard* mPasteboard;
+ int mPasteboardChangeCount;
+ EventListener* mEventListener;
+};
+
+#endif
diff --git a/vcl/aqua/source/dtrans/aqua_service.cxx b/vcl/aqua/source/dtrans/aqua_service.cxx
new file mode 100644
index 000000000000..571bea2e554f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/aqua_service.cxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include "aqua_clipboard.hxx"
+#include <cppuhelper/factory.hxx>
+#include <com/sun/star/container/XSet.hpp>
+#include <osl/diagnose.h>
+
+using namespace rtl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::registry;
+using namespace cppu;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace aqua;
+
+namespace aqua {
+
+Reference< XInterface > SAL_CALL createInstance( const Reference< XMultiServiceFactory >& rServiceManager )
+{
+ return Reference< XInterface >( static_cast< XClipboard* >( new AquaClipboard(rServiceManager) ) );
+}
+
+} // namespace aqua
+
+extern "C"
+{
+
+void SAL_CALL component_getImplementationEnvironment(
+ const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
+{
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+sal_Bool SAL_CALL component_writeInfo( void* pServiceManager, void* pRegistryKey )
+{
+ sal_Bool bRetVal = sal_False;
+
+ if ( pRegistryKey )
+ {
+ try
+ {
+ Reference< XRegistryKey > pXNewKey( static_cast< XRegistryKey* >( pRegistryKey ) );
+ pXNewKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_REGKEY_NAME ) ) );
+ bRetVal = sal_True;
+ }
+ catch( InvalidRegistryException& )
+ {
+ OSL_ENSURE(sal_False, "InvalidRegistryException caught");
+ bRetVal = sal_False;
+ }
+ }
+
+ return bRetVal;
+}
+
+void* SAL_CALL component_getFactory( const sal_Char* pImplName, uno_Interface* pSrvManager, uno_Interface* pRegistryKey )
+{
+ void* pRet = 0;
+
+ if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, AQUA_CLIPBOARD_IMPL_NAME ) ) )
+ {
+ Sequence< OUString > aSNS( 1 );
+ aSNS.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_SERVICE_NAME ) );
+
+ //OUString( RTL_CONSTASCII_USTRINGPARAM( FPS_IMPL_NAME ) )
+ Reference< XSingleServiceFactory > xFactory ( createOneInstanceFactory(
+ reinterpret_cast< XMultiServiceFactory* > ( pSrvManager ),
+ OUString::createFromAscii( pImplName ),
+ createInstance,
+ aSNS ) );
+ if ( xFactory.is() )
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ }
+
+ return pRet;
+}
+
+} // extern "C"
diff --git a/vcl/aqua/source/dtrans/makefile.mk b/vcl/aqua/source/dtrans/makefile.mk
new file mode 100644
index 000000000000..369799c9a260
--- /dev/null
+++ b/vcl/aqua/source/dtrans/makefile.mk
@@ -0,0 +1,68 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=dtransaqua
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# ------------------------------------------------------------------
+
+.IF "$(OS)"!="MACOSX"
+dummy:
+ @echo "Nothing to build for this platform"
+.ELSE # "$(OS)"!="MACOSX"
+.IF "$(GUIBASE)"!="aqua"
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+.ELSE
+
+CFLAGSCXX+=-fconstant-cfstrings -x objective-c++ -fobjc-exceptions
+
+SLOFILES= \
+ $(SLO)$/aqua_clipboard.obj \
+ $(SLO)$/DataFlavorMapping.obj \
+ $(SLO)$/OSXTransferable.obj \
+ $(SLO)$/HtmlFmtFlt.obj \
+ $(SLO)$/PictToBmpFlt.obj \
+ $(SLO)$/DropTarget.obj \
+ $(SLO)$/DragSource.obj \
+ $(SLO)$/service_entry.obj \
+ $(SLO)$/DragSourceContext.obj \
+ $(SLO)$/DragActionConversion.obj
+
+# --- Targets ------------------------------------------------------
+.INCLUDE : target.mk
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+.ENDIF # "$(OS)"!="MACOSX"
+
diff --git a/vcl/aqua/source/dtrans/service_entry.cxx b/vcl/aqua/source/dtrans/service_entry.cxx
new file mode 100644
index 000000000000..16308951bcfe
--- /dev/null
+++ b/vcl/aqua/source/dtrans/service_entry.cxx
@@ -0,0 +1,64 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "saldata.hxx"
+#include "salinst.h"
+#include "DragSource.hxx"
+#include "DropTarget.hxx"
+#include "aqua_clipboard.hxx"
+#include "osl/diagnose.h"
+
+using namespace ::osl;
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::cppu;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::datatransfer::clipboard;
+
+
+Reference< XInterface > AquaSalInstance::CreateClipboard( const Sequence< Any >& i_rArguments )
+{
+ SalData* pSalData = GetSalData();
+ if( ! pSalData->mxClipboard.is() )
+ pSalData->mxClipboard = Reference<XInterface>(static_cast< XClipboard* >(new AquaClipboard()), UNO_QUERY);
+ return pSalData->mxClipboard;
+}
+
+
+Reference<XInterface> AquaSalInstance::CreateDragSource()
+{
+ return Reference<XInterface>(static_cast< XInitialization* >(new DragSource()), UNO_QUERY);
+}
+
+Reference<XInterface> AquaSalInstance::CreateDropTarget()
+{
+ return Reference<XInterface>(static_cast< XInitialization* >(new DropTarget()), UNO_QUERY);
+}
+
diff --git a/vcl/aqua/source/dtrans/test_aquacb.cxx b/vcl/aqua/source/dtrans/test_aquacb.cxx
new file mode 100644
index 000000000000..85c87c6b9ba9
--- /dev/null
+++ b/vcl/aqua/source/dtrans/test_aquacb.cxx
@@ -0,0 +1,208 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aqua_clipboard.hxx"
+#include <cppuhelper/servicefactory.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+
+#ifndef _CPPUHELPER_IMPLBASE1_HXX_
+#include <cppuhelper/implbase2.hxx>
+#endif
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <osl/diagnose.h>
+
+#include <stdio.h>
+
+using namespace ::rtl;
+using namespace ::std;
+using namespace ::cppu;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+
+Reference< XTransferable > rXTransfRead;
+
+class TestTransferable : public WeakImplHelper2< XClipboardOwner, XTransferable >
+{
+public:
+ TestTransferable();
+ virtual Any SAL_CALL getTransferData( const DataFlavor& aFlavor ) throw(UnsupportedFlavorException, IOException, RuntimeException);
+ virtual Sequence< DataFlavor > SAL_CALL getTransferDataFlavors() throw(RuntimeException);
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const DataFlavor& aFlavor ) throw(RuntimeException);
+ virtual void SAL_CALL lostOwnership( const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans ) throw(RuntimeException);
+
+private:
+ Sequence< DataFlavor > m_seqDFlv;
+ OUString m_Data;
+};
+
+TestTransferable::TestTransferable() :
+ m_seqDFlv( 1 ),
+ m_Data( RTL_CONSTASCII_USTRINGPARAM( "This is a test string" ) )
+{
+ DataFlavor df;
+
+ df.MimeType = OUString::createFromAscii( "text/html" );
+ df.DataType = getCppuType( ( Sequence< sal_Int8 >* )0 );
+
+ m_seqDFlv[0] = df;
+}
+
+Any SAL_CALL TestTransferable::getTransferData( const DataFlavor& aFlavor )
+ throw(UnsupportedFlavorException, IOException, RuntimeException)
+{
+ Any anyData;
+
+ if ( aFlavor.MimeType == m_seqDFlv[0].MimeType )
+ {
+ OString aStr( m_Data.getStr(), m_Data.getLength(), 1252 );
+ Sequence< sal_Int8 > sOfChars( aStr.getLength() );
+ sal_Int32 lenStr = aStr.getLength();
+
+ for ( sal_Int32 i = 0; i < lenStr; ++i )
+ sOfChars[i] = aStr[i];
+
+ anyData = makeAny( sOfChars );
+ }
+
+ return anyData;
+}
+
+Sequence< DataFlavor > SAL_CALL TestTransferable::getTransferDataFlavors()
+ throw(RuntimeException)
+{
+ return m_seqDFlv;
+}
+
+sal_Bool SAL_CALL TestTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
+ throw(RuntimeException)
+{
+ sal_Int32 nLength = m_seqDFlv.getLength();
+ sal_Bool bRet = sal_False;
+
+ for ( sal_Int32 i = 0; i < nLength; ++i )
+ {
+ if ( m_seqDFlv[i].MimeType == aFlavor.MimeType )
+ {
+ bRet = sal_True;
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+void SAL_CALL TestTransferable::lostOwnership( const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans )
+ throw(RuntimeException)
+{
+}
+
+int SAL_CALL main( int argc, char** argv )
+{
+ if(argc != 2)
+ {
+ fprintf( stderr, "usage: %s <my rdb file>\n", argv[0] );
+ return 1;
+ }
+
+ //-------------------------------------------------
+ // get the global service-manager
+ //-------------------------------------------------
+ OUString rdbName = OUString::createFromAscii( argv[1] );
+ Reference< XMultiServiceFactory > g_xFactory( createRegistryServiceFactory( rdbName ) );
+
+ // Print a message if an error occured.
+ if ( !g_xFactory.is() )
+ {
+ OSL_ENSURE(sal_False, "Can't create RegistryServiceFactory");
+ return(-1);
+ }
+
+ //-------------------------------------------------
+ // try to get an Interface to a XFilePicker Service
+ //-------------------------------------------------
+
+ Reference< XTransferable > rXTransf( static_cast< XTransferable* >( new TestTransferable ) );
+
+ Reference< XClipboard > xClipboard( g_xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_SERVICE_NAME ) ) ), UNO_QUERY );
+ if ( !xClipboard.is() )
+ {
+ OSL_ENSURE( sal_False, "Error creating FolderPicker Service" );
+ return(-1);
+ }
+
+ Reference< XTypeProvider > rXTypProv( xClipboard, UNO_QUERY );
+
+ if ( rXTypProv.is() )
+ {
+ Sequence< Type > seqType = rXTypProv->getTypes();
+ sal_Int32 nLen = seqType.getLength();
+ for ( sal_Int32 i = 0; i < nLen; i++ )
+ {
+ Type nxtType = seqType[i];
+ }
+
+ Sequence< sal_Int8 > seqInt8 = rXTypProv->getImplementationId();
+ }
+
+ xClipboard->setContents( rXTransf, Reference< XClipboardOwner >( rXTransf, UNO_QUERY ) );
+
+ rXTransfRead = xClipboard->getContents();
+
+ // destroy the transferable explicitly
+ rXTransfRead = Reference< XTransferable>();
+
+ // destroy the clipboard
+ xClipboard = Reference< XClipboard >();
+
+ //--------------------------------------------------
+ // shutdown the service manager
+ //--------------------------------------------------
+
+ // Cast factory to XComponent
+ Reference< XComponent > xComponent( g_xFactory, UNO_QUERY );
+
+ if ( !xComponent.is() )
+ OSL_ENSURE(sal_False, "Error shuting down");
+
+ // Dispose and clear factory
+ xComponent->dispose();
+ g_xFactory.clear();
+ g_xFactory = Reference< XMultiServiceFactory >();
+
+ return 0;
+}
diff --git a/vcl/aqua/source/gdi/aquaprintaccessoryview.mm b/vcl/aqua/source/gdi/aquaprintaccessoryview.mm
new file mode 100644
index 000000000000..d00fc9a6cd0e
--- /dev/null
+++ b/vcl/aqua/source/gdi/aquaprintaccessoryview.mm
@@ -0,0 +1,1241 @@
+/************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aquaprintview.h"
+#include "salinst.h"
+#include "vcl/print.hxx"
+#include "vcl/image.hxx"
+#include "vcl/virdev.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/unohelp.hxx"
+
+#include "vcl/svids.hrc"
+
+#include "tools/resary.hxx"
+
+#include "com/sun/star/i18n/XBreakIterator.hpp"
+#include "com/sun/star/i18n/WordType.hpp"
+
+#include <map>
+
+using namespace vcl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::uno;
+
+/* Note: the accesory view as implemented here is already deprecated in Leopard. Unfortunately
+ as long as our baseline is Tiger we cannot gain the advantages over multiple accessory views
+ as well havs having accessory views AND a preview (as long as you are linked vs. 10.4 libraries
+ the preview insists on not being present. This is unfortunate.
+*/
+
+class ControllerProperties;
+
+@interface ControlTarget : NSObject
+{
+ ControllerProperties* mpController;
+}
+-(id)initWithControllerMap: (ControllerProperties*)pController;
+-(void)triggered:(id)pSender;
+-(void)triggeredNumeric:(id)pSender;
+-(void)triggeredPreview:(id)pSender;
+-(void)dealloc;
+@end
+
+
+class ControllerProperties
+{
+ vcl::PrinterController* mpController;
+ std::map< int, rtl::OUString > maTagToPropertyName;
+ std::map< int, sal_Int32 > maTagToValueInt;
+ std::map< NSView*, NSView* > maViewPairMap;
+ std::vector< NSObject* > maViews;
+ int mnNextTag;
+ sal_Int32 mnLastPageCount;
+ PrintAccessoryViewState* mpState;
+ NSPrintOperation* mpOp;
+ NSView* mpAccessoryView;
+ NSTabView* mpTabView;
+ NSBox* mpPreviewBox;
+ NSImageView* mpPreview;
+ NSTextField* mpPageEdit;
+ NSStepper* mpStepper;
+ NSTextView* mpPagesLabel;
+ ResStringArray maLocalizedStrings;
+
+ public:
+ ControllerProperties( vcl::PrinterController* i_pController,
+ NSPrintOperation* i_pOp,
+ NSView* i_pAccessoryView,
+ NSTabView* i_pTabView,
+ PrintAccessoryViewState* i_pState )
+ : mpController( i_pController ),
+ mnNextTag( 0 ),
+ mnLastPageCount( i_pController->getFilteredPageCount() ),
+ mpState( i_pState ),
+ mpOp( i_pOp ),
+ mpAccessoryView( i_pAccessoryView ),
+ mpTabView( i_pTabView ),
+ mpPreviewBox( nil ),
+ mpPreview( nil ),
+ mpPageEdit( nil ),
+ mpStepper( nil ),
+ mpPagesLabel( nil ),
+ maLocalizedStrings( VclResId( SV_PRINT_NATIVE_STRINGS ) )
+ {
+ mpState->bNeedRestart = false;
+ DBG_ASSERT( maLocalizedStrings.Count() >= 4, "resources not found !" );
+ }
+
+ rtl::OUString getMoreString()
+ {
+ return maLocalizedStrings.Count() >= 4
+ ? rtl::OUString( maLocalizedStrings.GetString( 3 ) )
+ : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "More" ) );
+ }
+
+ void updatePrintJob()
+ {
+ // TODO: refresh page count etc from mpController
+
+ // page range may have changed depending on options
+ sal_Int32 nPages = mpController->getFilteredPageCount();
+ #if OSL_DEBUG_LEVEL > 1
+ if( nPages != mnLastPageCount )
+ fprintf( stderr, "trouble: number of pages changed from %ld to %ld !\n", mnLastPageCount, nPages );
+ #endif
+ mpState->bNeedRestart = (nPages != mnLastPageCount);
+ NSTabViewItem* pItem = [mpTabView selectedTabViewItem];
+ if( pItem )
+ mpState->nLastPage = [mpTabView indexOfTabViewItem: pItem];
+ else
+ mpState->nLastPage = 0;
+ mnLastPageCount = nPages;
+ if( mpState->bNeedRestart )
+ {
+ #if 0
+ // Warning: bad hack ahead
+ // Apple does not give us a chance of changing the page count,
+ // and they don't let us cancel the dialog either
+ // hack: send a cancel message to the window displaying our views.
+ // this is ugly.
+ for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it )
+ {
+ if( [*it isKindOfClass: [NSView class]] )
+ {
+ NSView* pView = (NSView*)*it;
+ NSWindow* pWindow = [pView window];
+ if( pWindow )
+ {
+ [pWindow cancelOperation: nil];
+ break;
+ }
+ }
+ }
+ #else
+ NSWindow* pWindow = [NSApp modalWindow];
+ if( pWindow )
+ [pWindow cancelOperation: nil];
+ #endif
+ [[mpOp printInfo] setJobDisposition: NSPrintCancelJob];
+ }
+ else
+ {
+ sal_Int32 nPage = [mpStepper intValue];
+ updatePreviewImage( nPage-1 );
+ }
+ }
+
+ int addNameTag( const rtl::OUString& i_rPropertyName )
+ {
+ int nNewTag = mnNextTag++;
+ maTagToPropertyName[ nNewTag ] = i_rPropertyName;
+ return nNewTag;
+ }
+
+ int addNameAndValueTag( const rtl::OUString& i_rPropertyName, sal_Int32 i_nValue )
+ {
+ int nNewTag = mnNextTag++;
+ maTagToPropertyName[ nNewTag ] = i_rPropertyName;
+ maTagToValueInt[ nNewTag ] = i_nValue;
+ return nNewTag;
+ }
+
+ void addObservedControl( NSObject* i_pView )
+ {
+ maViews.push_back( i_pView );
+ }
+
+ void addViewPair( NSView* i_pLeft, NSView* i_pRight )
+ {
+ maViewPairMap[ i_pLeft ] = i_pRight;
+ maViewPairMap[ i_pRight ] = i_pLeft;
+ }
+
+ NSView* getPair( NSView* i_pLeft ) const
+ {
+ NSView* pRight = nil;
+ std::map< NSView*, NSView* >::const_iterator it = maViewPairMap.find( i_pLeft );
+ if( it != maViewPairMap.end() )
+ pRight = it->second;
+ return pRight;
+ }
+
+ void changePropertyWithIntValue( int i_nTag )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ std::map< int, sal_Int32 >::const_iterator value_it = maTagToValueInt.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() && value_it != maTagToValueInt.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= value_it->second;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void changePropertyWithIntValue( int i_nTag, sal_Int64 i_nValue )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= i_nValue;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void changePropertyWithBoolValue( int i_nTag, sal_Bool i_bValue )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= i_bValue;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void changePropertyWithStringValue( int i_nTag, const rtl::OUString& i_rValue )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= i_rValue;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void updateEnableState()
+ {
+ for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it )
+ {
+ NSObject* pObj = *it;
+ NSControl* pCtrl = nil;
+ NSCell* pCell = nil;
+ if( [pObj isKindOfClass: [NSControl class]] )
+ pCtrl = (NSControl*)pObj;
+ else if( [pObj isKindOfClass: [NSCell class]] )
+ pCell = (NSCell*)pObj;
+
+ int nTag = pCtrl ? [pCtrl tag] :
+ pCell ? [pCell tag] :
+ -1;
+
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ MacOSBOOL bEnabled = mpController->isUIOptionEnabled( name_it->second ) ? YES : NO;
+ if( pCtrl )
+ {
+ [pCtrl setEnabled: bEnabled];
+ NSView* pOther = getPair( pCtrl );
+ if( pOther && [pOther isKindOfClass: [NSControl class]] )
+ [(NSControl*)pOther setEnabled: bEnabled];
+ }
+ else if( pCell )
+ [pCell setEnabled: bEnabled];
+
+ }
+ }
+ }
+
+ void updatePreviewImage( sal_Int32 i_nPage )
+ {
+ sal_Int32 nPages = mpController->getFilteredPageCount();
+ NSRect aViewFrame = [mpPreview frame];
+ Size aPixelSize( static_cast<long>(aViewFrame.size.width),
+ static_cast<long>(aViewFrame.size.height) );
+ if( i_nPage >= 0 && nPages > i_nPage )
+ {
+ GDIMetaFile aMtf;
+ PrinterController::PageSize aPageSize( mpController->getFilteredPageFile( i_nPage, aMtf, false ) );
+ VirtualDevice aDev;
+ // see salprn.cxx, currently we pretend to be a 720dpi device on printers
+ aDev.SetReferenceDevice( 720, 720 );
+ aDev.EnableOutput( TRUE );
+ Size aLogicSize( aDev.PixelToLogic( aPixelSize, MapMode( MAP_100TH_MM ) ) );
+ double fScaleX = double(aLogicSize.Width())/double(aPageSize.aSize.Width());
+ double fScaleY = double(aLogicSize.Height())/double(aPageSize.aSize.Height());
+ double fScale = (fScaleX < fScaleY) ? fScaleX : fScaleY;
+ // #i104784# if we render the page too small then rounding issues result in
+ // layout artifacts looking really bad. So scale the page unto a device that is not
+ // full page size but not too small either. This also results in much better visual
+ // quality of the preview, e.g. when its height approaches the number of text lines
+ if( fScale < 0.1 )
+ fScale = 0.1;
+ aMtf.WindStart();
+ aMtf.Scale( fScale, fScale );
+ aMtf.WindStart();
+ aLogicSize.Width() = long(double(aPageSize.aSize.Width()) * fScale);
+ aLogicSize.Height() = long(double(aPageSize.aSize.Height()) * fScale);
+ aPixelSize = aDev.LogicToPixel( aLogicSize, MapMode( MAP_100TH_MM ) );
+ aDev.SetOutputSizePixel( aPixelSize );
+ aMtf.WindStart();
+ aDev.SetMapMode( MapMode( MAP_100TH_MM ) );
+ aMtf.Play( &aDev, Point( 0, 0 ), aLogicSize );
+ aDev.EnableMapMode( FALSE );
+ Image aImage( aDev.GetBitmap( Point( 0, 0 ), aPixelSize ) );
+ NSImage* pImage = CreateNSImage( aImage );
+ [mpPreview setImage: [pImage autorelease]];
+ }
+ else
+ [mpPreview setImage: nil];
+ }
+
+ void setupPreview( ControlTarget* i_pCtrlTarget )
+ {
+ if( maLocalizedStrings.Count() < 3 )
+ return;
+
+ // get the preview control
+ NSRect aPreviewFrame = [mpAccessoryView frame];
+ aPreviewFrame.origin.x = 0;
+ aPreviewFrame.origin.y = 5;
+ aPreviewFrame.size.width = 190;
+ aPreviewFrame.size.height -= 7;
+
+ // create a box to put the preview controls in
+ mpPreviewBox = [[NSBox alloc] initWithFrame: aPreviewFrame];
+ [mpPreviewBox setTitle: [CreateNSString( maLocalizedStrings.GetString( 0 ) ) autorelease]];
+ [mpAccessoryView addSubview: [mpPreviewBox autorelease]];
+
+ // now create the image view of the preview
+ NSSize aMargins = [mpPreviewBox contentViewMargins];
+ aPreviewFrame.origin.x = 0;
+ aPreviewFrame.origin.y = 34;
+ aPreviewFrame.size.width -= 2*(aMargins.width+1);
+ aPreviewFrame.size.height -= 61;
+ mpPreview = [[NSImageView alloc] initWithFrame: aPreviewFrame];
+ [mpPreview setImageScaling: NSScaleProportionally];
+ [mpPreview setImageAlignment: NSImageAlignCenter];
+ [mpPreview setImageFrameStyle: NSImageFrameNone];
+ [mpPreviewBox addSubview: [mpPreview autorelease]];
+
+ // add a label
+ sal_Int32 nPages = mpController->getFilteredPageCount();
+ rtl::OUStringBuffer aBuf( 16 );
+ aBuf.appendAscii( "/ " );
+ aBuf.append( rtl::OUString::valueOf( nPages ) );
+
+ NSString* pText = CreateNSString( aBuf.makeStringAndClear() );
+ NSRect aTextRect = { { 100, 5 }, { 100, 22 } };
+ mpPagesLabel = [[NSTextView alloc] initWithFrame: aTextRect];
+ [mpPagesLabel setFont: [NSFont controlContentFontOfSize: 0]];
+ [mpPagesLabel setEditable: NO];
+ [mpPagesLabel setSelectable: NO];
+ [mpPagesLabel setDrawsBackground: NO];
+ [mpPagesLabel setString: [pText autorelease]];
+ [mpPagesLabel setToolTip: [CreateNSString( maLocalizedStrings.GetString( 2 ) ) autorelease]];
+ [mpPreviewBox addSubview: [mpPagesLabel autorelease]];
+
+ NSRect aFieldRect = { { 45, 5 }, { 35, 25 } };
+ mpPageEdit = [[NSTextField alloc] initWithFrame: aFieldRect];
+ [mpPageEdit setEditable: YES];
+ [mpPageEdit setSelectable: YES];
+ [mpPageEdit setDrawsBackground: YES];
+ [mpPageEdit setToolTip: [CreateNSString( maLocalizedStrings.GetString( 1 ) ) autorelease]];
+ [mpPreviewBox addSubview: [mpPageEdit autorelease]];
+
+ // add a stepper control
+ NSRect aStepFrame = { { 85, 5 }, { 15, 25 } };
+ mpStepper = [[NSStepper alloc] initWithFrame: aStepFrame];
+ [mpStepper setIncrement: 1];
+ [mpStepper setValueWraps: NO];
+ [mpPreviewBox addSubview: [mpStepper autorelease]];
+
+ // constrain the text field to decimal numbers
+ NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init];
+ [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4];
+ [pFormatter setMinimum: [[NSNumber numberWithInt: 1] autorelease]];
+ [pFormatter setMaximum: [[NSNumber numberWithInt: nPages] autorelease]];
+ [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
+ [pFormatter setAllowsFloats: NO];
+ [pFormatter setMaximumFractionDigits: 0];
+ [mpPageEdit setFormatter: pFormatter];
+ [mpStepper setMinValue: 1];
+ [mpStepper setMaxValue: nPages];
+
+ [mpPageEdit setIntValue: 1];
+ [mpStepper setIntValue: 1];
+
+ // connect target and action
+ [mpStepper setTarget: i_pCtrlTarget];
+ [mpStepper setAction: @selector(triggeredPreview:)];
+ [mpPageEdit setTarget: i_pCtrlTarget];
+ [mpPageEdit setAction: @selector(triggeredPreview:)];
+
+ // set first preview image
+ updatePreviewImage( 0 );
+ }
+
+ void changePreview( NSObject* i_pSender )
+ {
+ if( [i_pSender isMemberOfClass: [NSTextField class]] )
+ {
+ NSTextField* pField = (NSTextField*)i_pSender;
+ if( pField == mpPageEdit ) // sanity check
+ {
+ sal_Int32 nPage = [pField intValue];
+ [mpStepper setIntValue: nPage];
+ updatePreviewImage( nPage-1 );
+ }
+ }
+ else if( [i_pSender isMemberOfClass: [NSStepper class]] )
+ {
+ NSStepper* pStepper = (NSStepper*)i_pSender;
+ if( pStepper == mpStepper ) // sanity check
+ {
+ sal_Int32 nPage = [pStepper intValue];
+ [mpPageEdit setIntValue: nPage];
+ updatePreviewImage( nPage-1 );
+ }
+ }
+ }
+};
+
+static void filterAccelerator( rtl::OUString& io_rText )
+{
+ rtl::OUStringBuffer aBuf( io_rText.getLength() );
+ for( sal_Int32 nIndex = 0; nIndex != -1; )
+ aBuf.append( io_rText.getToken( 0, '~', nIndex ) );
+ io_rText = aBuf.makeStringAndClear();
+}
+
+@implementation ControlTarget
+-(id)initWithControllerMap: (ControllerProperties*)pController
+{
+ if( (self = [super init]) )
+ {
+ mpController = pController;
+ }
+ return self;
+}
+-(void)triggered:(id)pSender;
+{
+ if( [pSender isMemberOfClass: [NSPopUpButton class]] )
+ {
+ NSPopUpButton* pBtn = (NSPopUpButton*)pSender;
+ NSMenuItem* pSelected = [pBtn selectedItem];
+ if( pSelected )
+ {
+ int nTag = [pSelected tag];
+ mpController->changePropertyWithIntValue( nTag );
+ }
+ }
+ else if( [pSender isMemberOfClass: [NSButton class]] )
+ {
+ NSButton* pBtn = (NSButton*)pSender;
+ int nTag = [pBtn tag];
+ mpController->changePropertyWithBoolValue( nTag, [pBtn state] == NSOnState );
+ }
+ else if( [pSender isMemberOfClass: [NSMatrix class]] )
+ {
+ NSObject* pObj = [(NSMatrix*)pSender selectedCell];
+ if( [pObj isMemberOfClass: [NSButtonCell class]] )
+ {
+ NSButtonCell* pCell = (NSButtonCell*)pObj;
+ int nTag = [pCell tag];
+ mpController->changePropertyWithIntValue( nTag );
+ }
+ }
+ else if( [pSender isMemberOfClass: [NSTextField class]] )
+ {
+ NSTextField* pField = (NSTextField*)pSender;
+ int nTag = [pField tag];
+ rtl::OUString aValue = GetOUString( [pSender stringValue] );
+ mpController->changePropertyWithStringValue( nTag, aValue );
+ }
+ else
+ {
+ DBG_ERROR( "unsupported class" );
+ }
+ mpController->updateEnableState();
+}
+-(void)triggeredNumeric:(id)pSender;
+{
+ if( [pSender isMemberOfClass: [NSTextField class]] )
+ {
+ NSTextField* pField = (NSTextField*)pSender;
+ int nTag = [pField tag];
+ sal_Int64 nValue = [pField intValue];
+
+ NSView* pOther = mpController->getPair( pField );
+ if( pOther )
+ [(NSControl*)pOther setIntValue: nValue];
+
+ mpController->changePropertyWithIntValue( nTag, nValue );
+ }
+ else if( [pSender isMemberOfClass: [NSStepper class]] )
+ {
+ NSStepper* pStep = (NSStepper*)pSender;
+ int nTag = [pStep tag];
+ sal_Int64 nValue = [pStep intValue];
+
+ NSView* pOther = mpController->getPair( pStep );
+ if( pOther )
+ [(NSControl*)pOther setIntValue: nValue];
+
+ mpController->changePropertyWithIntValue( nTag, nValue );
+ }
+ else
+ {
+ DBG_ERROR( "unsupported class" );
+ }
+ mpController->updateEnableState();
+}
+-(void)triggeredPreview:(id)pSender
+{
+ mpController->changePreview( pSender );
+}
+-(void)dealloc
+{
+ delete mpController;
+ [super dealloc];
+}
+@end
+
+struct ColumnItem
+{
+ NSControl* pControl;
+ long nOffset;
+ NSControl* pSubControl;
+
+ ColumnItem( NSControl* i_pControl = nil, long i_nOffset = 0, NSControl* i_pSub = nil )
+ : pControl( i_pControl )
+ , nOffset( i_nOffset )
+ , pSubControl( i_pSub )
+ {}
+
+ long getWidth() const
+ {
+ long nWidth = 0;
+ if( pControl )
+ {
+ NSRect aCtrlRect = [pControl frame];
+ nWidth = aCtrlRect.size.width;
+ nWidth += nOffset;
+ if( pSubControl )
+ {
+ NSRect aSubRect = [pSubControl frame];
+ nWidth += aSubRect.size.width;
+ nWidth += aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width);
+ }
+ }
+ return nWidth;
+ }
+};
+
+static void adjustViewAndChildren( NSView* pView, NSSize& rMaxSize,
+ std::vector< ColumnItem >& rLeftColumn,
+ std::vector< ColumnItem >& rRightColumn
+ )
+{
+ // balance columns
+
+ // first get overall column widths
+ long nLeftWidth = 0;
+ long nRightWidth = 0;
+ for( size_t i = 0; i < rLeftColumn.size(); i++ )
+ {
+ long nW = rLeftColumn[i].getWidth();
+ if( nW > nLeftWidth )
+ nLeftWidth = nW;
+ }
+ for( size_t i = 0; i < rRightColumn.size(); i++ )
+ {
+ long nW = rRightColumn[i].getWidth();
+ if( nW > nRightWidth )
+ nRightWidth = nW;
+ }
+
+ // right align left column
+ for( size_t i = 0; i < rLeftColumn.size(); i++ )
+ {
+ if( rLeftColumn[i].pControl )
+ {
+ NSRect aCtrlRect = [rLeftColumn[i].pControl frame];
+ long nX = nLeftWidth - aCtrlRect.size.width;
+ if( rLeftColumn[i].pSubControl )
+ {
+ NSRect aSubRect = [rLeftColumn[i].pSubControl frame];
+ nX -= aSubRect.size.width + (aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width));
+ aSubRect.origin.x = nLeftWidth - aSubRect.size.width;
+ [rLeftColumn[i].pSubControl setFrame: aSubRect];
+ }
+ aCtrlRect.origin.x = nX;
+ [rLeftColumn[i].pControl setFrame: aCtrlRect];
+ }
+ }
+
+ // left align right column
+ for( size_t i = 0; i < rRightColumn.size(); i++ )
+ {
+ if( rRightColumn[i].pControl )
+ {
+ NSRect aCtrlRect = [rRightColumn[i].pControl frame];
+ long nX = nLeftWidth + 3;
+ if( rRightColumn[i].pSubControl )
+ {
+ NSRect aSubRect = [rRightColumn[i].pSubControl frame];
+ aSubRect.origin.x = nX + aSubRect.origin.x - aCtrlRect.origin.x;
+ [rRightColumn[i].pSubControl setFrame: aSubRect];
+ }
+ aCtrlRect.origin.x = nX;
+ [rRightColumn[i].pControl setFrame: aCtrlRect];
+ }
+ }
+
+ NSArray* pSubViews = [pView subviews];
+ unsigned int nViews = [pSubViews count];
+ NSRect aUnion = { { 0, 0 }, { 0, 0 } };
+
+ // get the combined frame of all subviews
+ for( unsigned int n = 0; n < nViews; n++ )
+ {
+ aUnion = NSUnionRect( aUnion, [[pSubViews objectAtIndex: n] frame] );
+ }
+
+ // move everything so it will fit
+ for( unsigned int n = 0; n < nViews; n++ )
+ {
+ NSView* pCurSubView = [pSubViews objectAtIndex: n];
+ NSRect aFrame = [pCurSubView frame];
+ aFrame.origin.x -= aUnion.origin.x - 5;
+ aFrame.origin.y -= aUnion.origin.y - 5;
+ [pCurSubView setFrame: aFrame];
+ }
+
+ // resize the view itself
+ aUnion.size.height += 10;
+ aUnion.size.width += 20;
+ [pView setFrameSize: aUnion.size];
+
+ if( aUnion.size.width > rMaxSize.width )
+ rMaxSize.width = aUnion.size.width;
+ if( aUnion.size.height > rMaxSize.height )
+ rMaxSize.height = aUnion.size.height;
+}
+
+static void adjustTabViews( NSTabView* pTabView, NSSize aTabSize )
+{
+ // loop over all contained tab pages
+ NSArray* pTabbedViews = [pTabView tabViewItems];
+ int nViews = [pTabbedViews count];
+ for( int i = 0; i < nViews; i++ )
+ {
+ NSTabViewItem* pItem = (NSTabViewItem*)[pTabbedViews objectAtIndex: i];
+ NSView* pView = [pItem view];
+ if( pView )
+ {
+ NSRect aRect = [pView frame];
+ double nDiff = aTabSize.height - aRect.size.height;
+ aRect.size = aTabSize;
+ [pView setFrame: aRect];
+
+ NSArray* pSubViews = [pView subviews];
+ unsigned int nSubViews = [pSubViews count];
+
+ // move everything up
+ for( unsigned int n = 0; n < nSubViews; n++ )
+ {
+ NSView* pCurSubView = [pSubViews objectAtIndex: n];
+ NSRect aFrame = [pCurSubView frame];
+ aFrame.origin.y += nDiff;
+ // give separators the correct width
+ // separators are currently the only NSBoxes we use
+ if( [pCurSubView isMemberOfClass: [NSBox class]] )
+ {
+ aFrame.size.width = aTabSize.width - aFrame.origin.x - 10;
+ }
+ [pCurSubView setFrame: aFrame];
+ }
+ }
+ }
+}
+
+static NSControl* createLabel( const rtl::OUString& i_rText )
+{
+ NSString* pText = CreateNSString( i_rText );
+ NSRect aTextRect = { { 0, 0 }, {20, 15} };
+ NSTextField* pTextView = [[NSTextField alloc] initWithFrame: aTextRect];
+ [pTextView setFont: [NSFont controlContentFontOfSize: 0]];
+ [pTextView setEditable: NO];
+ [pTextView setSelectable: NO];
+ [pTextView setDrawsBackground: NO];
+ [pTextView setBordered: NO];
+ [pTextView setStringValue: pText];
+ [pTextView sizeToFit];
+ [pText release];
+ return pTextView;
+}
+
+static sal_Int32 findBreak( const rtl::OUString& i_rText, sal_Int32 i_nPos )
+{
+ sal_Int32 nRet = i_rText.getLength();
+ Reference< i18n::XBreakIterator > xBI( vcl::unohelper::CreateBreakIterator() );
+ if( xBI.is() )
+ {
+ i18n::Boundary aBoundary = xBI->getWordBoundary( i_rText, i_nPos,
+ Application::GetSettings().GetLocale(),
+ i18n::WordType::ANYWORD_IGNOREWHITESPACES,
+ sal_True );
+ nRet = aBoundary.endPos;
+ }
+ return nRet;
+}
+
+static void linebreakCell( NSCell* pBtn, const rtl::OUString& i_rText )
+{
+ NSString* pText = CreateNSString( i_rText );
+ [pBtn setTitle: pText];
+ [pText release];
+ NSSize aSize = [pBtn cellSize];
+ if( aSize.width > 280 )
+ {
+ // need two lines
+ sal_Int32 nLen = i_rText.getLength();
+ sal_Int32 nIndex = nLen / 2;
+ nIndex = findBreak( i_rText, nIndex );
+ if( nIndex < nLen )
+ {
+ rtl::OUStringBuffer aBuf( i_rText );
+ aBuf.setCharAt( nIndex, '\n' );
+ pText = CreateNSString( aBuf.makeStringAndClear() );
+ [pBtn setTitle: pText];
+ [pText release];
+ }
+ }
+}
+
+
+@implementation AquaPrintAccessoryView
++(NSObject*)setupPrinterPanel: (NSPrintOperation*)pOp withController: (vcl::PrinterController*)pController withState: (PrintAccessoryViewState*)pState;
+{
+ const Sequence< PropertyValue >& rOptions( pController->getUIOptions() );
+ if( rOptions.getLength() == 0 )
+ return nil;
+
+ NSView* pCurParent = 0;
+ long nCurY = 0;
+ long nCurX = 0;
+ NSRect aViewFrame = { { 0, 0 }, {600, 400 } };
+ NSRect aTabViewFrame = { { 190, 0 }, {410, 400 } };
+ NSSize aMaxTabSize = { 0, 0 };
+ NSView* pAccessoryView = [[NSView alloc] initWithFrame: aViewFrame];
+ NSTabView* pTabView = [[NSTabView alloc] initWithFrame: aTabViewFrame];
+ [pAccessoryView addSubview: [pTabView autorelease]];
+
+ sal_Bool bIgnoreSubgroup = sal_False;
+
+ ControllerProperties* pControllerProperties = new ControllerProperties( pController, pOp, pAccessoryView, pTabView, pState );
+ ControlTarget* pCtrlTarget = [[ControlTarget alloc] initWithControllerMap: pControllerProperties];
+
+ std::vector< ColumnItem > aLeftColumn, aRightColumn;
+
+ for( int i = 0; i < rOptions.getLength(); i++ )
+ {
+ Sequence< beans::PropertyValue > aOptProp;
+ rOptions[i].Value >>= aOptProp;
+
+ // extract ui element
+ bool bEnabled = true;
+ rtl::OUString aCtrlType;
+ rtl::OUString aText;
+ rtl::OUString aPropertyName;
+ Sequence< rtl::OUString > aChoices;
+ sal_Int64 nMinValue = 0, nMaxValue = 0;
+ long nAttachOffset = 0;
+ sal_Bool bIgnore = sal_False;
+
+ for( int n = 0; n < aOptProp.getLength(); n++ )
+ {
+ const beans::PropertyValue& rEntry( aOptProp[ n ] );
+ if( rEntry.Name.equalsAscii( "Text" ) )
+ {
+ rEntry.Value >>= aText;
+ filterAccelerator( aText );
+ }
+ else if( rEntry.Name.equalsAscii( "ControlType" ) )
+ {
+ rEntry.Value >>= aCtrlType;
+ }
+ else if( rEntry.Name.equalsAscii( "Choices" ) )
+ {
+ rEntry.Value >>= aChoices;
+ }
+ else if( rEntry.Name.equalsAscii( "Property" ) )
+ {
+ PropertyValue aVal;
+ rEntry.Value >>= aVal;
+ aPropertyName = aVal.Name;
+ }
+ else if( rEntry.Name.equalsAscii( "Enabled" ) )
+ {
+ sal_Bool bValue = sal_True;
+ rEntry.Value >>= bValue;
+ bEnabled = bValue;
+ }
+ else if( rEntry.Name.equalsAscii( "MinValue" ) )
+ {
+ rEntry.Value >>= nMinValue;
+ }
+ else if( rEntry.Name.equalsAscii( "MaxValue" ) )
+ {
+ rEntry.Value >>= nMaxValue;
+ }
+ else if( rEntry.Name.equalsAscii( "AttachToDependency" ) )
+ {
+ nAttachOffset = 20;
+ }
+ else if( rEntry.Name.equalsAscii( "InternalUIOnly" ) )
+ {
+ rEntry.Value >>= bIgnore;
+ }
+ }
+
+ if( aCtrlType.equalsAscii( "Group" ) ||
+ aCtrlType.equalsAscii( "Subgroup" ) ||
+ aCtrlType.equalsAscii( "Radio" ) ||
+ aCtrlType.equalsAscii( "List" ) ||
+ aCtrlType.equalsAscii( "Edit" ) ||
+ aCtrlType.equalsAscii( "Range" ) ||
+ aCtrlType.equalsAscii( "Bool" ) )
+ {
+ // since our build target is MacOSX 10.4 we can have only one accessory view
+ // so we have a single accessory view that is tabbed for grouping
+ if( aCtrlType.equalsAscii( "Group" )
+ || ! pCurParent
+ || ( aCtrlType.equalsAscii( "Subgroup" ) && nCurY < -250 && ! bIgnore )
+ )
+ {
+ rtl::OUString aGroupTitle( aText );
+ if( aCtrlType.equalsAscii( "Subgroup" ) )
+ aGroupTitle = pControllerProperties->getMoreString();
+ // set size of current parent
+ if( pCurParent )
+ adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn );
+
+ // new tab item
+ if( ! aText.getLength() )
+ aText = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OOo" ) );
+ NSString* pLabel = CreateNSString( aGroupTitle );
+ NSTabViewItem* pItem = [[NSTabViewItem alloc] initWithIdentifier: pLabel ];
+ [pItem setLabel: pLabel];
+ [pTabView addTabViewItem: pItem];
+ pCurParent = [[NSView alloc] initWithFrame: aTabViewFrame];
+ [pItem setView: pCurParent];
+ [pLabel release];
+
+ // reset indent
+ nCurX = 20;
+ // reset Y
+ nCurY = 0;
+ // clear columns
+ aLeftColumn.clear();
+ aRightColumn.clear();
+ }
+
+ if( aCtrlType.equalsAscii( "Subgroup" ) && pCurParent )
+ {
+ bIgnoreSubgroup = bIgnore;
+ if( bIgnore )
+ continue;
+
+ NSControl* pTextView = createLabel( aText );
+ [pCurParent addSubview: [pTextView autorelease]];
+ NSRect aTextRect = [pTextView frame];
+ // move to nCurY
+ aTextRect.origin.y = nCurY - aTextRect.size.height;
+ [pTextView setFrame: aTextRect];
+
+ NSRect aSepRect = { { aTextRect.size.width + 1, aTextRect.origin.y }, { 100, 6 } };
+ NSBox* pBox = [[NSBox alloc] initWithFrame: aSepRect];
+ [pBox setBoxType: NSBoxSeparator];
+ [pCurParent addSubview: [pBox autorelease]];
+
+ // update nCurY
+ nCurY = aTextRect.origin.y - 5;
+ }
+ else if( bIgnoreSubgroup || bIgnore )
+ continue;
+ else if( aCtrlType.equalsAscii( "Bool" ) && pCurParent )
+ {
+ NSRect aCheckRect = { { nCurX + nAttachOffset, 0 }, { 0, 15 } };
+ NSButton* pBtn = [[NSButton alloc] initWithFrame: aCheckRect];
+ [pBtn setButtonType: NSSwitchButton];
+ sal_Bool bVal = sal_False;
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ if( pVal )
+ pVal->Value >>= bVal;
+ [pBtn setState: bVal ? NSOnState : NSOffState];
+ linebreakCell( [pBtn cell], aText );
+ [pBtn sizeToFit];
+ [pCurParent addSubview: [pBtn autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pBtn ) );
+
+ // connect target
+ [pBtn setTarget: pCtrlTarget];
+ [pBtn setAction: @selector(triggered:)];
+ int nTag = pControllerProperties->addNameTag( aPropertyName );
+ pControllerProperties->addObservedControl( pBtn );
+ [pBtn setTag: nTag];
+
+ aCheckRect = [pBtn frame];
+
+ // move to nCurY
+ aCheckRect.origin.y = nCurY - aCheckRect.size.height;
+ [pBtn setFrame: aCheckRect];
+
+ // update nCurY
+ nCurY = aCheckRect.origin.y - 5;
+ }
+ else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent )
+ {
+ sal_Int32 nOff = 0;
+ if( aText.getLength() )
+ {
+ // add a label
+ NSControl* pTextView = createLabel( aText );
+ NSRect aTextRect = [pTextView frame];
+ aTextRect.origin.x = nCurX + nAttachOffset;
+ [pCurParent addSubview: [pTextView autorelease]];
+
+ aLeftColumn.push_back( ColumnItem( pTextView ) );
+
+ // move to nCurY
+ aTextRect.origin.y = nCurY - aTextRect.size.height;
+ [pTextView setFrame: aTextRect];
+
+ // update nCurY
+ nCurY = aTextRect.origin.y - 5;
+
+ // indent the radio group relative to the text
+ // nOff = 20;
+ }
+
+ // setup radio matrix
+ NSButtonCell* pProto = [[NSButtonCell alloc] init];
+
+ NSRect aRadioRect = { { nCurX + nOff, 0 }, { 280 - nCurX, 5*aChoices.getLength() } };
+ [pProto setTitle: @"RadioButtonGroup"];
+ [pProto setButtonType: NSRadioButton];
+ NSMatrix* pMatrix = [[NSMatrix alloc] initWithFrame: aRadioRect
+ mode: NSRadioModeMatrix
+ prototype: (NSCell*)pProto
+ numberOfRows: aChoices.getLength()
+ numberOfColumns: 1];
+ // get currently selected value
+ sal_Int32 nSelectVal = 0;
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= nSelectVal;
+ // set individual titles
+ NSArray* pCells = [pMatrix cells];
+ for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
+ {
+ NSCell* pCell = [pCells objectAtIndex: m];
+ filterAccelerator( aChoices[m] );
+ linebreakCell( pCell, aChoices[m] );
+ //NSString* pTitle = CreateNSString( aChoices[m] );
+ //[pCell setTitle: pTitle];
+ // connect target and action
+ [pCell setTarget: pCtrlTarget];
+ [pCell setAction: @selector(triggered:)];
+ int nTag = pControllerProperties->addNameAndValueTag( aPropertyName, m );
+ pControllerProperties->addObservedControl( pCell );
+ [pCell setTag: nTag];
+ //[pTitle release];
+ // set current selection
+ if( nSelectVal == m )
+ [pMatrix selectCellAtRow: m column: 0];
+ }
+ [pMatrix sizeToFit];
+ aRadioRect = [pMatrix frame];
+
+ // move it down, so it comes to the correct position
+ aRadioRect.origin.y = nCurY - aRadioRect.size.height;
+ [pMatrix setFrame: aRadioRect];
+ [pCurParent addSubview: [pMatrix autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pMatrix ) );
+
+ // update nCurY
+ nCurY = aRadioRect.origin.y - 5;
+
+ [pProto release];
+ }
+ else if( aCtrlType.equalsAscii( "List" ) && pCurParent )
+ {
+ // don't indent attached lists, looks bad in the existing cases
+ NSControl* pTextView = createLabel( aText );
+ [pCurParent addSubview: [pTextView autorelease]];
+ aLeftColumn.push_back( ColumnItem( pTextView ) );
+ NSRect aTextRect = [pTextView frame];
+ aTextRect.origin.x = nCurX /* + nAttachOffset*/;
+
+ // don't indent attached lists, looks bad in the existing cases
+ NSRect aBtnRect = { { nCurX /*+ nAttachOffset*/ + aTextRect.size.width, 0 }, { 0, 15 } };
+ NSPopUpButton* pBtn = [[NSPopUpButton alloc] initWithFrame: aBtnRect pullsDown: NO];
+
+ // iterate options
+ for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
+ {
+ NSString* pItemText = CreateNSString( aChoices[m] );
+ [pBtn addItemWithTitle: pItemText];
+ NSMenuItem* pItem = [pBtn itemWithTitle: pItemText];
+ int nTag = pControllerProperties->addNameAndValueTag( aPropertyName, m );
+ [pItem setTag: nTag];
+ [pItemText release];
+ }
+
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ sal_Int32 aSelectVal = 0;
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= aSelectVal;
+ [pBtn selectItemAtIndex: aSelectVal];
+
+ // add the button to observed controls for enabled state changes
+ // also add a tag just for this purpose
+ pControllerProperties->addObservedControl( pBtn );
+ [pBtn setTag: pControllerProperties->addNameTag( aPropertyName )];
+
+ [pBtn sizeToFit];
+ [pCurParent addSubview: [pBtn autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pBtn ) );
+
+ // connect target and action
+ [pBtn setTarget: pCtrlTarget];
+ [pBtn setAction: @selector(triggered:)];
+
+ // move to nCurY
+ aBtnRect = [pBtn frame];
+ aBtnRect.origin.y = nCurY - aBtnRect.size.height;
+ [pBtn setFrame: aBtnRect];
+
+ // align label
+ aTextRect.origin.y = aBtnRect.origin.y + (aBtnRect.size.height - aTextRect.size.height)/2;
+ [pTextView setFrame: aTextRect];
+
+ // update nCurY
+ nCurY = aBtnRect.origin.y - 5;
+ }
+ else if( (aCtrlType.equalsAscii( "Edit" ) || aCtrlType.equalsAscii( "Range" )) && pCurParent )
+ {
+ sal_Int32 nOff = 0;
+ if( aText.getLength() )
+ {
+ // add a label
+ NSControl* pTextView = createLabel( aText );
+ [pCurParent addSubview: [pTextView autorelease]];
+
+ aLeftColumn.push_back( ColumnItem( pTextView ) );
+
+ // move to nCurY
+ NSRect aTextRect = [pTextView frame];
+ aTextRect.origin.x = nCurX + nAttachOffset;
+ aTextRect.origin.y = nCurY - aTextRect.size.height;
+ [pTextView setFrame: aTextRect];
+
+ // update nCurY
+ nCurY = aTextRect.origin.y - 5;
+
+ // and set the offset for the real edit field
+ nOff = aTextRect.size.width + 5;
+ }
+
+ NSRect aFieldRect = { { nCurX + nOff + nAttachOffset, 0 }, { 100, 25 } };
+ NSTextField* pFieldView = [[NSTextField alloc] initWithFrame: aFieldRect];
+ [pFieldView setEditable: YES];
+ [pFieldView setSelectable: YES];
+ [pFieldView setDrawsBackground: YES];
+ [pFieldView sizeToFit]; // FIXME: this does nothing
+ [pCurParent addSubview: [pFieldView autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pFieldView ) );
+
+ // add the field to observed controls for enabled state changes
+ // also add a tag just for this purpose
+ pControllerProperties->addObservedControl( pFieldView );
+ int nTag = pControllerProperties->addNameTag( aPropertyName );
+ [pFieldView setTag: nTag];
+ // pControllerProperties->addNamedView( pFieldView, aPropertyName );
+
+ // move to nCurY
+ aFieldRect.origin.y = nCurY - aFieldRect.size.height;
+ [pFieldView setFrame: aFieldRect];
+
+ // current value
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ if( aCtrlType.equalsAscii( "Range" ) )
+ {
+ // add a stepper control
+ NSRect aStepFrame = { { aFieldRect.origin.x + aFieldRect.size.width + 5,
+ aFieldRect.origin.y },
+ { 15, aFieldRect.size.height } };
+ NSStepper* pStep = [[NSStepper alloc] initWithFrame: aStepFrame];
+ [pStep setIncrement: 1];
+ [pStep setValueWraps: NO];
+ [pStep setTag: nTag];
+ [pCurParent addSubview: [pStep autorelease]];
+
+ aRightColumn.back().pSubControl = pStep;
+
+ pControllerProperties->addObservedControl( pStep );
+ [pStep setTarget: pCtrlTarget];
+ [pStep setAction: @selector(triggered:)];
+
+ // constrain the text field to decimal numbers
+ NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init];
+ [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4];
+ [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
+ [pFormatter setAllowsFloats: NO];
+ [pFormatter setMaximumFractionDigits: 0];
+ if( nMinValue != nMaxValue )
+ {
+ [pFormatter setMinimum: [[NSNumber numberWithInt: nMinValue] autorelease]];
+ [pStep setMinValue: nMinValue];
+ [pFormatter setMaximum: [[NSNumber numberWithInt: nMaxValue] autorelease]];
+ [pStep setMaxValue: nMaxValue];
+ }
+ [pFieldView setFormatter: pFormatter];
+
+ sal_Int64 nSelectVal = 0;
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= nSelectVal;
+
+ [pFieldView setIntValue: nSelectVal];
+ [pStep setIntValue: nSelectVal];
+
+ pControllerProperties->addViewPair( pFieldView, pStep );
+ // connect target and action
+ [pFieldView setTarget: pCtrlTarget];
+ [pFieldView setAction: @selector(triggeredNumeric:)];
+ [pStep setTarget: pCtrlTarget];
+ [pStep setAction: @selector(triggeredNumeric:)];
+ }
+ else
+ {
+ // connect target and action
+ [pFieldView setTarget: pCtrlTarget];
+ [pFieldView setAction: @selector(triggered:)];
+
+ if( pVal && pVal->Value.hasValue() )
+ {
+ rtl::OUString aValue;
+ pVal->Value >>= aValue;
+ if( aValue.getLength() )
+ {
+ NSString* pText = CreateNSString( aValue );
+ [pFieldView setStringValue: pText];
+ [pText release];
+ }
+ }
+ }
+
+ // update nCurY
+ nCurY = aFieldRect.origin.y - 5;
+
+ }
+ }
+ else
+ {
+ DBG_ERROR( "Unsupported UI option" );
+ }
+ }
+
+ pControllerProperties->updateEnableState();
+ adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn );
+
+ // leave some space for the preview
+ if( aMaxTabSize.height < 200 )
+ aMaxTabSize.height = 200;
+
+ // now reposition everything again so it is upper bound
+ adjustTabViews( pTabView, aMaxTabSize );
+
+ // find the minimum needed tab size
+ NSSize aTabCtrlSize = [pTabView minimumSize];
+ aTabCtrlSize.height += aMaxTabSize.height + 10;
+ if( aTabCtrlSize.width < aMaxTabSize.width + 10 )
+ aTabCtrlSize.width = aMaxTabSize.width + 10;
+ [pTabView setFrameSize: aTabCtrlSize];
+ aViewFrame.size.width = aTabCtrlSize.width + aTabViewFrame.origin.x;
+ aViewFrame.size.height = aTabCtrlSize.height + aTabViewFrame.origin.y;
+ [pAccessoryView setFrameSize: aViewFrame.size];
+
+ pControllerProperties->setupPreview( pCtrlTarget );
+
+ // set the accessory view
+ [pOp setAccessoryView: [pAccessoryView autorelease]];
+
+ // set the current selecte tab item
+ if( pState->nLastPage >= 0 && pState->nLastPage < [pTabView numberOfTabViewItems] )
+ [pTabView selectTabViewItemAtIndex: pState->nLastPage];
+
+ return pCtrlTarget;
+}
+
+@end
diff --git a/vcl/aqua/source/gdi/aquaprintview.mm b/vcl/aqua/source/gdi/aquaprintview.mm
new file mode 100755
index 000000000000..ae42c5c09e8d
--- /dev/null
+++ b/vcl/aqua/source/gdi/aquaprintview.mm
@@ -0,0 +1,82 @@
+/************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "aquaprintview.h"
+#include "salprn.h"
+#include "vcl/print.hxx"
+
+@implementation AquaPrintView
+-(id)initWithController: (vcl::PrinterController*)pController withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter
+{
+ NSRect aRect = { { 0, 0 }, [pInfoPrinter->getPrintInfo() paperSize] };
+ if( (self = [super initWithFrame: aRect]) != nil )
+ {
+ mpController = pController;
+ mpInfoPrinter = pInfoPrinter;
+ }
+ return self;
+}
+
+-(MacOSBOOL)knowsPageRange: (NSRangePointer)range
+{
+ range->location = 1;
+ range->length = mpInfoPrinter->getCurPageRangeCount();
+ return YES;
+}
+
+-(NSRect)rectForPage: (int)page
+{
+ NSSize aPaperSize = [mpInfoPrinter->getPrintInfo() paperSize];
+ int nWidth = (int)aPaperSize.width;
+ // #i101108# sanity check
+ if( nWidth < 1 )
+ nWidth = 1;
+ NSRect aRect = { { page % nWidth, page / nWidth }, aPaperSize };
+ return aRect;
+}
+
+-(NSPoint)locationOfPrintRect: (NSRect)aRect
+{
+ NSPoint aPoint = { 0, 0 };
+ return aPoint;
+}
+
+-(void)drawRect: (NSRect)rect
+{
+ NSPoint aPoint = [self locationOfPrintRect: rect];
+ mpInfoPrinter->setStartPageOffset( static_cast<int>(rect.origin.x), static_cast<int>(rect.origin.y) );
+ NSSize aPaperSize = [mpInfoPrinter->getPrintInfo() paperSize];
+ int nPage = (int)(aPaperSize.width * rect.origin.y + rect.origin.x);
+
+ // page count is 1 based
+ if( nPage - 1 < (mpInfoPrinter->getCurPageRangeStart() + mpInfoPrinter->getCurPageRangeCount() ) )
+ mpController->printFilteredPage( nPage-1 );
+}
+@end
diff --git a/vcl/aqua/source/gdi/makefile.mk b/vcl/aqua/source/gdi/makefile.mk
new file mode 100644
index 000000000000..2aea58e49250
--- /dev/null
+++ b/vcl/aqua/source/gdi/makefile.mk
@@ -0,0 +1,74 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=salgdi
+ENABLE_EXCEPTIONS=TRUE
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= $(SLO)$/salmathutils.obj \
+ $(SLO)$/salcolorutils.obj \
+ $(SLO)$/salgdiutils.obj \
+ $(SLO)$/salnativewidgets.obj \
+ $(SLO)$/salatsuifontutils.obj \
+ $(SLO)$/salatslayout.obj \
+ $(SLO)$/salgdi.obj \
+ $(SLO)$/salvd.obj \
+ $(SLO)$/salprn.obj \
+ $(SLO)$/aquaprintview.obj \
+ $(SLO)$/aquaprintaccessoryview.obj \
+ $(SLO)$/salbmp.obj
+
+.IF "$(ENABLE_CAIRO)" == "TRUE"
+CDEFS+= -DCAIRO
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/aqua/source/gdi/salatslayout.cxx b/vcl/aqua/source/gdi/salatslayout.cxx
new file mode 100755
index 000000000000..335505de85ac
--- /dev/null
+++ b/vcl/aqua/source/gdi/salatslayout.cxx
@@ -0,0 +1,1264 @@
+/*************************************************************************
+*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+#include "vcl/salgdi.hxx"
+#include "saldata.hxx"
+#include "salgdi.h"
+#include "vcl/sallayout.hxx"
+#include "salatsuifontutils.hxx"
+#include "tools/debug.hxx"
+
+#include <math.h>
+
+// =======================================================================
+
+class ATSLayout : public SalLayout
+{
+public:
+ ATSLayout( ATSUStyle&, float fFontScale );
+ virtual ~ATSLayout();
+
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
+
+ virtual long GetTextWidth() const;
+ virtual long FillDXArray( long* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+ virtual bool GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const;
+ virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const;
+
+ const ImplFontData* GetFallbackFontData( sal_GlyphId ) const;
+
+ virtual void InitFont();
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+
+private:
+ ATSUStyle& mrATSUStyle;
+ ATSUTextLayout maATSULayout;
+ int mnCharCount; // ==mnEndCharPos-mnMinCharPos
+ // to prevent ATS overflowing the Fixed16.16 values
+ // ATS font requests get size limited by downscaling huge fonts
+ // in these cases the font scale becomes something bigger than 1.0
+ float mfFontScale;
+
+private:
+ bool InitGIA( ImplLayoutArgs* pArgs = NULL ) const;
+ bool GetIdealX() const;
+ bool GetDeltaY() const;
+ void InvalidateMeasurements();
+
+ int Fixed2Vcl( Fixed ) const; // convert ATSU-Fixed units to VCL units
+ int AtsuPix2Vcl( int ) const; // convert ATSU-Pixel units to VCL units
+ Fixed Vcl2Fixed( int ) const; // convert VCL units to ATSU-Fixed units
+
+ // cached details about the resulting layout
+ // mutable members since these details are all lazy initialized
+ mutable int mnGlyphCount; // glyph count
+ mutable Fixed mnCachedWidth; // cached value of resulting typographical width
+ int mnTrailingSpaceWidth; // in Pixels
+
+ mutable ATSGlyphRef* mpGlyphIds; // ATSU glyph ids
+ mutable Fixed* mpCharWidths; // map relative charpos to charwidth
+ mutable int* mpChars2Glyphs; // map relative charpos to absolute glyphpos
+ mutable int* mpGlyphs2Chars; // map absolute glyphpos to absolute charpos
+ mutable bool* mpGlyphRTLFlags; // BiDi status for glyphs: true if RTL
+ mutable Fixed* mpGlyphAdvances; // contains glyph widths for the justified layout
+ mutable Fixed* mpGlyphOrigAdvs; // contains glyph widths for the unjustified layout
+ mutable Fixed* mpDeltaY; // vertical offset from the baseline
+
+ struct SubPortion { int mnMinCharPos, mnEndCharPos; Fixed mnXOffset; };
+ typedef std::vector<SubPortion> SubPortionVector;
+ mutable SubPortionVector maSubPortions; // Writer&ATSUI layouts can differ quite a bit...
+
+ // storing details about fonts used in glyph-fallback for this layout
+ mutable class FallbackInfo* mpFallbackInfo;
+
+ // x-offset relative to layout origin
+ // currently only used in RTL-layouts
+ mutable Fixed mnBaseAdv;
+};
+
+class FallbackInfo
+{
+public:
+ FallbackInfo() : mnMaxLevel(0) {}
+ int AddFallback( ATSUFontID );
+ const ImplFontData* GetFallbackFontData( int nLevel ) const;
+
+private:
+ const ImplMacFontData* maFontData[ MAX_FALLBACK ];
+ ATSUFontID maATSUFontId[ MAX_FALLBACK ];
+ int mnMaxLevel;
+};
+
+// =======================================================================
+
+ATSLayout::ATSLayout( ATSUStyle& rATSUStyle, float fFontScale )
+: mrATSUStyle( rATSUStyle ),
+ maATSULayout( NULL ),
+ mnCharCount( 0 ),
+ mfFontScale( fFontScale ),
+ mnGlyphCount( -1 ),
+ mnCachedWidth( 0 ),
+ mnTrailingSpaceWidth( 0 ),
+ mpGlyphIds( NULL ),
+ mpCharWidths( NULL ),
+ mpChars2Glyphs( NULL ),
+ mpGlyphs2Chars( NULL ),
+ mpGlyphRTLFlags( NULL ),
+ mpGlyphAdvances( NULL ),
+ mpGlyphOrigAdvs( NULL ),
+ mpDeltaY( NULL ),
+ mpFallbackInfo( NULL ),
+ mnBaseAdv( 0 )
+{}
+
+// -----------------------------------------------------------------------
+
+ATSLayout::~ATSLayout()
+{
+ if( mpDeltaY )
+ ATSUDirectReleaseLayoutDataArrayPtr( NULL,
+ kATSUDirectDataBaselineDeltaFixedArray, (void**)&mpDeltaY );
+
+ if( maATSULayout )
+ ATSUDisposeTextLayout( maATSULayout );
+
+ delete[] mpGlyphRTLFlags;
+ delete[] mpGlyphs2Chars;
+ delete[] mpChars2Glyphs;
+ if( mpCharWidths != mpGlyphAdvances )
+ delete[] mpCharWidths;
+ delete[] mpGlyphIds;
+ delete[] mpGlyphOrigAdvs;
+ delete[] mpGlyphAdvances;
+
+ delete mpFallbackInfo;
+}
+
+// -----------------------------------------------------------------------
+
+inline int ATSLayout::Fixed2Vcl( Fixed nFixed ) const
+{
+ float fFloat = mfFontScale * FixedToFloat( nFixed );
+ return static_cast<int>(fFloat + 0.5);
+}
+
+// -----------------------------------------------------------------------
+
+inline int ATSLayout::AtsuPix2Vcl( int nAtsuPixel) const
+{
+ float fVclPixel = mfFontScale * nAtsuPixel;
+ fVclPixel += (fVclPixel>=0) ? +0.5 : -0.5; // prepare rounding to int
+ int nVclPixel = static_cast<int>( fVclPixel);
+ return nVclPixel;
+}
+
+// -----------------------------------------------------------------------
+
+inline Fixed ATSLayout::Vcl2Fixed( int nPixel ) const
+{
+ return FloatToFixed( nPixel / mfFontScale );
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::LayoutText : Manage text layouting
+ *
+ * @param rArgs: contains array of char to be layouted, starting and ending position of the text to layout
+ *
+ * Typographic layout of text by using the style maATSUStyle
+ *
+ * @return : true if everything is ok
+**/
+bool ATSLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ if( maATSULayout )
+ ATSUDisposeTextLayout( maATSULayout );
+
+ maATSULayout = NULL;
+
+ // Layout text
+ // set up our locals, verify parameters...
+ DBG_ASSERT( (rArgs.mpStr!=NULL), "ATSLayout::LayoutText() with rArgs.mpStr==NULL !!!");
+ DBG_ASSERT( (mrATSUStyle!=NULL), "ATSLayout::LayoutText() with ATSUStyle==NULL !!!");
+
+ SalLayout::AdjustLayout( rArgs );
+ mnCharCount = mnEndCharPos - mnMinCharPos;
+
+ // Workaround a bug in ATSUI with empty string
+ if( mnCharCount<=0 )
+ return false;
+
+#if (OSL_DEBUG_LEVEL > 3)
+ Fixed fFontSize = 0;
+ ByteCount nDummy;
+ ATSUGetAttribute( mrATSUStyle, kATSUSizeTag, sizeof(fFontSize), &fFontSize, &nDummy);
+ String aUniName( &rArgs.mpStr[rArgs.mnMinCharPos], mnCharCount );
+ ByteString aCName( aUniName, RTL_TEXTENCODING_UTF8 );
+ fprintf( stderr, "ATSLayout( \"%s\" %d..%d of %d) with h=%4.1f\n",
+ aCName.GetBuffer(),rArgs.mnMinCharPos,rArgs.mnEndCharPos,rArgs.mnLength,Fix2X(fFontSize) );
+#endif
+
+ // create the ATSUI layout
+ UniCharCount nRunLengths[1] = { mnCharCount };
+ const int nRunCount = sizeof(nRunLengths)/sizeof(*nRunLengths);
+ OSStatus eStatus = ATSUCreateTextLayoutWithTextPtr( rArgs.mpStr,
+ rArgs.mnMinCharPos, mnCharCount, rArgs.mnLength,
+ nRunCount, &nRunLengths[0], &mrATSUStyle,
+ &maATSULayout);
+
+ DBG_ASSERT( (eStatus==noErr), "ATSUCreateTextLayoutWithTextPtr failed\n");
+ if( eStatus != noErr )
+ return false;
+
+ // prepare setting of layout controls
+ static const int nMaxTagCount = 1;
+ ATSUAttributeTag aTagAttrs[ nMaxTagCount ];
+ ByteCount aTagSizes[ nMaxTagCount ];
+ ATSUAttributeValuePtr aTagValues[ nMaxTagCount ];
+
+ // prepare control of "glyph fallback"
+ const SalData* pSalData = GetSalData();
+ ATSUFontFallbacks aFontFallbacks = pSalData->mpFontList->maFontFallbacks;
+ aTagAttrs[0] = kATSULineFontFallbacksTag;
+ aTagSizes[0] = sizeof( ATSUFontFallbacks );
+ aTagValues[0] = &aFontFallbacks;
+
+ // set paragraph layout controls
+ ATSUSetLayoutControls( maATSULayout, 1, aTagAttrs, aTagSizes, aTagValues );
+
+ // enable "glyph fallback"
+ ATSUSetTransientFontMatching( maATSULayout, true );
+
+ // control run-specific layout controls
+ if( (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG) != 0 )
+ {
+ // control BiDi defaults
+ MacOSBOOL nLineDirTag = kATSULeftToRightBaseDirection;
+ if( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) != 0 )
+ nLineDirTag = kATSURightToLeftBaseDirection;
+ aTagAttrs[0] = kATSULineDirectionTag;
+ aTagSizes[0] = sizeof( nLineDirTag );
+ aTagValues[0] = &nLineDirTag;
+ // set run-specific layout controls
+#if 0 // why don't line-controls work as reliably as layout-controls???
+ ATSUSetLineControls( maATSULayout, rArgs.mnMinCharPos, 1, aTagAttrs, aTagSizes, aTagValues );
+#else
+ ATSUSetLayoutControls( maATSULayout, 1, aTagAttrs, aTagSizes, aTagValues );
+#endif
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::AdjustLayout : Adjust layout style
+ *
+ * @param rArgs: contains attributes relevant to do a text specific layout
+ *
+ * Adjust text layout by moving glyphs to match the requested logical widths
+ *
+ * @return : none
+**/
+void ATSLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ int nOrigWidth = GetTextWidth();
+ int nPixelWidth = rArgs.mnLayoutWidth;
+ if( !nPixelWidth && rArgs.mpDXArray ) {
+ // for now we are only interested in the layout width
+ // TODO: use all mpDXArray elements for layouting
+ nPixelWidth = rArgs.mpDXArray[ mnCharCount - 1 ];
+
+ // workaround for ATSUI not using trailing spaces for justification
+ int i = mnCharCount;
+ while( (--i >= 0) && IsSpacingGlyph( rArgs.mpStr[mnMinCharPos+i]|GF_ISCHAR ) ) {}
+ if( i < 0 ) // nothing to do if the text is all spaces
+ return;
+ // #i91685# trailing letters are left aligned (right aligned for RTL)
+ mnTrailingSpaceWidth = rArgs.mpDXArray[ mnCharCount-1 ];
+ if( i > 0 )
+ mnTrailingSpaceWidth -= rArgs.mpDXArray[ i-1 ];
+ InitGIA(); // ensure valid mpCharWidths[], TODO: use GetIdealX() instead?
+ mnTrailingSpaceWidth -= Fixed2Vcl( mpCharWidths[i] );
+ // ignore trailing space for calculating the available width
+ nOrigWidth -= mnTrailingSpaceWidth;
+ nPixelWidth -= mnTrailingSpaceWidth;
+ // in RTL-layouts trailing spaces are leftmost
+ // TODO: use BiDi-algorithm to thoroughly check this assumption
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
+ mnBaseAdv = mnTrailingSpaceWidth;
+ }
+ // return early if there is nothing to do
+ if( !nPixelWidth )
+ return;
+
+ // HACK: justification requests which change the width by just one pixel were probably
+ // #i86038# introduced by lossy conversions between integer based coordinate system
+ // => ignoring such requests has many more benefits than eventual drawbacks
+ if( (nOrigWidth >= nPixelWidth-1) && (nOrigWidth <= nPixelWidth+1) )
+ return;
+
+ // changing the layout will make all previous measurements invalid
+ InvalidateMeasurements();
+
+ ATSUAttributeTag nTags[3];
+ ATSUAttributeValuePtr nVals[3];
+ ByteCount nBytes[3];
+
+ Fixed nFixedWidth = Vcl2Fixed( nPixelWidth );
+ mnCachedWidth = nFixedWidth;
+ Fract nFractFactor = kATSUFullJustification;
+ ATSLineLayoutOptions nLineLayoutOptions = kATSLineHasNoHangers | kATSLineHasNoOpticalAlignment | kATSLineBreakToNearestCharacter;
+
+ nTags[0] = kATSULineWidthTag;
+ nVals[0] = &nFixedWidth;
+ nBytes[0] = sizeof(Fixed);
+ nTags[1] = kATSULineLayoutOptionsTag;
+ nVals[1] = &nLineLayoutOptions;
+ nBytes[1] = sizeof(ATSLineLayoutOptions);
+ nTags[2] = kATSULineJustificationFactorTag;
+ nVals[2] = &nFractFactor;
+ nBytes[2] = sizeof(Fract);
+
+ OSStatus eStatus = ATSUSetLayoutControls( maATSULayout, 3, nTags, nBytes, nVals );
+ if( eStatus != noErr )
+ return;
+
+ // update the measurements of the justified layout to match the justification request
+ if( rArgs.mpDXArray )
+ InitGIA( &rArgs );
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::DrawText : Draw text to screen
+ *
+ * @param rGraphics: device to draw to
+ *
+ * Draw the layouted text to the CGContext
+ *
+ * @return : none
+**/
+void ATSLayout::DrawText( SalGraphics& rGraphics ) const
+{
+ AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
+
+ // short circuit if there is nothing to do
+ if( (mnCharCount <= 0)
+ || !rAquaGraphics.CheckContext() )
+ return;
+
+ // the view is vertically flipped => flipped glyphs
+ // so apply a temporary transformation that it flips back
+ // also compensate if the font was size limited
+ CGContextSaveGState( rAquaGraphics.mrContext );
+ CGContextScaleCTM( rAquaGraphics.mrContext, +mfFontScale, -mfFontScale );
+ CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText );
+
+ // prepare ATSUI drawing attributes
+ static const ItemCount nMaxControls = 8;
+ ATSUAttributeTag theTags[ nMaxControls ];
+ ByteCount theSizes[ nMaxControls];
+ ATSUAttributeValuePtr theValues[ nMaxControls ];
+ ItemCount numcontrols = 0;
+
+ // Tell ATSUI to use CoreGraphics
+ theTags[numcontrols] = kATSUCGContextTag;
+ theSizes[numcontrols] = sizeof( CGContextRef );
+ theValues[numcontrols++] = &rAquaGraphics.mrContext;
+
+ // Rotate if necessary
+ if( rAquaGraphics.mnATSUIRotation != 0 )
+ {
+ Fixed theAngle = rAquaGraphics.mnATSUIRotation;
+ theTags[numcontrols] = kATSULineRotationTag;
+ theSizes[numcontrols] = sizeof( Fixed );
+ theValues[numcontrols++] = &theAngle;
+ }
+
+ DBG_ASSERT( (numcontrols <= nMaxControls), "ATSLayout::DrawText() numcontrols overflow" );
+ OSStatus theErr = ATSUSetLayoutControls (maATSULayout, numcontrols, theTags, theSizes, theValues);
+ DBG_ASSERT( (theErr==noErr), "ATSLayout::DrawText ATSUSetLayoutControls failed!\n" );
+
+ // Draw the text
+ const Point aPos = GetDrawPosition( Point(mnBaseAdv,0) );
+ const Fixed nFixedX = Vcl2Fixed( +aPos.X() );
+ const Fixed nFixedY = Vcl2Fixed( -aPos.Y() ); // adjusted for y-mirroring
+ if( maSubPortions.empty() )
+ ATSUDrawText( maATSULayout, mnMinCharPos, mnCharCount, nFixedX, nFixedY );
+ else
+ {
+ // draw the sub-portions and apply individual adjustments
+ SubPortionVector::const_iterator it = maSubPortions.begin();
+ for(; it != maSubPortions.end(); ++it )
+ {
+ const SubPortion& rSubPortion = *it;
+ // calculate sub-portion offset for rotated text
+ Fixed nXOfsFixed = 0, nYOfsFixed = 0;
+ if( rAquaGraphics.mnATSUIRotation != 0 )
+ {
+ const double fRadians = rAquaGraphics.mnATSUIRotation * (M_PI/0xB40000);
+ nXOfsFixed = static_cast<Fixed>(static_cast<double>(+rSubPortion.mnXOffset) * cos( fRadians ));
+ nYOfsFixed = static_cast<Fixed>(static_cast<double>(+rSubPortion.mnXOffset) * sin( fRadians ));
+ }
+
+ // draw sub-portions
+ ATSUDrawText( maATSULayout,
+ rSubPortion.mnMinCharPos, rSubPortion.mnEndCharPos - rSubPortion.mnMinCharPos,
+ nFixedX + nXOfsFixed, nFixedY + nYOfsFixed );
+ }
+ }
+
+ // request an update of the changed window area
+ if( rAquaGraphics.IsWindowGraphics() )
+ {
+ Rect drawRect; // rectangle of the changed area
+ theErr = ATSUMeasureTextImage( maATSULayout,
+ mnMinCharPos, mnCharCount, nFixedX, nFixedY, &drawRect );
+ if( theErr == noErr )
+ {
+ // FIXME: transformation from baseline to top left
+ // with the simple approach below we invalidate too much
+ short d = drawRect.bottom - drawRect.top;
+ drawRect.top -= d;
+ drawRect.bottom += d;
+ CGRect aRect = CGRectMake( drawRect.left, drawRect.top,
+ drawRect.right - drawRect.left,
+ drawRect.bottom - drawRect.top );
+ aRect = CGContextConvertRectToDeviceSpace( rAquaGraphics.mrContext, aRect );
+ rAquaGraphics.RefreshRect( aRect );
+ }
+ }
+
+ // restore the original graphic context transformations
+ CGContextRestoreGState( rAquaGraphics.mrContext );
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetNextGlyphs : Get info about next glyphs in the layout
+ *
+ * @param nLen: max number of char
+ * @param pGlyphs: returned array of glyph ids
+ * @param rPos: returned x starting position
+ * @param nStart: index of the first requested glyph
+ * @param pGlyphAdvances: returned array of glyphs advances
+ * @param pCharIndexes: returned array of char indexes
+ *
+ * Returns infos about the next glyphs in the text layout
+ *
+ * @return : number of glyph details that were provided
+**/
+int ATSLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int& nStart,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
+{
+ if( nStart < 0 ) // first glyph requested?
+ nStart = 0;
+
+ // get glyph measurements
+ InitGIA();
+ // some measurements are only needed for multi-glyph results
+ if( nLen > 1 )
+ {
+ GetIdealX();
+ GetDeltaY();
+ }
+
+ if( nStart >= mnGlyphCount ) // no glyph left?
+ return 0;
+
+ // calculate glyph position relative to layout base
+ // TODO: avoid for nStart!=0 case by reusing rPos
+ Fixed nXOffset = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXOffset += mpGlyphAdvances[ i ];
+ // if sub-portion offsets are involved there is an additional x-offset
+ if( !maSubPortions.empty() )
+ {
+ // prepare to find the sub-portion
+ int nCharPos = nStart + mnMinCharPos;
+ if( mpGlyphs2Chars )
+ nCharPos = mpGlyphs2Chars[nStart];
+
+ // find the matching subportion
+ // TODO: is a non-linear search worth it?
+ SubPortionVector::const_iterator it = maSubPortions.begin();
+ for(; it != maSubPortions.end(); ++it) {
+ const SubPortion& r = *it;
+ if( nCharPos < r.mnMinCharPos )
+ continue;
+ if( nCharPos >= r.mnEndCharPos )
+ continue;
+ // apply the sub-portion xoffset
+ nXOffset += r.mnXOffset;
+ break;
+ }
+ }
+
+ Fixed nYOffset = 0;
+ if( mpDeltaY )
+ nYOffset = mpDeltaY[ nStart ];
+
+ // calculate absolute position in pixel units
+ const Point aRelativePos( Fix2Long(static_cast<Fixed>(nXOffset*mfFontScale)), Fix2Long(static_cast<Fixed>(nYOffset*mfFontScale)) );
+ rPos = GetDrawPosition( aRelativePos );
+
+ // update return values
+ int nCount = 0;
+ while( nCount < nLen )
+ {
+ ++nCount;
+ sal_GlyphId nGlyphId = mpGlyphIds[nStart];
+
+ // check if glyph fallback is needed for this glyph
+ // TODO: use ATSUDirectGetLayoutDataArrayPtrFromTextLayout(kATSUDirectDataStyleIndex) API instead?
+ const int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[nStart] : nStart + mnMinCharPos;
+ ATSUFontID nFallbackFontID = kATSUInvalidFontID;
+ UniCharArrayOffset nChangedOffset = 0;
+ UniCharCount nChangedLength = 0;
+ OSStatus eStatus = ATSUMatchFontsToText( maATSULayout, nCharPos, kATSUToTextEnd,
+ &nFallbackFontID, &nChangedOffset, &nChangedLength );
+ if( (eStatus == kATSUFontsMatched) && ((int)nChangedOffset == nCharPos) )
+ {
+ // fallback is needed
+ if( !mpFallbackInfo )
+ mpFallbackInfo = new FallbackInfo;
+ // register fallback font
+ const int nLevel = mpFallbackInfo->AddFallback( nFallbackFontID );
+ // update sal_GlyphId with fallback level
+ nGlyphId |= (nLevel << GF_FONTSHIFT);
+ }
+
+ // update resulting glyphid array
+ *(pGlyphIDs++) = nGlyphId;
+
+ // update returned glyph advance array
+ if( pGlyphAdvances )
+ *(pGlyphAdvances++) = Fixed2Vcl( mpGlyphAdvances[nStart] );
+
+ // update returned index-into-string array
+ if( pCharIndexes )
+ {
+ int nCharPos;
+ if( mpGlyphs2Chars )
+ nCharPos = mpGlyphs2Chars[nStart];
+ else
+ nCharPos = nStart + mnMinCharPos;
+ *(pCharIndexes++) = nCharPos;
+ }
+
+ // stop at last glyph
+ if( ++nStart >= mnGlyphCount )
+ break;
+
+ // stop when next the x-position is unexpected
+ if( !maSubPortions.empty() )
+ break; // TODO: finish the complete sub-portion
+ if( !pGlyphAdvances && mpGlyphOrigAdvs )
+ if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
+ break;
+
+ // stop when the next y-position is unexpected
+ if( mpDeltaY )
+ if( mpDeltaY[nStart-1] != mpDeltaY[nStart] )
+ break;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetTextWidth : Get typographic width of layouted text
+ *
+ * Get typographic bounds of the text
+ *
+ * @return : text width
+**/
+long ATSLayout::GetTextWidth() const
+{
+ if( mnCharCount <= 0 )
+ return 0;
+
+ DBG_ASSERT( (maATSULayout!=NULL), "ATSLayout::GetTextWidth() with maATSULayout==NULL !\n");
+ if( !maATSULayout )
+ return 0;
+
+ if( !mnCachedWidth )
+ {
+ // prepare precise measurements on pixel based or reference-device
+ const UInt16 eTypeOfBounds = kATSUseFractionalOrigins;
+
+ // determine number of needed measurement trapezoids
+ ItemCount nMaxBounds = 0;
+ OSStatus err = ATSUGetGlyphBounds( maATSULayout, 0, 0, mnMinCharPos, mnCharCount,
+ eTypeOfBounds, 0, NULL, &nMaxBounds );
+ if( (err != noErr)
+ || (nMaxBounds <= 0) )
+ return 0;
+
+ // get the trapezoids
+ typedef std::vector<ATSTrapezoid> TrapezoidVector;
+ TrapezoidVector aTrapezoidVector( nMaxBounds );
+ ItemCount nBoundsCount = 0;
+ err = ATSUGetGlyphBounds( maATSULayout, 0, 0, mnMinCharPos, mnCharCount,
+ eTypeOfBounds, nMaxBounds, &aTrapezoidVector[0], &nBoundsCount );
+ if( err != noErr )
+ return 0;
+
+ DBG_ASSERT( (nBoundsCount <= nMaxBounds), "ATSLayout::GetTextWidth() : too many trapezoids !\n");
+
+ // find the bound extremas
+ Fixed nLeftBound = 0;
+ Fixed nRightBound = 0;
+ for( ItemCount i = 0; i < nBoundsCount; ++i )
+ {
+ const ATSTrapezoid& rTrap = aTrapezoidVector[i];
+ if( (i == 0) || (nLeftBound < rTrap.lowerLeft.x) )
+ nLeftBound = rTrap.lowerLeft.x;
+ if( (i == 0) || (nRightBound > rTrap.lowerRight.x) )
+ nRightBound = rTrap.lowerRight.x;
+ }
+
+ // measure the bound extremas
+ mnCachedWidth = nRightBound - nLeftBound;
+ // adjust for eliminated trailing space widths
+ }
+
+ int nScaledWidth = Fixed2Vcl( mnCachedWidth );
+ nScaledWidth += mnTrailingSpaceWidth;
+ return nScaledWidth;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::FillDXArray : Get Char widths
+ *
+ * @param pDXArray: array to be filled with x-advances
+ *
+ * Fill the pDXArray with horizontal deltas : CharWidths
+ *
+ * @return : typographical width of the complete text layout
+**/
+long ATSLayout::FillDXArray( long* pDXArray ) const
+{
+ // short circuit requests which don't need full details
+ if( !pDXArray )
+ return GetTextWidth();
+
+ // check assumptions
+ DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::FillDXArray() with nTSW!=0" );
+
+ // initialize details about the resulting layout
+ InitGIA();
+
+ // distribute the widths among the string elements
+ int nPixWidth = 0;
+ mnCachedWidth = 0;
+ for( int i = 0; i < mnCharCount; ++i )
+ {
+ // convert and adjust for accumulated rounding errors
+ mnCachedWidth += mpCharWidths[i];
+ const int nOldPixWidth = nPixWidth;
+ nPixWidth = Fixed2Vcl( mnCachedWidth );
+ pDXArray[i] = nPixWidth - nOldPixWidth;
+ }
+
+ return nPixWidth;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetTextBreak : Find line break depending on width
+ *
+ * @param nMaxWidth : maximal logical text width in subpixel units
+ * @param nCharExtra: expanded/condensed spacing in subpixel units
+ * @param nFactor: number of subpixel units per pixel
+ *
+ * Measure the layouted text to find the typographical line break
+ * the result is needed by the language specific line breaking
+ *
+ * @return : string index corresponding to the suggested line break
+**/
+int ATSLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ if( !maATSULayout )
+ return STRING_LEN;
+
+ // the semantics of the legacy use case (nCharExtra!=0) cannot be mapped to ATSUBreakLine()
+ if( nCharExtra != 0 )
+ {
+ // prepare the measurement by layouting and measuring the un-expanded/un-condensed text
+ if( !InitGIA() )
+ return STRING_LEN;
+
+ // TODO: use a better way than by testing each the char position
+ ATSUTextMeasurement nATSUSumWidth = 0;
+ const ATSUTextMeasurement nATSUMaxWidth = Vcl2Fixed( nMaxWidth / nFactor );
+ const ATSUTextMeasurement nATSUExtraWidth = Vcl2Fixed( nCharExtra ) / nFactor;
+ for( int i = 0; i < mnCharCount; ++i )
+ {
+ nATSUSumWidth += mpCharWidths[i];
+ if( nATSUSumWidth >= nATSUMaxWidth )
+ return (mnMinCharPos + i);
+ nATSUSumWidth += nATSUExtraWidth;
+ if( nATSUSumWidth >= nATSUMaxWidth )
+ if( i+1 < mnCharCount )
+ return (mnMinCharPos + i);
+ }
+
+ return STRING_LEN;
+ }
+
+ // get a quick overview on what could fit
+ const long nPixelWidth = (nMaxWidth - (nCharExtra * mnCharCount)) / nFactor;
+ if( nPixelWidth <= 0 )
+ return mnMinCharPos;
+
+ // check assumptions
+ DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::GetTextBreak() with nTSW!=0" );
+
+ // initial measurement of text break position
+ UniCharArrayOffset nBreakPos = mnMinCharPos;
+ const ATSUTextMeasurement nATSUMaxWidth = Vcl2Fixed( nPixelWidth );
+ OSStatus eStatus = ATSUBreakLine( maATSULayout, mnMinCharPos,
+ nATSUMaxWidth, false, &nBreakPos );
+
+ if( (eStatus != noErr) && (eStatus != kATSULineBreakInWord) )
+ return STRING_LEN;
+
+ // the result from ATSUBreakLine() doesn't match the semantics expected by its
+ // application layer callers from SW+SVX+I18N. Adjust the results to the expectations:
+
+ // ATSU reports that everything fits even when trailing spaces would break the line
+ // #i89789# OOo's application layers expect STRING_LEN if everything fits
+ if( nBreakPos >= static_cast<UniCharArrayOffset>(mnEndCharPos) )
+ return STRING_LEN;
+
+ // GetTextBreak()'s callers expect it to return the "stupid visual line break".
+ // Returning anything else result.s in subtle problems in the application layers.
+ static const bool bInWord = true; // TODO: add as argument to GetTextBreak() method
+ if( !bInWord )
+ return nBreakPos;
+
+ // emulate stupid visual line breaking by line breaking for the remaining width
+ ATSUTextMeasurement nLeft, nRight, nDummy;
+ eStatus = ATSUGetUnjustifiedBounds( maATSULayout, mnMinCharPos, nBreakPos-mnMinCharPos,
+ &nLeft, &nRight, &nDummy, &nDummy );
+ if( eStatus != noErr )
+ return nBreakPos;
+ const ATSUTextMeasurement nATSURemWidth = nATSUMaxWidth - (nRight - nLeft);
+ if( nATSURemWidth <= 0 )
+ return nBreakPos;
+ UniCharArrayOffset nBreakPosInWord = nBreakPos;
+ eStatus = ATSUBreakLine( maATSULayout, nBreakPos, nATSURemWidth, false, &nBreakPosInWord );
+ return nBreakPosInWord;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetCaretPositions : Find positions of carets
+ *
+ * @param nMaxIndex position to which we want to find the carets
+ *
+ * Fill the array of positions of carets (for cursors and selections)
+ *
+ * @return : none
+**/
+void ATSLayout::GetCaretPositions( int nMaxIndex, long* pCaretXArray ) const
+{
+ DBG_ASSERT( ((nMaxIndex>0)&&!(nMaxIndex&1)),
+ "ATSLayout::GetCaretPositions() : invalid number of caret pairs requested");
+
+ // initialize the caret positions
+ for( int i = 0; i < nMaxIndex; ++i )
+ pCaretXArray[ i ] = -1;
+
+ for( int n = 0; n <= mnCharCount; ++n )
+ {
+ // measure the characters cursor position
+ typedef unsigned char Boolean;
+ const Boolean bIsLeading = true;
+ ATSUCaret aCaret0, aCaret1;
+ Boolean bIsSplit;
+ OSStatus eStatus = ATSUOffsetToCursorPosition( maATSULayout,
+ mnMinCharPos + n, bIsLeading, kATSUByCharacter,
+ &aCaret0, &aCaret1, &bIsSplit );
+ if( eStatus != noErr )
+ continue;
+ const Fixed nFixedPos = mnBaseAdv + aCaret0.fX;
+ // convert the measurement to pixel units
+ const int nPixelPos = Fixed2Vcl( nFixedPos );
+ // update previous trailing position
+ if( n > 0 )
+ pCaretXArray[2*n-1] = nPixelPos;
+ // update current leading position
+ if( 2*n >= nMaxIndex )
+ break;
+ pCaretXArray[2*n+0] = nPixelPos;
+ }
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetBoundRect : Get rectangle dim containing the layouted text
+ *
+ * @param rVCLRect: rectangle of text image (layout) measures
+ *
+ * Get ink bounds of the text
+ *
+ * @return : measurement valid
+**/
+bool ATSLayout::GetBoundRect( SalGraphics&, Rectangle& rVCLRect ) const
+{
+ const Point aPos = GetDrawPosition( Point(mnBaseAdv, 0) );
+ const Fixed nFixedX = Vcl2Fixed( +aPos.X() );
+ const Fixed nFixedY = Vcl2Fixed( +aPos.Y() );
+
+ Rect aMacRect;
+ OSStatus eStatus = ATSUMeasureTextImage( maATSULayout,
+ mnMinCharPos, mnCharCount, nFixedX, nFixedY, &aMacRect );
+ if( eStatus != noErr )
+ return false;
+
+ // ATSU top-bottom are vertically flipped from a VCL aspect
+ rVCLRect.Left() = AtsuPix2Vcl( aMacRect.left );
+ rVCLRect.Top() = AtsuPix2Vcl( aMacRect.top );
+ rVCLRect.Right() = AtsuPix2Vcl( aMacRect.right );
+ rVCLRect.Bottom() = AtsuPix2Vcl( aMacRect.bottom );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::InitGIA() : get many informations about layouted text
+ *
+ * Fills arrays of information about the gylph layout previously done
+ * in ASTLayout::LayoutText() : glyph advance (width), glyph delta Y (from baseline),
+ * mapping between glyph index and character index, chars widths
+ *
+ * @return : true if everything could be computed, otherwise false
+**/
+bool ATSLayout::InitGIA( ImplLayoutArgs* pArgs ) const
+{
+ // no need to run InitGIA more than once on the same ATSLayout object
+ if( mnGlyphCount >= 0 )
+ return true;
+ mnGlyphCount = 0;
+
+ // Workaround a bug in ATSUI with empty string
+ if( mnCharCount <= 0 )
+ return false;
+
+ // initialize character details
+ mpCharWidths = new Fixed[ mnCharCount ];
+ mpChars2Glyphs = new int[ mnCharCount ];
+ for( int n = 0; n < mnCharCount; ++n )
+ {
+ mpCharWidths[ n ] = 0;
+ mpChars2Glyphs[ n ] = -1;
+ }
+
+ // get details about the glyph layout
+ ItemCount iLayoutDataCount;
+ const ATSLayoutRecord* pALR;
+ OSStatus eStatus = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
+ maATSULayout, mnMinCharPos, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void**)&pALR, &iLayoutDataCount );
+ DBG_ASSERT( (eStatus==noErr), "ATSLayout::InitGIA() : no ATSLayoutRecords!\n");
+ if( (eStatus != noErr)
+ || (iLayoutDataCount <= 1) )
+ return false;
+
+ // initialize glyph details
+ mpGlyphIds = new ATSGlyphRef[ iLayoutDataCount ];
+ mpGlyphAdvances = new Fixed[ iLayoutDataCount ];
+ mpGlyphs2Chars = new int[ iLayoutDataCount ];
+
+ // measure details of the glyph layout
+ Fixed nLeftPos = 0;
+ for( ItemCount i = 0; i < iLayoutDataCount; ++i )
+ {
+ const ATSLayoutRecord& rALR = pALR[i];
+
+ // distribute the widths as fairly as possible among the chars
+ const int nRelativeIdx = (rALR.originalOffset / 2);
+ if( i+1 < iLayoutDataCount )
+ mpCharWidths[ nRelativeIdx ] += pALR[i+1].realPos - rALR.realPos;
+
+ // new glyph is available => finish measurement of old glyph
+ if( mnGlyphCount > 0 )
+ mpGlyphAdvances[ mnGlyphCount-1 ] = rALR.realPos - nLeftPos;
+
+ // ignore marker or deleted glyphs
+ enum { MARKED_OUTGLYPH=0xFFFE, DROPPED_OUTGLYPH=0xFFFF};
+ if( rALR.glyphID >= MARKED_OUTGLYPH )
+ continue;
+
+ DBG_ASSERT( !(rALR.flags & kATSGlyphInfoTerminatorGlyph),
+ "ATSLayout::InitGIA(): terminator glyph not marked as deleted!" );
+
+ // store details of the visible glyphs
+ nLeftPos = rALR.realPos;
+ mpGlyphIds[ mnGlyphCount ] = rALR.glyphID;
+
+ // map visible glyphs to their counterparts in the UTF16-character array
+ mpGlyphs2Chars[ mnGlyphCount ] = nRelativeIdx + mnMinCharPos;
+ mpChars2Glyphs[ nRelativeIdx ] = mnGlyphCount;
+
+ ++mnGlyphCount;
+ }
+
+ // measure complete width
+ mnCachedWidth = mnBaseAdv;
+ mnCachedWidth += pALR[iLayoutDataCount-1].realPos - pALR[0].realPos;
+
+#if (OSL_DEBUG_LEVEL > 1)
+ Fixed nWidthSum = mnBaseAdv;
+ for( int n = 0; n < mnCharCount; ++n )
+ nWidthSum += mpCharWidths[ n ];
+ DBG_ASSERT( (nWidthSum==mnCachedWidth),
+ "ATSLayout::InitGIA(): measured widths do not match!\n" );
+#endif
+
+ // #i91183# we need to split up the portion into sub-portions
+ // if the ATSU-layout differs too much from the requested layout
+ if( pArgs && pArgs->mpDXArray )
+ {
+ // TODO: non-strong-LTR case cases should be handled too
+ if( (pArgs->mnFlags & TEXT_LAYOUT_BIDI_STRONG)
+ && !(pArgs->mnFlags & TEXT_LAYOUT_BIDI_RTL) )
+ {
+ Fixed nSumCharWidths = 0;
+ SubPortion aSubPortion = { mnMinCharPos, 0, 0 };
+ for( int i = 0; i < mnCharCount; ++i )
+ {
+ // calculate related logical position
+ nSumCharWidths += mpCharWidths[i];
+
+ // start new sub-portion if needed
+ const Fixed nNextXPos = Vcl2Fixed(pArgs->mpDXArray[i]);
+ const Fixed nNextXOffset = nNextXPos - nSumCharWidths;
+ const Fixed nFixedDiff = aSubPortion.mnXOffset - nNextXOffset;
+ if( (nFixedDiff < -0xC000) || (nFixedDiff > +0xC000) ) {
+ // get to the end of the current sub-portion
+ // prevent splitting up at diacritics etc.
+ int j = i;
+ while( (++j < mnCharCount) && !mpCharWidths[j] );
+ aSubPortion.mnEndCharPos = mnMinCharPos + j;
+ // emit current sub-portion
+ maSubPortions.push_back( aSubPortion );
+ // prepare next sub-portion
+ aSubPortion.mnMinCharPos = aSubPortion.mnEndCharPos;
+ aSubPortion.mnXOffset = nNextXOffset;
+ }
+ }
+
+ // emit the remaining sub-portion
+ if( !maSubPortions.empty() )
+ {
+ aSubPortion.mnEndCharPos = mnEndCharPos;
+ if( aSubPortion.mnEndCharPos != aSubPortion.mnMinCharPos )
+ maSubPortions.push_back( aSubPortion );
+ }
+ }
+
+ // override layouted charwidths with requested charwidths
+ for( int n = 0; n < mnCharCount; ++n )
+ mpCharWidths[ n ] = pArgs->mpDXArray[ n ];
+ }
+
+ // release the ATSU layout records
+ ATSUDirectReleaseLayoutDataArrayPtr(NULL,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&pALR );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ATSLayout::GetIdealX() const
+{
+ // compute the ideal advance widths only once
+ if( mpGlyphOrigAdvs != NULL )
+ return true;
+
+ DBG_ASSERT( (mpGlyphIds!=NULL), "GetIdealX() called with mpGlyphIds==NULL !" );
+ DBG_ASSERT( (mrATSUStyle!=NULL), "GetIdealX called with mrATSUStyle==NULL !" );
+
+ // TODO: cache ideal metrics per glyph?
+ std::vector<ATSGlyphIdealMetrics> aIdealMetrics;
+ aIdealMetrics.resize( mnGlyphCount );
+ OSStatus theErr = ATSUGlyphGetIdealMetrics( mrATSUStyle,
+ mnGlyphCount, &mpGlyphIds[0], sizeof(*mpGlyphIds), &aIdealMetrics[0] );
+ DBG_ASSERT( (theErr==noErr), "ATSUGlyphGetIdealMetrics failed!");
+ if( theErr != noErr )
+ return false;
+
+ mpGlyphOrigAdvs = new Fixed[ mnGlyphCount ];
+ for( int i = 0;i < mnGlyphCount;++i )
+ mpGlyphOrigAdvs[i] = FloatToFixed( aIdealMetrics[i].advance.x );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ATSLayout::GetDeltaY() const
+{
+ // don't bother to get the same delta-y-array more than once
+ if( mpDeltaY != NULL )
+ return true;
+
+#if 1
+ if( !maATSULayout )
+ return false;
+
+ // get and keep the y-deltas in the mpDeltaY member variable
+ // => release it in the destructor
+ ItemCount nDeltaCount = 0;
+ OSStatus theErr = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
+ maATSULayout, mnMinCharPos, kATSUDirectDataBaselineDeltaFixedArray,
+ (void**)&mpDeltaY, &nDeltaCount );
+
+ DBG_ASSERT( (theErr==noErr ), "mpDeltaY - ATSUDirectGetLayoutDataArrayPtrFromTextLayout failed!\n");
+ if( theErr != noErr )
+ return false;
+
+ if( mpDeltaY == NULL )
+ return true;
+
+ if( nDeltaCount != (ItemCount)mnGlyphCount )
+ {
+ DBG_WARNING( "ATSLayout::GetDeltaY() : wrong deltaY count!" );
+ ATSUDirectReleaseLayoutDataArrayPtr( NULL,
+ kATSUDirectDataBaselineDeltaFixedArray, (void**)&mpDeltaY );
+ mpDeltaY = NULL;
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+#define DELETEAZ( X ) { delete[] X; X = NULL; }
+
+void ATSLayout::InvalidateMeasurements()
+{
+ mnGlyphCount = -1;
+ DELETEAZ( mpGlyphIds );
+ DELETEAZ( mpCharWidths );
+ DELETEAZ( mpChars2Glyphs );
+ DELETEAZ( mpGlyphs2Chars );
+ DELETEAZ( mpGlyphRTLFlags );
+ DELETEAZ( mpGlyphAdvances );
+ DELETEAZ( mpGlyphOrigAdvs );
+ DELETEAZ( mpDeltaY );
+}
+
+// =======================================================================
+
+#if 0
+// helper class to convert ATSUI outlines to VCL PolyPolygons
+class PolyArgs
+{
+public:
+ PolyArgs();
+ ~PolyArgs();
+
+ void Init( PolyPolygon* pPolyPoly, long nXOffset, long nYOffset );
+ void AddPoint( const Float32Point&, PolyFlags );
+ void ClosePolygon();
+
+private:
+ PolyPolygon* mpPolyPoly;
+ long mnXOffset, mnYOffset;
+
+ Point* mpPointAry;
+ BYTE* mpFlagAry;
+ USHORT mnMaxPoints;
+
+ USHORT mnPointCount;
+ USHORT mnPolyCount;
+ bool mbHasOffline;
+};
+
+// -----------------------------------------------------------------------
+
+PolyArgs::PolyArgs()
+: mpPolyPoly(NULL),
+ mnPointCount(0),
+ mnPolyCount(0),
+ mbHasOffline(false)
+{
+ mnMaxPoints = 256;
+ mpPointAry = new Point[ mnMaxPoints ];
+ mpFlagAry = new BYTE [ mnMaxPoints ];
+}
+
+// -----------------------------------------------------------------------
+
+PolyArgs::~PolyArgs()
+{
+ delete[] mpFlagAry;
+ delete[] mpPointAry;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::Init( PolyPolygon* pPolyPoly, long nXOffset, long nYOffset )
+{
+ mnXOffset = nXOffset;
+ mnYOffset = nYOffset;
+ mpPolyPoly = pPolyPoly;
+
+ mpPolyPoly->Clear();
+ mnPointCount = 0;
+ mnPolyCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::AddPoint( const Float32Point& rPoint, PolyFlags eFlags )
+{
+ if( mnPointCount >= mnMaxPoints )
+ {
+ // resize if needed (TODO: use STL?)
+ mnMaxPoints *= 4;
+ Point* mpNewPoints = new Point[ mnMaxPoints ];
+ BYTE* mpNewFlags = new BYTE[ mnMaxPoints ];
+ for( int i = 0; i < mnPointCount; ++i )
+ {
+ mpNewPoints[ i ] = mpPointAry[ i ];
+ mpNewFlags[ i ] = mpFlagAry[ i ];
+ }
+ delete[] mpFlagAry;
+ delete[] mpPointAry;
+ mpPointAry = mpNewPoints;
+ mpFlagAry = mpNewFlags;
+ }
+
+ // convert to pixels and add startpoint offset
+ int nXPos = Float32ToInt( rPoint.x );
+ int nYPos = Float32ToInt( rPoint.y );
+ mpPointAry[ mnPointCount ] = Point( nXPos + mnXOffset, nYPos + mnYOffset );
+ // set point flags
+ mpFlagAry[ mnPointCount++ ]= eFlags;
+ mbHasOffline |= (eFlags != POLY_NORMAL);
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::ClosePolygon()
+{
+ if( !mnPolyCount++ )
+ return;
+
+ // append finished polygon
+ Polygon aPoly( mnPointCount, mpPointAry, (mbHasOffline ? mpFlagAry : NULL) );
+ mpPolyPoly->Insert( aPoly );
+
+ // prepare for new polygon
+ mnPointCount = 0;
+ mbHasOffline = false;
+}
+#endif
+// =======================================================================
+
+// glyph fallback is supported directly by Aqua
+// so methods used only by MultiSalLayout can be dummy implementated
+bool ATSLayout::GetGlyphOutlines( SalGraphics&, PolyPolyVector& rPPV ) const { return false; }
+void ATSLayout::InitFont() {}
+void ATSLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
+void ATSLayout::DropGlyph( int /*nStart*/ ) {}
+void ATSLayout::Simplify( bool /*bIsBase*/ ) {}
+
+// get the ImplFontData for a glyph fallback font
+// for a glyphid that was returned by ATSLayout::GetNextGlyphs()
+const ImplFontData* ATSLayout::GetFallbackFontData( sal_GlyphId nGlyphId ) const
+{
+ // check if any fallback fonts were needed
+ if( !mpFallbackInfo )
+ return NULL;
+ // check if the current glyph needs a fallback font
+ int nFallbackLevel = (nGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
+ if( !nFallbackLevel )
+ return NULL;
+ return mpFallbackInfo->GetFallbackFontData( nFallbackLevel );
+}
+
+// =======================================================================
+
+int FallbackInfo::AddFallback( ATSUFontID nFontId )
+{
+ // check if the fallback font is already known
+ for( int nLevel = 0; nLevel < mnMaxLevel; ++nLevel )
+ if( maATSUFontId[ nLevel ] == nFontId )
+ return (nLevel + 1);
+
+ // append new fallback font if possible
+ if( mnMaxLevel >= MAX_FALLBACK-1 )
+ return 0;
+ // keep ATSU font id of fallback font
+ maATSUFontId[ mnMaxLevel ] = nFontId;
+ // find and cache the corresponding ImplFontData pointer
+ const SystemFontList* pSFL = GetSalData()->mpFontList;
+ const ImplMacFontData* pFontData = pSFL->GetFontDataFromId( nFontId );
+ maFontData[ mnMaxLevel ] = pFontData;
+ // increase fallback level by one
+ return (++mnMaxLevel);
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontData* FallbackInfo::GetFallbackFontData( int nFallbackLevel ) const
+{
+ const ImplMacFontData* pFallbackFont = maFontData[ nFallbackLevel-1 ];
+ return pFallbackFont;
+}
+
+// =======================================================================
+
+SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ ATSLayout* pATSLayout = new ATSLayout( maATSUStyle, mfFontScale );
+ return pATSLayout;
+}
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salatsuifontutils.cxx b/vcl/aqua/source/gdi/salatsuifontutils.cxx
new file mode 100644
index 000000000000..8281c41ceeab
--- /dev/null
+++ b/vcl/aqua/source/gdi/salatsuifontutils.cxx
@@ -0,0 +1,552 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <boost/assert.hpp>
+#include <vector>
+#include <set>
+
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "vcl/svapp.hxx"
+#include "salatsuifontutils.hxx"
+
+// we have to get the font attributes from the name table
+// since neither head's macStyle nor OS/2's panose are easily available
+// during font enumeration. macStyle bits would be not sufficient anyway
+// and SFNT fonts on Mac usually do not contain an OS/2 table.
+static void UpdateAttributesFromPSName( const String& rPSName, ImplDevFontAttributes& rDFA )
+{
+ ByteString aPSName( rPSName, RTL_TEXTENCODING_UTF8 );
+ aPSName.ToLowerAscii();
+
+ // TODO: use a multi-string ignore-case matcher once it becomes available
+ if( (aPSName.Search("regular") != STRING_NOTFOUND)
+ || (aPSName.Search("normal") != STRING_NOTFOUND)
+ || (aPSName.Search("roman") != STRING_NOTFOUND)
+ || (aPSName.Search("medium") != STRING_NOTFOUND)
+ || (aPSName.Search("plain") != STRING_NOTFOUND)
+ || (aPSName.Search("standard") != STRING_NOTFOUND)
+ || (aPSName.Search("std") != STRING_NOTFOUND) )
+ {
+ rDFA.meWidthType = WIDTH_NORMAL;
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ }
+
+ // heuristics for font weight
+ if (aPSName.Search("extrablack") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ else if (aPSName.Search("black") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ //else if (aPSName.Search("book") != STRING_NOTFOUND)
+ // rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if( (aPSName.Search("semibold") != STRING_NOTFOUND)
+ || (aPSName.Search("smbd") != STRING_NOTFOUND))
+ rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if (aPSName.Search("ultrabold") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRABOLD;
+ else if (aPSName.Search("extrabold") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ else if( (aPSName.Search("bold") != STRING_NOTFOUND)
+ || (aPSName.Search("-bd") != STRING_NOTFOUND))
+ rDFA.meWeight = WEIGHT_BOLD;
+ else if (aPSName.Search("extralight") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRALIGHT;
+ else if (aPSName.Search("ultralight") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRALIGHT;
+ else if (aPSName.Search("light") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_LIGHT;
+ else if (aPSName.Search("thin") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_THIN;
+ else if (aPSName.Search("-w3") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_LIGHT;
+ else if (aPSName.Search("-w4") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_SEMILIGHT;
+ else if (aPSName.Search("-w5") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_NORMAL;
+ else if (aPSName.Search("-w6") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if (aPSName.Search("-w7") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BOLD;
+ else if (aPSName.Search("-w8") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRABOLD;
+ else if (aPSName.Search("-w9") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+
+ // heuristics for font slant
+ if( (aPSName.Search("italic") != STRING_NOTFOUND)
+ || (aPSName.Search(" ital") != STRING_NOTFOUND)
+ || (aPSName.Search("cursive") != STRING_NOTFOUND)
+ || (aPSName.Search("-it") != STRING_NOTFOUND)
+ || (aPSName.Search("lightit") != STRING_NOTFOUND)
+ || (aPSName.Search("mediumit") != STRING_NOTFOUND)
+ || (aPSName.Search("boldit") != STRING_NOTFOUND)
+ || (aPSName.Search("cnit") != STRING_NOTFOUND)
+ || (aPSName.Search("bdcn") != STRING_NOTFOUND)
+ || (aPSName.Search("bdit") != STRING_NOTFOUND)
+ || (aPSName.Search("condit") != STRING_NOTFOUND)
+ || (aPSName.Search("bookit") != STRING_NOTFOUND)
+ || (aPSName.Search("blackit") != STRING_NOTFOUND) )
+ rDFA.meItalic = ITALIC_NORMAL;
+ if( (aPSName.Search("oblique") != STRING_NOTFOUND)
+ || (aPSName.Search("inclined") != STRING_NOTFOUND)
+ || (aPSName.Search("slanted") != STRING_NOTFOUND) )
+ rDFA.meItalic = ITALIC_OBLIQUE;
+
+ // heuristics for font width
+ if( (aPSName.Search("condensed") != STRING_NOTFOUND)
+ || (aPSName.Search("-cond") != STRING_NOTFOUND)
+ || (aPSName.Search("boldcond") != STRING_NOTFOUND)
+ || (aPSName.Search("boldcn") != STRING_NOTFOUND)
+ || (aPSName.Search("cnit") != STRING_NOTFOUND) )
+ rDFA.meWidthType = WIDTH_CONDENSED;
+ else if (aPSName.Search("narrow") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_SEMI_CONDENSED;
+ else if (aPSName.Search("expanded") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_EXPANDED;
+ else if (aPSName.Search("wide") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_EXPANDED;
+
+ // heuristics for font pitch
+ if( (aPSName.Search("mono") != STRING_NOTFOUND)
+ || (aPSName.Search("courier") != STRING_NOTFOUND)
+ || (aPSName.Search("monaco") != STRING_NOTFOUND)
+ || (aPSName.Search("typewriter") != STRING_NOTFOUND) )
+ rDFA.mePitch = PITCH_FIXED;
+
+ // heuristics for font family type
+ if( (aPSName.Search("script") != STRING_NOTFOUND)
+ || (aPSName.Search("chancery") != STRING_NOTFOUND)
+ || (aPSName.Search("zapfino") != STRING_NOTFOUND))
+ rDFA.meFamily = FAMILY_SCRIPT;
+ else if( (aPSName.Search("comic") != STRING_NOTFOUND)
+ || (aPSName.Search("outline") != STRING_NOTFOUND)
+ || (aPSName.Search("pinpoint") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ else if( (aPSName.Search("sans") != STRING_NOTFOUND)
+ || (aPSName.Search("arial") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_SWISS;
+ else if( (aPSName.Search("roman") != STRING_NOTFOUND)
+ || (aPSName.Search("times") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_ROMAN;
+
+ // heuristics for codepoint semantic
+ if( (aPSName.Search("symbol") != STRING_NOTFOUND)
+ || (aPSName.Search("dings") != STRING_NOTFOUND)
+ || (aPSName.Search("dingbats") != STRING_NOTFOUND)
+ || (aPSName.Search("ornaments") != STRING_NOTFOUND)
+ || (aPSName.Search("embellishments") != STRING_NOTFOUND) )
+ rDFA.mbSymbolFlag = true;
+
+ // #i100020# special heuristic for names with single-char styles
+ // NOTE: we are checking name that hasn't been lower-cased
+ if( rPSName.Len() > 3 )
+ {
+ int i = rPSName.Len();
+ sal_Unicode c = rPSName.GetChar( --i );
+ if( c == 'C' ) { // "capitals"
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'O' ) { // CFF-based OpenType
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'I' ) { // "italic"
+ rDFA.meItalic = ITALIC_NORMAL;
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'B' ) // "bold"
+ rDFA.meWeight = WEIGHT_BOLD;
+ if( c == 'C' ) // "capitals"
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ // TODO: check that all single-char styles have been resolved?
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA )
+{
+ // all ATSU fonts are device fonts that can be directly rotated
+ rDFA.mbOrientation = true;
+ rDFA.mbDevice = true;
+ rDFA.mnQuality = 0;
+
+ // reset the attributes
+ rDFA.meFamily = FAMILY_DONTKNOW;
+ rDFA.mePitch = PITCH_VARIABLE;
+ rDFA.meWidthType = WIDTH_NORMAL;
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ rDFA.mbSymbolFlag = false;
+
+ // ignore bitmap fonts
+ ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID );
+ ByteCount nHeadLen = 0;
+ OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen );
+ if( (rc != noErr) || (nHeadLen <= 0) )
+ return false;
+
+ // all scalable fonts on this platform are subsettable
+ rDFA.mbSubsettable = true;
+ rDFA.mbEmbeddable = false;
+
+ // prepare iterating over all name strings of the font
+ ItemCount nFontNameCount = 0;
+ rc = ATSUCountFontNames( nFontID, &nFontNameCount );
+ if( rc != noErr )
+ return false;
+ int nBestNameValue = 0;
+ int nBestStyleValue = 0;
+ FontLanguageCode eBestLangCode = 0;
+ const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage();
+ typedef std::vector<char> NameBuffer;
+ NameBuffer aNameBuffer( 256 );
+
+ // iterate over all available name strings of the font
+ for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex )
+ {
+ ByteCount nNameLength = 0;
+
+ FontNameCode eFontNameCode;
+ FontPlatformCode eFontNamePlatform;
+ FontScriptCode eFontNameScript;
+ FontLanguageCode eFontNameLanguage;
+ rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL,
+ &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
+ if( rc != noErr )
+ continue;
+
+ // ignore non-interesting name entries
+ if( (eFontNameCode != kFontFamilyName)
+ && (eFontNameCode != kFontStyleName)
+ && (eFontNameCode != kFontPostscriptName) )
+ continue;
+
+ // heuristic to find the most common font name
+ // prefering default language names or even better the names matching to the UI language
+ int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20);
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE;
+ const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript;
+ switch( nPlatformEncoding )
+ {
+ case 0x000: nNameValue += 23; break; // Unicode 1.0
+ case 0x001: nNameValue += 24; break; // Unicode 1.1
+ case 0x002: nNameValue += 25; break; // iso10646_1993
+ case 0x003: nNameValue += 26; break; // UCS-2
+ case 0x301: nNameValue += 27; break; // Win UCS-2
+ case 0x004: // UCS-4
+ case 0x30A: nNameValue += 0; // Win-UCS-4
+ eEncoding = RTL_TEXTENCODING_UCS4;
+ break;
+ case 0x100: nNameValue += 21; // Mac Roman
+ eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
+ break;
+ case 0x300: nNameValue = 0; // Win Symbol encoded name!
+ rDFA.mbSymbolFlag = true; // (often seen for symbol fonts)
+ break;
+ default: nNameValue = 0; // ignore other encodings
+ break;
+ }
+
+ // ignore name entries with no useful encoding
+ if( nNameValue <= 0 )
+ continue;
+ if( nNameLength >= aNameBuffer.size() )
+ continue;
+
+ // get the encoded name
+ aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging
+ rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0],
+ &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
+ if( rc != noErr )
+ continue;
+
+ // convert to unicode name
+ UniString aUtf16Name;
+ if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names
+ aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 );
+ else if( eEncoding == RTL_TEXTENCODING_UCS4 )
+ aUtf16Name = UniString(); // TODO
+ else // assume the non-unicode encoded names are byte encoded
+ aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding );
+
+ // ignore empty strings
+ if( aUtf16Name.Len() <= 0 )
+ continue;
+
+ // handle the name depending on its namecode
+ switch( eFontNameCode )
+ {
+ case kFontFamilyName:
+ // ignore font names starting with '.'
+ if( aUtf16Name.GetChar(0) == '.' )
+ nNameValue = 0;
+ else if( rDFA.maName.Len() )
+ {
+ // even if a family name is not the one we are looking for
+ // it is still useful as a font name alternative
+ if( rDFA.maMapNames.Len() )
+ rDFA.maMapNames += ';';
+ rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name;
+ }
+ if( nBestNameValue < nNameValue )
+ {
+ // get the best family name
+ nBestNameValue = nNameValue;
+ eBestLangCode = eFontNameLanguage;
+ rDFA.maName = aUtf16Name;
+ }
+ break;
+ case kFontStyleName:
+ // get a style name matching to the family name
+ if( nBestStyleValue < nNameValue )
+ {
+ nBestStyleValue = nNameValue;
+ rDFA.maStyleName = aUtf16Name;
+ }
+ break;
+ case kFontPostscriptName:
+ // use the postscript name to get some useful info
+ UpdateAttributesFromPSName( aUtf16Name, rDFA );
+ break;
+ default:
+ // TODO: use other name entries too?
+ break;
+ }
+ }
+
+#if 0 // multiple-master fonts are mostly obsolete nowadays
+ // if we still want to support them this should probably be done one frame higher
+ ItemCount nMaxInstances = 0;
+ rc = ATSUCountFontInstances ( nFontID, &nMaxInstances );
+ for( ItemCount nInstanceIndex = 0; nInstanceIndex < nMaxInstances; ++nInstanceIndex )
+ {
+ ItemCount nMaxVariations = 0;
+ rc = ATSUGetFontInstance( nFontID, nInstanceIndex, 0, NULL, NULL, &nMaxVariations );
+ if( (rc == noErr) && (nMaxVariations > 0) )
+ {
+ fprintf(stderr,"\tnMaxVariations=%d\n",(int)nMaxVariations);
+ typedef ::std::vector<ATSUFontVariationAxis> VariationAxisVector;
+ typedef ::std::vector<ATSUFontVariationValue> VariationValueVector;
+ VariationAxisVector aVariationAxes( nMaxVariations );
+ VariationValueVector aVariationValues( nMaxVariations );
+ ItemCount nVariationCount = 0;
+ rc = ATSUGetFontInstance ( nFontID, nInstanceIndex, nMaxVariations,
+ &aVariationAxes[0], &aVariationValues[0], &nVariationCount );
+ fprintf(stderr,"\tnVariationCount=%d\n",(int)nVariationCount);
+ for( ItemCount nVariationIndex = 0; nVariationIndex < nMaxVariations; ++nVariationIndex )
+ {
+ const char* pTag = (const char*)&aVariationAxes[nVariationIndex];
+ fprintf(stderr,"\tvariation[%d] \'%c%c%c%c\' is %d\n", (int)nVariationIndex,
+ pTag[3],pTag[2],pTag[1],pTag[0], (int)aVariationValues[nVariationIndex]);
+ }
+ }
+ }
+#endif
+
+#if 0 // selecting non-defaulted font features is not enabled yet
+ ByteString aFName( rDFA.maName, RTL_TEXTENCODING_UTF8 );
+ ByteString aSName( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
+ ItemCount nMaxFeatures = 0;
+ rc = ATSUCountFontFeatureTypes( nFontID, &nMaxFeatures );
+ fprintf(stderr,"Font \"%s\" \"%s\" has %d features\n",aFName.GetBuffer(),aSName.GetBuffer(),rc);
+ if( (rc == noErr) && (nMaxFeatures > 0) )
+ {
+ typedef std::vector<ATSUFontFeatureType> FeatureVector;
+ FeatureVector aFeatureVector( nMaxFeatures );
+ ItemCount nFeatureCount = 0;
+ rc = ATSUGetFontFeatureTypes( nFontID, nMaxFeatures, &aFeatureVector[0], &nFeatureCount );
+ fprintf(stderr,"nFeatureCount=%d\n",(int)nFeatureCount);
+ for( ItemCount nFeatureIndex = 0; nFeatureIndex < nFeatureCount; ++nFeatureIndex )
+ {
+ ItemCount nMaxSelectors = 0;
+ rc = ATSUCountFontFeatureSelectors( nFontID, aFeatureVector[nFeatureIndex], &nMaxSelectors );
+ fprintf(stderr,"\tFeature[%d] = %d has %d selectors\n",
+ (int)nFeatureIndex, (int)aFeatureVector[nFeatureIndex], (int)nMaxSelectors );
+ typedef std::vector<ATSUFontFeatureSelector> SelectorVector;
+ SelectorVector aSelectorVector( nMaxSelectors );
+ typedef std::vector<MacOSBoolean> BooleanVector;
+ BooleanVector aEnabledVector( nMaxSelectors );
+ BooleanVector aExclusiveVector( nMaxSelectors );
+ ItemCount nSelectorCount = 0;
+ rc = ATSUGetFontFeatureSelectors ( nFontID, aFeatureVector[nFeatureIndex], nMaxSelectors,
+ &aSelectorVector[0], &aEnabledVector[0], &nSelectorCount, &aExclusiveVector[0]);
+ for( ItemCount nSelectorIndex = 0; nSelectorIndex < nSelectorCount; ++nSelectorIndex )
+ {
+ FontNameCode eFontNameCode;
+ rc = ATSUGetFontFeatureNameCode( nFontID, aFeatureVector[nFeatureIndex],
+ aSelectorVector[nSelectorIndex], &eFontNameCode );
+ fprintf(stderr,"\t\tselector[%d] n=%d e=%d, x=%d\n",
+ (int)nSelectorIndex, (int)eFontNameCode,
+ aEnabledVector[nSelectorIndex], aExclusiveVector[nSelectorIndex] );
+ }
+ }
+ }
+#endif
+
+ bool bRet = (rDFA.maName.Len() > 0);
+ return bRet;
+}
+
+// =======================================================================
+
+SystemFontList::SystemFontList()
+{
+ // count available system fonts
+ ItemCount nATSUICompatibleFontsAvailable = 0;
+ if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr )
+ return;
+ if( nATSUICompatibleFontsAvailable <= 0 )
+ return;
+
+ // enumerate available system fonts
+ typedef std::vector<ATSUFontID> AtsFontIDVector;
+ AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable );
+ ItemCount nFontItemsCount = 0;
+ if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr )
+ return;
+
+ BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal");
+
+ // prepare use of the available fonts
+ AtsFontIDVector::const_iterator it = aFontIDVector.begin();
+ for(; it != aFontIDVector.end(); ++it )
+ {
+ const ATSUFontID nFontID = *it;
+ ImplDevFontAttributes aDevFontAttr;
+ if( !GetDevFontAttributes( nFontID, aDevFontAttr ) )
+ continue;
+ ImplMacFontData* pFontData = new ImplMacFontData( aDevFontAttr, nFontID );
+ maFontContainer[ nFontID ] = pFontData;
+ }
+
+ InitGlyphFallbacks();
+}
+
+// -----------------------------------------------------------------------
+
+SystemFontList::~SystemFontList()
+{
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ delete (*it).second;
+ maFontContainer.clear();
+
+ ATSUDisposeFontFallbacks( maFontFallbacks );
+}
+
+// -----------------------------------------------------------------------
+
+void SystemFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
+{
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ rFontList.Add( (*it).second->Clone() );
+}
+
+// -----------------------------------------------------------------------
+
+// not all fonts are suitable for glyph fallback => sort them
+struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); };
+
+inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB )
+{
+ // use symbol fonts only as last resort
+ bool bPreferA = !pA->IsSymbolFont();
+ bool bPreferB = !pB->IsSymbolFont();
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer scalable fonts
+ bPreferA = pA->IsScalable();
+ bPreferB = pB->IsScalable();
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer non-slanted fonts
+ bPreferA = (pA->GetSlant() == ITALIC_NONE);
+ bPreferB = (pB->GetSlant() == ITALIC_NONE);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer normal weight fonts
+ bPreferA = (pA->GetWeight() == WEIGHT_NORMAL);
+ bPreferB = (pB->GetWeight() == WEIGHT_NORMAL);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer normal width fonts
+ bPreferA = (pA->GetWidthType() == WIDTH_NORMAL);
+ bPreferB = (pB->GetWidthType() == WIDTH_NORMAL);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ return false;
+}
+
+void SystemFontList::InitGlyphFallbacks()
+{
+ // sort fonts for "glyph fallback"
+ typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet;
+ FallbackSet aFallbackSet;
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ {
+ const ImplMacFontData* pIFD = (*it).second;
+ // TODO: subsettable/embeddable glyph fallback only for PDF export?
+ if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() )
+ aFallbackSet.insert( pIFD );
+ }
+
+ // tell ATSU about font preferences for "glyph fallback"
+ typedef std::vector<ATSUFontID> AtsFontIDVector;
+ AtsFontIDVector aFallbackVector;
+ aFallbackVector.reserve( maFontContainer.size() );
+ FallbackSet::const_iterator itFData = aFallbackSet.begin();
+ for(; itFData != aFallbackSet.end(); ++itFData )
+ {
+ const ImplMacFontData* pFontData = (*itFData);
+ ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId();
+ aFallbackVector.push_back( nFontID );
+ }
+
+ ATSUCreateFontFallbacks( &maFontFallbacks );
+ ATSUSetObjFontFallbacks( maFontFallbacks,
+ aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred );
+}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData* SystemFontList::GetFontDataFromId( ATSUFontID nFontId ) const
+{
+ MacFontContainer::const_iterator it = maFontContainer.find( nFontId );
+ if( it == maFontContainer.end() )
+ return NULL;
+ return (*it).second;
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/aqua/source/gdi/salbmp.cxx b/vcl/aqua/source/gdi/salbmp.cxx
new file mode 100644
index 000000000000..0e58c35b5fad
--- /dev/null
+++ b/vcl/aqua/source/gdi/salbmp.cxx
@@ -0,0 +1,904 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "tools/color.hxx"
+#include "salbmp.h"
+#include "vcl/bitmap.hxx" // for BitmapSystemData
+#include "vcl/salbtype.hxx"
+#include "vcl/bmpfast.hxx"
+
+#include "basebmp/scanlineformats.hxx"
+#include "basebmp/color.hxx"
+#include "basegfx/vector/b2ivector.hxx"
+
+#include <boost/bind.hpp>
+
+#include "salinst.h"
+
+// =======================================================================
+
+static bool isValidBitCount( sal_uInt16 nBitCount )
+{
+ return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 16) || (nBitCount == 24) || (nBitCount == 32);
+}
+
+// =======================================================================
+
+AquaSalBitmap::AquaSalBitmap()
+: mxGraphicContext( NULL )
+, mxCachedImage( NULL )
+, mnBits(0)
+, mnWidth(0)
+, mnHeight(0)
+, mnBytesPerRow(0)
+{
+}
+
+// ------------------------------------------------------------------
+
+AquaSalBitmap::~AquaSalBitmap()
+{
+ Destroy();
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( CGLayerRef xLayer, int nBitmapBits,
+ int nX, int nY, int nWidth, int nHeight, bool /*bMirrorVert*/ )
+{
+ DBG_ASSERT( xLayer, "AquaSalBitmap::Create() from non-layered context" );
+
+ // sanitize input parameters
+ if( nX < 0 )
+ nWidth += nX, nX = 0;
+ if( nY < 0 )
+ nHeight += nY, nY = 0;
+ const CGSize aLayerSize = CGLayerGetSize( xLayer );
+ if( nWidth >= (int)aLayerSize.width - nX )
+ nWidth = (int)aLayerSize.width - nX;
+ if( nHeight >= (int)aLayerSize.height - nY )
+ nHeight = (int)aLayerSize.height - nY;
+ if( (nWidth < 0) || (nHeight < 0) )
+ nWidth = nHeight = 0;
+
+ // initialize properties
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ mnBits = nBitmapBits ? nBitmapBits : 32;
+
+ // initialize drawing context
+ CreateContext();
+
+ // copy layer content into the bitmap buffer
+ const CGPoint aSrcPoint = { -nX, -nY };
+ ::CGContextDrawLayerAtPoint( mxGraphicContext, aSrcPoint, xLayer );
+ return true;
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const Size& rSize, USHORT nBits, const BitmapPalette& rBitmapPalette )
+{
+ if( !isValidBitCount( nBits ) )
+ return false;
+ maPalette = rBitmapPalette;
+ mnBits = nBits;
+ mnWidth = rSize.Width();
+ mnHeight = rSize.Height();
+ return AllocateUserData();
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const SalBitmap& rSalBmp )
+{
+ return Create( rSalBmp, rSalBmp.GetBitCount() );
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
+{
+ return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() );
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, USHORT nNewBitCount )
+{
+ const AquaSalBitmap& rSourceBitmap = static_cast<const AquaSalBitmap&>(rSalBmp);
+
+ if( isValidBitCount( nNewBitCount ) && rSourceBitmap.maUserBuffer.get() )
+ {
+ mnBits = nNewBitCount;
+ mnWidth = rSourceBitmap.mnWidth;
+ mnHeight = rSourceBitmap.mnHeight;
+ maPalette = rSourceBitmap.maPalette;
+
+ if( AllocateUserData() )
+ {
+ ConvertBitmapData( mnWidth, mnHeight, mnBits, mnBytesPerRow, maPalette, maUserBuffer.get(), rSourceBitmap.mnBits, rSourceBitmap.mnBytesPerRow, rSourceBitmap.maPalette, rSourceBitmap.maUserBuffer.get() );
+ return true;
+ }
+ }
+ return false;
+}
+
+// ------------------------------------------------------------------
+
+void AquaSalBitmap::Destroy()
+{
+ DestroyContext();
+ maUserBuffer.reset();
+}
+
+// ------------------------------------------------------------------
+
+void AquaSalBitmap::DestroyContext()
+{
+ CGImageRelease( mxCachedImage );
+ mxCachedImage = NULL;
+
+ if( mxGraphicContext )
+ {
+ CGContextRelease( mxGraphicContext );
+ mxGraphicContext = NULL;
+ maContextBuffer.reset();
+ }
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::CreateContext()
+{
+ DestroyContext();
+
+ // prepare graphics context
+ // convert image from user input if available
+ const bool bSkipConversion = !maUserBuffer;
+ if( bSkipConversion )
+ AllocateUserData();
+
+ // default to RGBA color space
+ CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
+
+ // convert data into something accepted by CGBitmapContextCreate()
+ size_t bitsPerComponent = (mnBits == 16) ? 5 : 8;
+ sal_uInt32 nContextBytesPerRow = mnBytesPerRow;
+ if( (mnBits == 16) || (mnBits == 32) )
+ {
+ // no conversion needed for truecolor
+ maContextBuffer = maUserBuffer;
+ }
+ else if( (mnBits == 8) && maPalette.IsGreyPalette() )
+ {
+ // no conversion needed for grayscale
+ maContextBuffer = maUserBuffer;
+ aCGColorSpace = GetSalData()->mxGraySpace;
+ aCGBmpInfo = kCGImageAlphaNone;
+ bitsPerComponent = mnBits;
+ }
+ // TODO: is special handling for 1bit input buffers worth it?
+ else
+ {
+ // convert user data to 32 bit
+ nContextBytesPerRow = mnWidth << 2;
+ try
+ {
+ maContextBuffer.reset( new sal_uInt8[ mnHeight * nContextBytesPerRow ] );
+
+ if( !bSkipConversion )
+ ConvertBitmapData( mnWidth, mnHeight,
+ 32, nContextBytesPerRow, maPalette, maContextBuffer.get(),
+ mnBits, mnBytesPerRow, maPalette, maUserBuffer.get() );
+ }
+ catch( std::bad_alloc )
+ {
+ mxGraphicContext = 0;
+ }
+ }
+
+ if( maContextBuffer.get() )
+ {
+ mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
+ bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
+ }
+
+ if( !mxGraphicContext )
+ maContextBuffer.reset();
+
+ return mxGraphicContext != NULL;
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::AllocateUserData()
+{
+ Destroy();
+
+ if( mnWidth && mnHeight )
+ {
+ mnBytesPerRow = 0;
+
+ switch( mnBits )
+ {
+ case 1: mnBytesPerRow = (mnWidth + 7) >> 3; break;
+ case 4: mnBytesPerRow = (mnWidth + 1) >> 1; break;
+ case 8: mnBytesPerRow = mnWidth; break;
+ case 16: mnBytesPerRow = mnWidth << 1; break;
+ case 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break;
+ case 32: mnBytesPerRow = mnWidth << 2; break;
+ default:
+ DBG_ERROR("vcl::AquaSalBitmap::AllocateUserData(), illegal bitcount!");
+ }
+ }
+
+ try
+ {
+ if( mnBytesPerRow )
+ maUserBuffer.reset( new sal_uInt8[mnBytesPerRow * mnHeight] );
+ }
+ catch( const std::bad_alloc& )
+ {
+ DBG_ERROR( "vcl::AquaSalBitmap::AllocateUserData: bad alloc" );
+ maUserBuffer.reset( NULL );
+ mnBytesPerRow = 0;
+ }
+
+ return maUserBuffer.get() != 0;
+}
+
+// ------------------------------------------------------------------
+
+class ImplPixelFormat
+{
+protected:
+ sal_uInt8* pData;
+public:
+ static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
+
+ virtual void StartLine( sal_uInt8* pLine ) { pData = pLine; }
+ virtual void SkipPixel( sal_uInt32 nPixel ) = 0;
+ virtual ColorData ReadPixel() = 0;
+ virtual void WritePixel( ColorData nColor ) = 0;
+};
+
+class ImplPixelFormat32 : public ImplPixelFormat
+// currently ARGB-format for 32bit depth
+{
+public:
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += nPixel << 2;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const ColorData c = RGB_COLORDATA( pData[1], pData[2], pData[3] );
+ pData += 4;
+ return c;
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ *pData++ = 0;
+ *pData++ = COLORDATA_RED( nColor );
+ *pData++ = COLORDATA_GREEN( nColor );
+ *pData++ = COLORDATA_BLUE( nColor );
+ }
+};
+
+class ImplPixelFormat24 : public ImplPixelFormat
+// currently BGR-format for 24bit depth
+{
+public:
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += (nPixel << 1) + nPixel;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const ColorData c = RGB_COLORDATA( pData[2], pData[1], pData[0] );
+ pData += 3;
+ return c;
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ *pData++ = COLORDATA_BLUE( nColor );
+ *pData++ = COLORDATA_GREEN( nColor );
+ *pData++ = COLORDATA_RED( nColor );
+ }
+};
+
+class ImplPixelFormat16 : public ImplPixelFormat
+// currently R5G6B5-format for 16bit depth
+{
+protected:
+ sal_uInt16* pData16;
+public:
+
+ virtual void StartLine( sal_uInt8* pLine )
+ {
+ pData16 = (sal_uInt16*)pLine;
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += nPixel;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const ColorData c = RGB_COLORDATA( (*pData & 0x7c00) >> 7, (*pData & 0x03e0) >> 2 , (*pData & 0x001f) << 3 );
+ pData++;
+ return c;
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ *pData++ = ((COLORDATA_RED( nColor ) & 0xf8 ) << 7 ) ||
+ ((COLORDATA_GREEN( nColor ) & 0xf8 ) << 2 ) ||
+ ((COLORDATA_BLUE( nColor ) & 0xf8 ) >> 3 );
+ }
+};
+
+class ImplPixelFormat8 : public ImplPixelFormat
+{
+private:
+ const BitmapPalette& mrPalette;
+
+public:
+ ImplPixelFormat8( const BitmapPalette& rPalette )
+ : mrPalette( rPalette )
+ {
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += nPixel;
+ }
+ virtual ColorData ReadPixel()
+ {
+ return mrPalette[ *pData++ ].operator Color().GetColor();
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
+ *pData++ = static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) );
+ }
+};
+
+class ImplPixelFormat4 : public ImplPixelFormat
+{
+private:
+ const BitmapPalette& mrPalette;
+ sal_uInt32 mnX;
+ sal_uInt32 mnShift;
+
+public:
+ ImplPixelFormat4( const BitmapPalette& rPalette )
+ : mrPalette( rPalette )
+ {
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ mnX += nPixel;
+ if( (nPixel & 1) )
+ mnShift ^= 4;
+ }
+ virtual void StartLine( sal_uInt8* pLine )
+ {
+ pData = pLine;
+ mnX = 0;
+ mnShift = 4;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const BitmapColor& rColor = mrPalette[( pData[mnX >> 1] >> mnShift) & 0x0f];
+ mnX++;
+ mnShift ^= 4;
+ return rColor.operator Color().GetColor();
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
+ pData[mnX>>1] &= (0xf0 >> mnShift);
+ pData[mnX>>1] |= (static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) ) & 0x0f);
+ mnX++;
+ mnShift ^= 4;
+ }
+};
+
+class ImplPixelFormat1 : public ImplPixelFormat
+{
+private:
+ const BitmapPalette& mrPalette;
+ sal_uInt32 mnX;
+
+public:
+ ImplPixelFormat1( const BitmapPalette& rPalette )
+ : mrPalette( rPalette )
+ {
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ mnX += nPixel;
+ }
+ virtual void StartLine( sal_uInt8* pLine )
+ {
+ pData = pLine;
+ mnX = 0;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const BitmapColor& rColor = mrPalette[ (pData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
+ mnX++;
+ return rColor.operator Color().GetColor();
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
+ if( mrPalette.GetBestIndex( aColor ) & 1 )
+ pData[ mnX >> 3 ] |= 1 << ( 7 - ( mnX & 7 ) );
+ else
+ pData[ mnX >> 3 ] &= ~( 1 << ( 7 - ( mnX & 7 ) ) );
+ mnX++;
+ }
+};
+
+ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
+{
+ switch( nBits )
+ {
+ case 1: return new ImplPixelFormat1( rPalette );
+ case 4: return new ImplPixelFormat4( rPalette );
+ case 8: return new ImplPixelFormat8( rPalette );
+ case 16: return new ImplPixelFormat16;
+ case 24: return new ImplPixelFormat24;
+ case 32: return new ImplPixelFormat32;
+ }
+
+ return 0;
+}
+
+void AquaSalBitmap::ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight,
+ sal_uInt16 nDestBits, sal_uInt32 nDestBytesPerRow, const BitmapPalette& rDestPalette, sal_uInt8* pDestData,
+ sal_uInt16 nSrcBits, sal_uInt32 nSrcBytesPerRow, const BitmapPalette& rSrcPalette, sal_uInt8* pSrcData )
+
+{
+ if( (nDestBytesPerRow == nSrcBytesPerRow) && (nDestBits == nSrcBits) && ((nSrcBits != 8) || (rDestPalette.operator==( rSrcPalette ))) )
+ {
+ // simple case, same format, so just copy
+ memcpy( pDestData, pSrcData, nHeight * nDestBytesPerRow );
+ return;
+ }
+
+ // try accelerated conversion if possible
+ // TODO: are other truecolor conversions except BGR->ARGB worth it?
+ bool bConverted = false;
+ if( (nSrcBits == 24) && (nDestBits == 32) )
+ {
+ // TODO: extend bmpfast.cxx with a method that can be directly used here
+ BitmapBuffer aSrcBuf;
+ aSrcBuf.mnFormat = BMP_FORMAT_24BIT_TC_BGR;
+ aSrcBuf.mpBits = pSrcData;
+ aSrcBuf.mnBitCount = nSrcBits;
+ aSrcBuf.mnScanlineSize = nSrcBytesPerRow;
+ BitmapBuffer aDstBuf;
+ aDstBuf.mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
+ aDstBuf.mpBits = pDestData;
+ aSrcBuf.mnBitCount = nDestBits;
+ aDstBuf.mnScanlineSize = nDestBytesPerRow;
+
+ aSrcBuf.mnWidth = aDstBuf.mnWidth = nWidth;
+ aSrcBuf.mnHeight = aDstBuf.mnHeight = nHeight;
+
+ SalTwoRect aTwoRects;
+ aTwoRects.mnSrcX = aTwoRects.mnDestX = 0;
+ aTwoRects.mnSrcY = aTwoRects.mnDestY = 0;
+ aTwoRects.mnSrcWidth = aTwoRects.mnDestWidth = mnWidth;
+ aTwoRects.mnSrcHeight = aTwoRects.mnDestHeight = mnHeight;
+ bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects );
+ }
+
+ if( !bConverted )
+ {
+ // TODO: this implementation is for clarety, not for speed
+
+ ImplPixelFormat* pD = ImplPixelFormat::GetFormat( nDestBits, rDestPalette );
+ ImplPixelFormat* pS = ImplPixelFormat::GetFormat( nSrcBits, rSrcPalette );
+
+ if( pD && pS )
+ {
+ sal_uInt32 nY = nHeight;
+ while( nY-- )
+ {
+ pD->StartLine( pDestData );
+ pS->StartLine( pSrcData );
+
+ sal_uInt32 nX = nWidth;
+ while( nX-- )
+ pD->WritePixel( pS->ReadPixel() );
+
+ pSrcData += nSrcBytesPerRow;
+ pDestData += nDestBytesPerRow;
+ }
+ }
+ delete pS;
+ delete pD;
+ }
+}
+
+// ------------------------------------------------------------------
+
+Size AquaSalBitmap::GetSize() const
+{
+ return Size( mnWidth, mnHeight );
+}
+
+// ------------------------------------------------------------------
+
+USHORT AquaSalBitmap::GetBitCount() const
+{
+ return mnBits;
+}
+
+// ------------------------------------------------------------------
+
+static struct pal_entry
+{
+ BYTE mnRed;
+ BYTE mnGreen;
+ BYTE mnBlue;
+}
+const aImplSalSysPalEntryAry[ 16 ] =
+{
+{ 0, 0, 0 },
+{ 0, 0, 0x80 },
+{ 0, 0x80, 0 },
+{ 0, 0x80, 0x80 },
+{ 0x80, 0, 0 },
+{ 0x80, 0, 0x80 },
+{ 0x80, 0x80, 0 },
+{ 0x80, 0x80, 0x80 },
+{ 0xC0, 0xC0, 0xC0 },
+{ 0, 0, 0xFF },
+{ 0, 0xFF, 0 },
+{ 0, 0xFF, 0xFF },
+{ 0xFF, 0, 0 },
+{ 0xFF, 0, 0xFF },
+{ 0xFF, 0xFF, 0 },
+{ 0xFF, 0xFF, 0xFF }
+};
+
+const BitmapPalette& GetDefaultPalette( int mnBits, bool bMonochrome )
+{
+ if( bMonochrome )
+ return Bitmap::GetGreyPalette( 1U << mnBits );
+
+ // at this point we should provide some kind of default palette
+ // since all other platforms do so, too.
+ static bool bDefPalInit = false;
+ static BitmapPalette aDefPalette256;
+ static BitmapPalette aDefPalette16;
+ static BitmapPalette aDefPalette2;
+ if( ! bDefPalInit )
+ {
+ bDefPalInit = true;
+ aDefPalette256.SetEntryCount( 256 );
+ aDefPalette16.SetEntryCount( 16 );
+ aDefPalette2.SetEntryCount( 2 );
+
+ // Standard colors
+ unsigned int i;
+ for( i = 0; i < 16; i++ )
+ {
+ aDefPalette16[i] =
+ aDefPalette256[i] = BitmapColor( aImplSalSysPalEntryAry[i].mnRed,
+ aImplSalSysPalEntryAry[i].mnGreen,
+ aImplSalSysPalEntryAry[i].mnBlue );
+ }
+
+ aDefPalette2[0] = BitmapColor( 0, 0, 0 );
+ aDefPalette2[1] = BitmapColor( 0xff, 0xff, 0xff );
+
+ // own palette (6/6/6)
+ const int DITHER_PAL_STEPS = 6;
+ const BYTE DITHER_PAL_DELTA = 51;
+ int nB, nG, nR;
+ BYTE nRed, nGreen, nBlue;
+ for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
+ {
+ for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
+ {
+ for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
+ {
+ aDefPalette256[ i ] = BitmapColor( nRed, nGreen, nBlue );
+ i++;
+ }
+ }
+ }
+ }
+
+ // now fill in appropriate palette
+ switch( mnBits )
+ {
+ case 1: return aDefPalette2;
+ case 4: return aDefPalette16;
+ case 8: return aDefPalette256;
+ default: break;
+ }
+
+ const static BitmapPalette aEmptyPalette;
+ return aEmptyPalette;
+}
+
+BitmapBuffer* AquaSalBitmap::AcquireBuffer( bool bReadOnly )
+{
+ if( !maUserBuffer.get() )
+// || maContextBuffer.get() && (maUserBuffer.get() != maContextBuffer.get()) )
+ {
+ fprintf(stderr,"ASB::Acq(%dx%d,d=%d)\n",mnWidth,mnHeight,mnBits);
+ // TODO: AllocateUserData();
+ return NULL;
+ }
+
+ BitmapBuffer* pBuffer = new BitmapBuffer;
+ pBuffer->mnWidth = mnWidth;
+ pBuffer->mnHeight = mnHeight;
+ pBuffer->maPalette = maPalette;
+ pBuffer->mnScanlineSize = mnBytesPerRow;
+ pBuffer->mpBits = maUserBuffer.get();
+ pBuffer->mnBitCount = mnBits;
+ switch( mnBits )
+ {
+ case 1: pBuffer->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; break;
+ case 4: pBuffer->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; break;
+ case 8: pBuffer->mnFormat = BMP_FORMAT_8BIT_PAL; break;
+ case 16: pBuffer->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK;
+ pBuffer->maColorMask = ColorMask( k16BitRedColorMask, k16BitGreenColorMask, k16BitBlueColorMask );
+ break;
+ case 24: pBuffer->mnFormat = BMP_FORMAT_24BIT_TC_BGR; break;
+ case 32: pBuffer->mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
+ pBuffer->maColorMask = ColorMask( k32BitRedColorMask, k32BitGreenColorMask, k32BitBlueColorMask );
+ break;
+ }
+ pBuffer->mnFormat |= BMP_FORMAT_BOTTOM_UP;
+
+ // some BitmapBuffer users depend on a complete palette
+ if( (mnBits <= 8) && !maPalette )
+ pBuffer->maPalette = GetDefaultPalette( mnBits, true );
+
+ return pBuffer;
+}
+
+// ------------------------------------------------------------------
+
+void AquaSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
+{
+ // invalidate graphic context if we have different data
+ if( !bReadOnly )
+ {
+ maPalette = pBuffer->maPalette;
+ if( mxGraphicContext )
+ DestroyContext();
+ }
+
+ delete pBuffer;
+}
+
+// ------------------------------------------------------------------
+
+CGImageRef AquaSalBitmap::CreateCroppedImage( int nX, int nY, int nNewWidth, int nNewHeight ) const
+{
+ if( !mxCachedImage )
+ {
+ if( !mxGraphicContext )
+ if( !const_cast<AquaSalBitmap*>(this)->CreateContext() )
+ return NULL;
+
+ mxCachedImage = CGBitmapContextCreateImage( mxGraphicContext );
+ }
+
+ CGImageRef xCroppedImage = NULL;
+ // short circuit if there is nothing to crop
+ if( !nX && !nY && (mnWidth == nNewWidth) && (mnHeight == nNewHeight) )
+ {
+ xCroppedImage = mxCachedImage;
+ CFRetain( xCroppedImage );
+ }
+ else
+ {
+ nY = mnHeight - (nY + nNewHeight); // adjust for y-mirrored context
+ const CGRect aCropRect = {{nX, nY}, {nNewWidth, nNewHeight}};
+ xCroppedImage = CGImageCreateWithImageInRect( mxCachedImage, aCropRect );
+ }
+
+ return xCroppedImage;
+}
+
+// ------------------------------------------------------------------
+
+static void CFRTLFree(void* /*info*/, const void* data, size_t /*size*/)
+{
+ rtl_freeMemory( const_cast<void*>(data) );
+}
+
+CGImageRef AquaSalBitmap::CreateWithMask( const AquaSalBitmap& rMask,
+ int nX, int nY, int nWidth, int nHeight ) const
+{
+ CGImageRef xImage( CreateCroppedImage( nX, nY, nWidth, nHeight ) );
+ if( !xImage )
+ return NULL;
+
+ CGImageRef xMask = rMask.CreateCroppedImage( nX, nY, nWidth, nHeight );
+ if( !xMask )
+ return xImage;
+
+ // CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
+ // TODO: isolate in an extra method?
+ if( !CGImageIsMask(xMask) || (CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
+ {
+ const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
+
+ // create the alpha mask image fitting our image
+ // TODO: is caching the full mask or the subimage mask worth it?
+ int nMaskBytesPerRow = ((nWidth + 3) & ~3);
+ void* pMaskMem = rtl_allocateMemory( nMaskBytesPerRow * nHeight );
+ CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem,
+ nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone );
+ CGContextDrawImage( xMaskContext, xImageRect, xMask );
+ CFRelease( xMask );
+ CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( NULL,
+ pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) );
+ static const float* pDecode = NULL;
+ xMask = CGImageMaskCreate( nWidth, nHeight, 8, 8, nMaskBytesPerRow, xDataProvider, pDecode, false );
+ CFRelease( xDataProvider );
+ CFRelease( xMaskContext );
+ }
+
+ if( !xMask )
+ return xImage;
+
+ // combine image and alpha mask
+ CGImageRef xMaskedImage = CGImageCreateWithMask( xImage, xMask );
+ CFRelease( xMask );
+ CFRelease( xImage );
+ return xMaskedImage;
+}
+
+// ------------------------------------------------------------------
+
+/** creates an image from the given rectangle, replacing all black pixels with nMaskColor and make all other full transparent */
+CGImageRef AquaSalBitmap::CreateColorMask( int nX, int nY, int nWidth, int nHeight, SalColor nMaskColor ) const
+{
+ CGImageRef xMask = 0;
+ if( maUserBuffer.get() && (nX + nWidth <= mnWidth) && (nY + nHeight <= mnHeight) )
+ {
+ const sal_uInt32 nDestBytesPerRow = nWidth << 2;
+ sal_uInt32* pMaskBuffer = static_cast<sal_uInt32*>( rtl_allocateMemory( nHeight * nDestBytesPerRow ) );
+ sal_uInt32* pDest = pMaskBuffer;
+
+ ImplPixelFormat* pSourcePixels = ImplPixelFormat::GetFormat( mnBits, maPalette );
+
+ if( pMaskBuffer && pSourcePixels )
+ {
+ sal_uInt32 nColor;
+ reinterpret_cast<sal_uInt8*>(&nColor)[0] = 0xff;
+ reinterpret_cast<sal_uInt8*>(&nColor)[1] = SALCOLOR_RED( nMaskColor );
+ reinterpret_cast<sal_uInt8*>(&nColor)[2] = SALCOLOR_GREEN( nMaskColor );
+ reinterpret_cast<sal_uInt8*>(&nColor)[3] = SALCOLOR_BLUE( nMaskColor );
+
+ sal_uInt8* pSource = maUserBuffer.get();
+ if( nY )
+ pSource += nY * mnBytesPerRow;
+
+ int y = nHeight;
+ while( y-- )
+ {
+ pSourcePixels->StartLine( pSource );
+ pSourcePixels->SkipPixel(nX);
+ sal_uInt32 x = nWidth;
+ while( x-- )
+ {
+ *pDest++ = ( pSourcePixels->ReadPixel() == 0 ) ? nColor : 0;
+ }
+ pSource += mnBytesPerRow;
+ }
+
+ CGDataProviderRef xDataProvider( CGDataProviderCreateWithData(NULL, pMaskBuffer, nHeight * nDestBytesPerRow, &CFRTLFree) );
+ xMask = CGImageCreate(nWidth, nHeight, 8, 32, nDestBytesPerRow, GetSalData()->mxRGBSpace, kCGImageAlphaPremultipliedFirst, xDataProvider, NULL, true, kCGRenderingIntentDefault);
+ CFRelease(xDataProvider);
+ }
+ else
+ {
+ free(pMaskBuffer);
+ }
+
+ delete pSourcePixels;
+ }
+ return xMask;
+}
+
+// =======================================================================
+
+/** AquaSalBitmap::GetSystemData Get platform native image data from existing image
+ *
+ * @param rData struct BitmapSystemData, defined in vcl/inc/bitmap.hxx
+ * @return true if successful
+**/
+bool AquaSalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ bool bRet = false;
+
+ if( !mxGraphicContext )
+ CreateContext();
+
+ if ( mxGraphicContext )
+ {
+ bRet = true;
+
+#ifdef CAIRO
+ if ((CGBitmapContextGetBitsPerPixel(mxGraphicContext) == 32) &&
+ (CGBitmapContextGetBitmapInfo(mxGraphicContext) & kCGBitmapByteOrderMask) != kCGBitmapByteOrder32Host) {
+ /**
+ * We need to hack things because VCL does not use kCGBitmapByteOrder32Host, while Cairo requires it.
+ */
+ OSL_TRACE("AquaSalBitmap::%s(): kCGBitmapByteOrder32Host not found => inserting it.",__func__);
+
+ CGImageRef xImage = CGBitmapContextCreateImage (mxGraphicContext);
+
+ // re-create the context with single change: include kCGBitmapByteOrder32Host flag.
+ CGContextRef mxGraphicContextNew = CGBitmapContextCreate( CGBitmapContextGetData(mxGraphicContext),
+ CGBitmapContextGetWidth(mxGraphicContext),
+ CGBitmapContextGetHeight(mxGraphicContext),
+ CGBitmapContextGetBitsPerComponent(mxGraphicContext),
+ CGBitmapContextGetBytesPerRow(mxGraphicContext),
+ CGBitmapContextGetColorSpace(mxGraphicContext),
+ CGBitmapContextGetBitmapInfo(mxGraphicContext) | kCGBitmapByteOrder32Host);
+ CFRelease(mxGraphicContext);
+
+ // Needs to be flipped
+ CGContextSaveGState( mxGraphicContextNew );
+ CGContextTranslateCTM (mxGraphicContextNew, 0, CGBitmapContextGetHeight(mxGraphicContextNew));
+ CGContextScaleCTM (mxGraphicContextNew, 1.0, -1.0);
+
+ CGContextDrawImage(mxGraphicContextNew, CGRectMake( 0, 0, CGImageGetWidth(xImage), CGImageGetHeight(xImage)), xImage);
+
+ // Flip back
+ CGContextRestoreGState( mxGraphicContextNew );
+
+ CGImageRelease( xImage );
+ mxGraphicContext = mxGraphicContextNew;
+ }
+#endif
+
+ rData.rImageContext = (void *) mxGraphicContext;
+ rData.mnWidth = mnWidth;
+ rData.mnHeight = mnHeight;
+ }
+
+ return bRet;
+}
diff --git a/vcl/aqua/source/gdi/salcolorutils.cxx b/vcl/aqua/source/gdi/salcolorutils.cxx
new file mode 100755
index 000000000000..ec33b2dd8f8d
--- /dev/null
+++ b/vcl/aqua/source/gdi/salcolorutils.cxx
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salcolorutils.hxx"
+#include "vcl/salbtype.hxx"
+
+// =======================================================================
+
+SalColor GetSalColor( const float* pQuartzColor )
+{
+ return MAKE_SALCOLOR( sal_uInt8( pQuartzColor[0] * 255.0), sal_uInt8( pQuartzColor[1] * 255.0 ), sal_uInt8( pQuartzColor[2] * 255.0 ) );
+}
+
+void SetSalColor( const SalColor& rColor, float* pQuartzColor )
+{
+ pQuartzColor[0] = (float) SALCOLOR_RED(rColor) / 255.0;
+ pQuartzColor[1] = (float) SALCOLOR_GREEN(rColor) / 255.0;
+ pQuartzColor[2] = (float) SALCOLOR_BLUE(rColor) / 255.0;
+ pQuartzColor[3] = 1.0;
+}
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salgdi.cxx b/vcl/aqua/source/gdi/salgdi.cxx
new file mode 100644
index 000000000000..8a4744d1efcd
--- /dev/null
+++ b/vcl/aqua/source/gdi/salgdi.cxx
@@ -0,0 +1,2672 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salconst.h"
+#include "salgdi.h"
+#include "salbmp.h"
+#include "salframe.h"
+#include "salcolorutils.hxx"
+#include "sft.hxx"
+#include "salatsuifontutils.hxx"
+
+#include "vcl/impfont.hxx"
+#include "vcl/fontsubset.hxx"
+#include "vcl/sysdata.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/svapp.hxx"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "vos/mutex.hxx"
+
+#include "rtl/bootstrap.h"
+#include "rtl/strbuf.hxx"
+
+#include "basegfx/range/b2drectangle.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+using namespace vcl;
+
+typedef unsigned char Boolean; // copied from MacTypes.h, should be properly included
+typedef std::vector<unsigned char> ByteVector;
+
+
+// =======================================================================
+
+ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, ATSUFontID nFontId )
+: ImplFontData( rDFA, 0 )
+, mnFontId( nFontId )
+, mpCharMap( NULL )
+, mbOs2Read( false )
+, mbHasOs2Table( false )
+, mbCmapEncodingRead( false )
+, mbHasCJKSupport( false )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData::~ImplMacFontData()
+{
+ if( mpCharMap )
+ mpCharMap->DeReference();
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr ImplMacFontData::GetFontId() const
+{
+ return (sal_IntPtr)mnFontId;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontData* ImplMacFontData::Clone() const
+{
+ ImplMacFontData* pClone = new ImplMacFontData(*this);
+ if( mpCharMap )
+ mpCharMap->AddReference();
+ return pClone;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplMacFontData::CreateFontInstance(ImplFontSelectData& rFSD) const
+{
+ return new ImplFontEntry(rFSD);
+}
+
+// -----------------------------------------------------------------------
+
+inline FourCharCode GetTag(const char aTagName[5])
+{
+ return (aTagName[0]<<24)+(aTagName[1]<<16)+(aTagName[2]<<8)+(aTagName[3]);
+}
+
+static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
+static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
+
+ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
+{
+ if( mpCharMap )
+ {
+ // return the cached charmap
+ mpCharMap->AddReference();
+ return mpCharMap;
+ }
+
+ // set the default charmap
+ mpCharMap = ImplFontCharMap::GetDefaultMap();
+
+ // get the CMAP byte size
+ ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
+ ByteCount nBufSize = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable1 failed!\n");
+ if( eStatus != noErr )
+ return mpCharMap;
+
+ // allocate a buffer for the CMAP raw data
+ ByteVector aBuffer( nBufSize );
+
+ // get the CMAP raw data
+ ByteCount nRawLength = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable2 failed!\n");
+ if( eStatus != noErr )
+ return mpCharMap;
+ DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::GetImplFontCharMap : ByteCount mismatch!\n");
+
+ // parse the CMAP
+ CmapResult aCmapResult;
+ if( !ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
+ return mpCharMap;
+
+ mpCharMap = new ImplFontCharMap( aCmapResult );
+ return mpCharMap;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplMacFontData::ReadOs2Table( void ) const
+{
+ // read this only once per font
+ if( mbOs2Read )
+ return;
+ mbOs2Read = true;
+
+ // prepare to get the OS/2 table raw data
+ ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
+ ByteCount nBufSize = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, 0, NULL, &nBufSize );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable1 failed!\n");
+ if( eStatus != noErr )
+ return;
+
+ // allocate a buffer for the OS/2 raw data
+ ByteVector aBuffer( nBufSize );
+
+ // get the OS/2 raw data
+ ByteCount nRawLength = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable2 failed!\n");
+ if( eStatus != noErr )
+ return;
+ DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadOs2Table : ByteCount mismatch!\n");
+ mbHasOs2Table = true;
+
+ // parse the OS/2 raw data
+ // TODO: also analyze panose info, etc.
+
+ // check if the fonts needs the "CJK extra leading" heuristic
+ const unsigned char* pOS2map = &aBuffer[0];
+ const sal_uInt32 nVersion = GetUShort( pOS2map );
+ if( nVersion >= 0x0001 )
+ {
+ sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
+ if( ulUnicodeRange2 & 0x2DF00000 )
+ mbHasCJKSupport = true;
+ }
+}
+
+void ImplMacFontData::ReadMacCmapEncoding( void ) const
+{
+ // read this only once per font
+ if( mbCmapEncodingRead )
+ return;
+ mbCmapEncodingRead = true;
+
+ ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
+ ByteCount nBufSize = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable1 failed!\n");
+ if( eStatus != noErr )
+ return;
+
+ ByteVector aBuffer( nBufSize );
+
+ ByteCount nRawLength = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable2 failed!\n");
+ if( eStatus != noErr )
+ return;
+ DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
+
+ const unsigned char* pCmap = &aBuffer[0];
+
+ if (nRawLength < 24 )
+ return;
+ if( GetUShort( pCmap ) != 0x0000 )
+ return;
+
+ // check if the fonts needs the "CJK extra leading" heuristic
+ int nSubTables = GetUShort( pCmap + 2 );
+
+ for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
+ {
+ int nPlatform = GetUShort( p );
+ if( nPlatform == kFontMacintoshPlatform ) {
+ int nEncoding = GetUShort (p + 2 );
+ if( nEncoding == kFontJapaneseScript ||
+ nEncoding == kFontTraditionalChineseScript ||
+ nEncoding == kFontKoreanScript ||
+ nEncoding == kFontSimpleChineseScript )
+ {
+ mbHasCJKSupport = true;
+ break;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplMacFontData::HasCJKSupport( void ) const
+{
+ ReadOs2Table();
+ if( !mbHasOs2Table )
+ ReadMacCmapEncoding();
+
+ return mbHasCJKSupport;
+}
+
+// =======================================================================
+
+AquaSalGraphics::AquaSalGraphics()
+ : mpFrame( NULL )
+ , mxLayer( NULL )
+ , mrContext( NULL )
+ , mpXorEmulation( NULL )
+ , mnXorMode( 0 )
+ , mnWidth( 0 )
+ , mnHeight( 0 )
+ , mnBitmapDepth( 0 )
+ , mnRealDPIX( 0 )
+ , mnRealDPIY( 0 )
+ , mfFakeDPIScale( 1.0 )
+ , mxClipPath( NULL )
+ , maLineColor( COL_WHITE )
+ , maFillColor( COL_BLACK )
+ , mpMacFontData( NULL )
+ , mnATSUIRotation( 0 )
+ , mfFontScale( 1.0 )
+ , mfFontStretch( 1.0 )
+ , mbNonAntialiasedText( false )
+ , mbPrinter( false )
+ , mbVirDev( false )
+ , mbWindow( false )
+{
+ // create the style object for font attributes
+ ATSUCreateStyle( &maATSUStyle );
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalGraphics::~AquaSalGraphics()
+{
+/*
+ if( mnUpdateGraphicsEvent )
+ {
+ Application::RemoveUserEvent( mnUpdateGraphicsEvent );
+ }
+*/
+ CGPathRelease( mxClipPath );
+ ATSUDisposeStyle( maATSUStyle );
+
+ if( mpXorEmulation )
+ delete mpXorEmulation;
+
+ if( mxLayer )
+ CGLayerRelease( mxLayer );
+ else if( mrContext && mbWindow )
+ {
+ // destroy backbuffer bitmap context that we created ourself
+ CGContextRelease( mrContext );
+ mrContext = NULL;
+ // memory is freed automatically by maOwnContextMemory
+ }
+}
+
+bool AquaSalGraphics::supportsOperation( OutDevSupportType eType ) const
+{
+ bool bRet = false;
+ switch( eType )
+ {
+ case OutDevSupport_TransparentRect:
+ case OutDevSupport_B2DClip:
+ case OutDevSupport_B2DDraw:
+ bRet = true;
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
+// =======================================================================
+
+void AquaSalGraphics::updateResolution()
+{
+ DBG_ASSERT( mbWindow, "updateResolution on inappropriate graphics" );
+
+ initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil );
+}
+
+void AquaSalGraphics::initResolution( NSWindow* pWin )
+{
+ // #i100617# read DPI only once; there is some kind of weird caching going on
+ // if the main screen changes
+ // FIXME: this is really unfortunate and needs to be investigated
+
+ SalData* pSalData = GetSalData();
+ if( pSalData->mnDPIX == 0 || pSalData->mnDPIY == 0 )
+ {
+ NSScreen* pScreen = nil;
+
+ /* #i91301#
+ many woes went into the try to have different resolutions
+ on different screens. The result of these trials is that OOo is not ready
+ for that yet, vcl and applications would need to be adapted.
+
+ Unfortunately this is not possible in the 3.0 timeframe.
+ So let's stay with one resolution for all Windows and VirtualDevices
+ which is the resolution of the main screen
+
+ This of course also means that measurements are exact only on the main screen.
+ For activating different resolutions again just comment out the two lines below.
+
+ if( pWin )
+ pScreen = [pWin screen];
+ */
+ if( pScreen == nil )
+ {
+ NSArray* pScreens = [NSScreen screens];
+ if( pScreens )
+ pScreen = [pScreens objectAtIndex: 0];
+ }
+
+ mnRealDPIX = mnRealDPIY = 96;
+ if( pScreen )
+ {
+ NSDictionary* pDev = [pScreen deviceDescription];
+ if( pDev )
+ {
+ NSNumber* pVal = [pDev objectForKey: @"NSScreenNumber"];
+ if( pVal )
+ {
+ // FIXME: casting a long to CGDirectDisplayID is evil, but
+ // Apple suggest to do it this way
+ const CGDirectDisplayID nDisplayID = (CGDirectDisplayID)[pVal longValue];
+ const CGSize aSize = CGDisplayScreenSize( nDisplayID ); // => result is in millimeters
+ mnRealDPIX = static_cast<long>((CGDisplayPixelsWide( nDisplayID ) * 25.4) / aSize.width);
+ mnRealDPIY = static_cast<long>((CGDisplayPixelsHigh( nDisplayID ) * 25.4) / aSize.height);
+ }
+ else
+ {
+ DBG_ERROR( "no resolution found in device description" );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no device description" );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no screen found" );
+ }
+
+ // #i107076# maintaining size-WYSIWYG-ness causes many problems for
+ // low-DPI, high-DPI or for mis-reporting devices
+ // => it is better to limit the calculation result then
+ static const int nMinDPI = 72;
+ if( (mnRealDPIX < nMinDPI) || (mnRealDPIY < nMinDPI) )
+ mnRealDPIX = mnRealDPIY = nMinDPI;
+ static const int nMaxDPI = 200;
+ if( (mnRealDPIX > nMaxDPI) || (mnRealDPIY > nMaxDPI) )
+ mnRealDPIX = mnRealDPIY = nMaxDPI;
+
+ // for OSX any anisotropy reported for the display resolution is best ignored (e.g. TripleHead2Go)
+ mnRealDPIX = mnRealDPIY = (mnRealDPIX + mnRealDPIY + 1) / 2;
+
+ pSalData->mnDPIX = mnRealDPIX;
+ pSalData->mnDPIY = mnRealDPIY;
+ }
+ else
+ {
+ mnRealDPIX = pSalData->mnDPIX;
+ mnRealDPIY = pSalData->mnDPIY;
+ }
+
+ mfFakeDPIScale = 1.0;
+}
+
+void AquaSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
+{
+ if( !mnRealDPIY )
+ initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil );
+
+ rDPIX = static_cast<long>(mfFakeDPIScale * mnRealDPIX);
+ rDPIY = static_cast<long>(mfFakeDPIScale * mnRealDPIY);
+}
+
+void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics )
+{
+ if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame )
+ rGraphics.initResolution( rGraphics.mpFrame->mpWindow );
+
+ mnRealDPIX = rGraphics.mnRealDPIX;
+ mnRealDPIY = rGraphics.mnRealDPIY;
+ mfFakeDPIScale = rGraphics.mfFakeDPIScale;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT AquaSalGraphics::GetBitCount()
+{
+ USHORT nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24;
+ return nBits;
+}
+
+// -----------------------------------------------------------------------
+
+static const basegfx::B2DPoint aHalfPointOfs ( 0.5, 0.5 );
+
+static void AddPolygonToPath( CGMutablePathRef xPath,
+ const ::basegfx::B2DPolygon& rPolygon, bool bClosePath, bool bPixelSnap, bool bLineDraw )
+{
+ // short circuit if there is nothing to do
+ const int nPointCount = rPolygon.count();
+ if( nPointCount <= 0 )
+ return;
+
+ (void)bPixelSnap; // TODO
+ const CGAffineTransform* pTransform = NULL;
+
+ const bool bHasCurves = rPolygon.areControlPointsUsed();
+ for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ )
+ {
+ int nClosedIdx = nPointIdx;
+ if( nPointIdx >= nPointCount )
+ {
+ // prepare to close last curve segment if needed
+ if( bClosePath && (nPointIdx == nPointCount) )
+ nClosedIdx = 0;
+ else
+ break;
+ }
+
+ ::basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx );
+
+ if( bPixelSnap)
+ {
+ // snap device coordinates to full pixels
+ aPoint.setX( basegfx::fround( aPoint.getX() ) );
+ aPoint.setY( basegfx::fround( aPoint.getY() ) );
+ }
+
+ if( bLineDraw )
+ aPoint += aHalfPointOfs;
+
+ if( !nPointIdx ) { // first point => just move there
+ CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() );
+ continue;
+ }
+
+ bool bPendingCurve = false;
+ if( bHasCurves )
+ {
+ bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx );
+ bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx );
+ }
+
+ if( !bPendingCurve ) // line segment
+ CGPathAddLineToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() );
+ else // cubic bezier segment
+ {
+ basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx );
+ basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx );
+ if( bLineDraw )
+ {
+ aCP1 += aHalfPointOfs;
+ aCP2 += aHalfPointOfs;
+ }
+ CGPathAddCurveToPoint( xPath, pTransform, aCP1.getX(), aCP1.getY(),
+ aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() );
+ }
+ }
+
+ if( bClosePath )
+ CGPathCloseSubpath( xPath );
+}
+
+static void AddPolyPolygonToPath( CGMutablePathRef xPath,
+ const ::basegfx::B2DPolyPolygon& rPolyPoly, bool bPixelSnap, bool bLineDraw )
+{
+ // short circuit if there is nothing to do
+ const int nPolyCount = rPolyPoly.count();
+ if( nPolyCount <= 0 )
+ return;
+
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx );
+ AddPolygonToPath( xPath, rPolygon, true, bPixelSnap, bLineDraw );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::ResetClipRegion()
+{
+ // release old path and indicate no clipping
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+ if( CheckContext() )
+ SetState();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::BeginSetClipRegion( ULONG nRectCount )
+{
+ // release old clip path
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( (nWidth <= 0) || (nHeight <= 0) )
+ return TRUE;
+
+ if( !mxClipPath )
+ mxClipPath = CGPathCreateMutable();
+ const CGRect aClipRect = {{nX,nY},{nWidth,nHeight}};
+ CGPathAddRect( mxClipPath, NULL, aClipRect );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& rPolyPolygon )
+{
+ if( rPolyPolygon.count() <= 0 )
+ return true;
+
+ if( !mxClipPath )
+ mxClipPath = CGPathCreateMutable();
+ AddPolyPolygonToPath( mxClipPath, rPolyPolygon, !getAntiAliasB2DDraw(), false );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::EndSetClipRegion()
+{
+ if( CheckContext() )
+ SetState();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetLineColor()
+{
+ maLineColor.SetAlpha( 0.0 ); // transparent
+ if( CheckContext() )
+ CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetLineColor( SalColor nSalColor )
+{
+ maLineColor = RGBAColor( nSalColor );
+ if( CheckContext() )
+ CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetFillColor()
+{
+ maFillColor.SetAlpha( 0.0 ); // transparent
+ if( CheckContext() )
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetFillColor( SalColor nSalColor )
+{
+ maFillColor = RGBAColor( nSalColor );
+ if( CheckContext() )
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
+{
+ SalColor nSalColor;
+ if ( nROPColor == SAL_ROP_0 )
+ nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
+ else
+ nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
+ return nSalColor;
+}
+
+void AquaSalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ if( ! mbPrinter )
+ SetLineColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ if( ! mbPrinter )
+ SetFillColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::ImplDrawPixel( long nX, long nY, const RGBAColor& rColor )
+{
+ if( !CheckContext() )
+ return;
+
+ // overwrite the fill color
+ CGContextSetFillColor( mrContext, rColor.AsArray() );
+ // draw 1x1 rect, there is no pixel drawing in Quartz
+ CGRect aDstRect = {{nX,nY,},{1,1}};
+ CGContextFillRect( mrContext, aDstRect );
+ RefreshRect( aDstRect );
+ // reset the fill color
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+}
+
+void AquaSalGraphics::drawPixel( long nX, long nY )
+{
+ // draw pixel with current line color
+ ImplDrawPixel( nX, nY, maLineColor );
+}
+
+void AquaSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ const RGBAColor aPixelColor( nSalColor );
+ ImplDrawPixel( nX, nY, aPixelColor );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ if( nX1 == nX2 && nY1 == nY2 )
+ {
+ // #i109453# platform independent code expects at least one pixel to be drawn
+ drawPixel( nX1, nY1 );
+ return;
+ }
+
+ if( !CheckContext() )
+ return;
+
+ CGContextBeginPath( mrContext );
+ CGContextMoveToPoint( mrContext, static_cast<float>(nX1)+0.5, static_cast<float>(nY1)+0.5 );
+ CGContextAddLineToPoint( mrContext, static_cast<float>(nX2)+0.5, static_cast<float>(nY2)+0.5 );
+ CGContextDrawPath( mrContext, kCGPathStroke );
+
+ Rectangle aRefreshRect( nX1, nY1, nX2, nY2 );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
+{
+ if( !CheckContext() )
+ return;
+
+ CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) );
+ if( IsPenVisible() )
+ {
+ aRect.origin.x += 0.5;
+ aRect.origin.y += 0.5;
+ aRect.size.width -= 1;
+ aRect.size.height -= 1;
+ }
+
+ if( IsBrushVisible() )
+ CGContextFillRect( mrContext, aRect );
+
+ if( IsPenVisible() )
+ CGContextStrokeRect( mrContext, aRect );
+
+ RefreshRect( nX, nY, nWidth, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+static void getBoundRect( ULONG nPoints, const SalPoint *pPtAry, long &rX, long& rY, long& rWidth, long& rHeight )
+{
+ long nX1 = pPtAry->mnX;
+ long nX2 = nX1;
+ long nY1 = pPtAry->mnY;
+ long nY2 = nY1;
+ for( ULONG n = 1; n < nPoints; n++ )
+ {
+ if( pPtAry[n].mnX < nX1 )
+ nX1 = pPtAry[n].mnX;
+ else if( pPtAry[n].mnX > nX2 )
+ nX2 = pPtAry[n].mnX;
+
+ if( pPtAry[n].mnY < nY1 )
+ nY1 = pPtAry[n].mnY;
+ else if( pPtAry[n].mnY > nY2 )
+ nY2 = pPtAry[n].mnY;
+ }
+ rX = nX1;
+ rY = nY1;
+ rWidth = nX2 - nX1 + 1;
+ rHeight = nY2 - nY1 + 1;
+}
+
+static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_fY )
+{
+ o_fX = static_cast<float>(i_pIn->mnX ) + 0.5;
+ o_fY = static_cast<float>(i_pIn->mnY ) + 0.5;
+}
+
+void AquaSalGraphics::drawPolyLine( ULONG nPoints, const SalPoint *pPtAry )
+{
+ if( nPoints < 1 )
+ return;
+ if( !CheckContext() )
+ return;
+
+ long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
+
+ float fX, fY;
+
+ CGContextBeginPath( mrContext );
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextMoveToPoint( mrContext, fX, fY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ {
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextAddLineToPoint( mrContext, fX, fY );
+ }
+ CGContextDrawPath( mrContext, kCGPathStroke );
+
+ RefreshRect( nX, nY, nWidth, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawPolygon( ULONG nPoints, const SalPoint *pPtAry )
+{
+ if( nPoints <= 1 )
+ return;
+ if( !CheckContext() )
+ return;
+
+ long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
+
+ CGPathDrawingMode eMode;
+ if( IsBrushVisible() && IsPenVisible() )
+ eMode = kCGPathEOFillStroke;
+ else if( IsPenVisible() )
+ eMode = kCGPathStroke;
+ else if( IsBrushVisible() )
+ eMode = kCGPathEOFill;
+ else
+ return;
+
+ CGContextBeginPath( mrContext );
+
+ if( IsPenVisible() )
+ {
+ float fX, fY;
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextMoveToPoint( mrContext, fX, fY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ {
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextAddLineToPoint( mrContext, fX, fY );
+ }
+ }
+ else
+ {
+ CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ }
+
+ CGContextDrawPath( mrContext, eMode );
+ RefreshRect( nX, nY, nWidth, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawPolyPolygon( ULONG nPolyCount, const ULONG *pPoints, PCONSTSALPOINT *ppPtAry )
+{
+ if( nPolyCount <= 0 )
+ return;
+ if( !CheckContext() )
+ return;
+
+ // find bound rect
+ long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0;
+ getBoundRect( pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight );
+ for( ULONG n = 1; n < nPolyCount; n++ )
+ {
+ long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight;
+ getBoundRect( pPoints[n], ppPtAry[n], nX, nY, nW, nH );
+ if( nX < leftX )
+ {
+ maxWidth += leftX - nX;
+ leftX = nX;
+ }
+ if( nY < topY )
+ {
+ maxHeight += topY - nY;
+ topY = nY;
+ }
+ if( nX + nW > leftX + maxWidth )
+ maxWidth = nX + nW - leftX;
+ if( nY + nH > topY + maxHeight )
+ maxHeight = nY + nH - topY;
+ }
+
+ // prepare drawing mode
+ CGPathDrawingMode eMode;
+ if( IsBrushVisible() && IsPenVisible() )
+ eMode = kCGPathEOFillStroke;
+ else if( IsPenVisible() )
+ eMode = kCGPathStroke;
+ else if( IsBrushVisible() )
+ eMode = kCGPathEOFill;
+ else
+ return;
+
+ // convert to CGPath
+ CGContextBeginPath( mrContext );
+ if( IsPenVisible() )
+ {
+ for( ULONG nPoly = 0; nPoly < nPolyCount; nPoly++ )
+ {
+ const ULONG nPoints = pPoints[nPoly];
+ if( nPoints > 1 )
+ {
+ const SalPoint *pPtAry = ppPtAry[nPoly];
+ float fX, fY;
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextMoveToPoint( mrContext, fX, fY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ {
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextAddLineToPoint( mrContext, fX, fY );
+ }
+ CGContextClosePath(mrContext);
+ }
+ }
+ }
+ else
+ {
+ for( ULONG nPoly = 0; nPoly < nPolyCount; nPoly++ )
+ {
+ const ULONG nPoints = pPoints[nPoly];
+ if( nPoints > 1 )
+ {
+ const SalPoint *pPtAry = ppPtAry[nPoly];
+ CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ CGContextClosePath(mrContext);
+ }
+ }
+ }
+
+ CGContextDrawPath( mrContext, eMode );
+
+ RefreshRect( leftX, topY, maxWidth, maxHeight );
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly,
+ double fTransparency )
+{
+ // short circuit if there is nothing to do
+ const int nPolyCount = rPolyPoly.count();
+ if( nPolyCount <= 0 )
+ return true;
+
+ // ignore invisible polygons
+ if( (fTransparency >= 1.0) || (fTransparency < 0) )
+ return true;
+
+ // setup poly-polygon path
+ CGMutablePathRef xPath = CGPathCreateMutable();
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx );
+ AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() );
+ }
+
+ const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
+#ifndef NO_I97317_WORKAROUND
+ // #i97317# workaround for Quartz having problems with drawing small polygons
+ if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
+#endif
+ {
+ // use the path to prepare the graphics context
+ CGContextSaveGState( mrContext );
+ CGContextBeginPath( mrContext );
+ CGContextAddPath( mrContext, xPath );
+
+ // draw path with antialiased polygon
+ CGContextSetShouldAntialias( mrContext, true );
+ CGContextSetAlpha( mrContext, 1.0 - fTransparency );
+ CGContextDrawPath( mrContext, kCGPathEOFillStroke );
+ CGContextRestoreGState( mrContext );
+
+ // mark modified rectangle as updated
+ RefreshRect( aRefreshRect );
+ }
+
+ CGPathRelease( xPath );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon& rPolyLine,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin eLineJoin )
+{
+ // short circuit if there is nothing to do
+ const int nPointCount = rPolyLine.count();
+ if( nPointCount <= 0 )
+ return true;
+
+ // reject requests that cannot be handled yet
+ if( rLineWidths.getX() != rLineWidths.getY() )
+ return false;
+
+ // #i101491# Aqua does not support B2DLINEJOIN_NONE; return false to use
+ // the fallback (own geometry preparation)
+ // #i104886# linejoin-mode and thus the above only applies to "fat" lines
+ if( (basegfx::B2DLINEJOIN_NONE == eLineJoin)
+ && (rLineWidths.getX() > 1.3) )
+ return false;
+
+ // setup line attributes
+ CGLineJoin aCGLineJoin = kCGLineJoinMiter;
+ switch( eLineJoin ) {
+ case ::basegfx::B2DLINEJOIN_NONE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break;
+ case ::basegfx::B2DLINEJOIN_MIDDLE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break;
+ case ::basegfx::B2DLINEJOIN_BEVEL: aCGLineJoin = kCGLineJoinBevel; break;
+ case ::basegfx::B2DLINEJOIN_MITER: aCGLineJoin = kCGLineJoinMiter; break;
+ case ::basegfx::B2DLINEJOIN_ROUND: aCGLineJoin = kCGLineJoinRound; break;
+ }
+
+ // setup poly-polygon path
+ CGMutablePathRef xPath = CGPathCreateMutable();
+ AddPolygonToPath( xPath, rPolyLine, rPolyLine.isClosed(), !getAntiAliasB2DDraw(), true );
+
+ const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
+#ifndef NO_I97317_WORKAROUND
+ // #i97317# workaround for Quartz having problems with drawing small polygons
+ if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
+#endif
+ {
+ // use the path to prepare the graphics context
+ CGContextSaveGState( mrContext );
+ CGContextAddPath( mrContext, xPath );
+ // draw path with antialiased line
+ CGContextSetShouldAntialias( mrContext, true );
+ CGContextSetAlpha( mrContext, 1.0 - fTransparency );
+ CGContextSetLineJoin( mrContext, aCGLineJoin );
+ CGContextSetLineWidth( mrContext, rLineWidths.getX() );
+ CGContextDrawPath( mrContext, kCGPathStroke );
+ CGContextRestoreGState( mrContext );
+
+ // mark modified rectangle as updated
+ RefreshRect( aRefreshRect );
+ }
+
+ CGPathRelease( xPath );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::drawPolyPolygonBezier( ULONG nPoly, const ULONG* pPoints,
+ const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::copyBits( const SalTwoRect *pPosAry, SalGraphics *pSrcGraphics )
+{
+ if( !pSrcGraphics )
+ pSrcGraphics = this;
+
+ //from unix salgdi2.cxx
+ //[FIXME] find a better way to prevent calc from crashing when width and height are negative
+ if( pPosAry->mnSrcWidth <= 0
+ || pPosAry->mnSrcHeight <= 0
+ || pPosAry->mnDestWidth <= 0
+ || pPosAry->mnDestHeight <= 0 )
+ {
+ return;
+ }
+
+ // accelerate trivial operations
+ /*const*/ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
+ const bool bSameGraphics = (this == pSrc) || (mbWindow && mpFrame && pSrc->mbWindow && (mpFrame == pSrc->mpFrame));
+ if( bSameGraphics
+ && (pPosAry->mnSrcWidth == pPosAry->mnDestWidth)
+ && (pPosAry->mnSrcHeight == pPosAry->mnDestHeight))
+ {
+ // short circuit if there is nothing to do
+ if( (pPosAry->mnSrcX == pPosAry->mnDestX)
+ && (pPosAry->mnSrcY == pPosAry->mnDestY))
+ return;
+ // use copyArea() if source and destination context are identical
+ copyArea( pPosAry->mnDestX, pPosAry->mnDestY, pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 0 );
+ return;
+ }
+
+ ApplyXorContext();
+ pSrc->ApplyXorContext();
+
+ DBG_ASSERT( pSrc->mxLayer!=NULL, "AquaSalGraphics::copyBits() from non-layered graphics" );
+
+ const CGPoint aDstPoint = { +pPosAry->mnDestX - pPosAry->mnSrcX, pPosAry->mnDestY - pPosAry->mnSrcY };
+ if( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth && pPosAry->mnSrcHeight == pPosAry->mnDestHeight) &&
+ (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher
+ {
+ // in XOR mode the drawing context is redirected to the XOR mask
+ // if source and target are identical then copyBits() paints onto the target context though
+ CGContextRef xCopyContext = mrContext;
+ if( mpXorEmulation && mpXorEmulation->IsEnabled() )
+ if( pSrcGraphics == this )
+ xCopyContext = mpXorEmulation->GetTargetContext();
+
+ CGContextSaveGState( xCopyContext );
+ const CGRect aDstRect = { {pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight} };
+ CGContextClipToRect( xCopyContext, aDstRect );
+
+ // draw at new destination
+ // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down
+ if( pSrc->IsFlipped() )
+ { CGContextTranslateCTM( xCopyContext, 0, +mnHeight ); CGContextScaleCTM( xCopyContext, +1, -1 ); }
+ // TODO: pSrc->size() != this->size()
+ ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, pSrc->mxLayer );
+ CGContextRestoreGState( xCopyContext );
+ // mark the destination rectangle as updated
+ RefreshRect( aDstRect );
+ }
+ else
+ {
+ SalBitmap* pBitmap = pSrc->getBitmap( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight );
+
+ if( pBitmap )
+ {
+ SalTwoRect aPosAry( *pPosAry );
+ aPosAry.mnSrcX = 0;
+ aPosAry.mnSrcY = 0;
+ drawBitmap( &aPosAry, *pBitmap );
+ delete pBitmap;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::copyArea( long nDstX, long nDstY,long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, USHORT nFlags )
+{
+ ApplyXorContext();
+
+#if 0 // TODO: make AquaSalBitmap as fast as the alternative implementation below
+ SalBitmap* pBitmap = getBitmap( nSrcX, nSrcY, nSrcWidth, nSrcHeight );
+ if( pBitmap )
+ {
+ SalTwoRect aPosAry;
+ aPosAry.mnSrcX = 0;
+ aPosAry.mnSrcY = 0;
+ aPosAry.mnSrcWidth = nSrcWidth;
+ aPosAry.mnSrcHeight = nSrcHeight;
+ aPosAry.mnDestX = nDstX;
+ aPosAry.mnDestY = nDstY;
+ aPosAry.mnDestWidth = nSrcWidth;
+ aPosAry.mnDestHeight = nSrcHeight;
+ drawBitmap( &aPosAry, *pBitmap );
+ delete pBitmap;
+ }
+#else
+ DBG_ASSERT( mxLayer!=NULL, "AquaSalGraphics::copyArea() for non-layered graphics" );
+
+ // in XOR mode the drawing context is redirected to the XOR mask
+ // copyArea() always works on the target context though
+ CGContextRef xCopyContext = mrContext;
+ if( mpXorEmulation && mpXorEmulation->IsEnabled() )
+ xCopyContext = mpXorEmulation->GetTargetContext();
+
+ // drawing a layer onto its own context causes trouble on OSX => copy it first
+ // TODO: is it possible to get rid of this unneeded copy more often?
+ // e.g. on OSX>=10.5 only this situation causes problems:
+ // mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth
+ CGLayerRef xSrcLayer = mxLayer;
+ // TODO: if( mnBitmapDepth > 0 )
+ {
+ const CGSize aSrcSize = { nSrcWidth, nSrcHeight };
+ xSrcLayer = ::CGLayerCreateWithContext( xCopyContext, aSrcSize, NULL );
+ const CGContextRef xSrcContext = CGLayerGetContext( xSrcLayer );
+ CGPoint aSrcPoint = { -nSrcX, -nSrcY };
+ if( IsFlipped() )
+ {
+ ::CGContextTranslateCTM( xSrcContext, 0, +nSrcHeight );
+ ::CGContextScaleCTM( xSrcContext, +1, -1 );
+ aSrcPoint.y = (nSrcY + nSrcHeight) - mnHeight;
+ }
+ ::CGContextDrawLayerAtPoint( xSrcContext, aSrcPoint, mxLayer );
+ }
+
+ // draw at new destination
+ const CGPoint aDstPoint = { +nDstX, +nDstY };
+ ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, xSrcLayer );
+
+ // cleanup
+ if( xSrcLayer != mxLayer )
+ CGLayerRelease( xSrcLayer );
+
+ // mark the destination rectangle as updated
+ RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ if( !CheckContext() )
+ return;
+
+ const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
+ CGImageRef xImage = rBitmap.CreateCroppedImage( (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY, (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight );
+ if( !xImage )
+ return;
+
+ const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xImage );
+ CGImageRelease( xImage );
+ RefreshRect( aDstRect );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap,SalColor nTransparentColor )
+{
+ DBG_ERROR("not implemented for color masking!");
+ drawBitmap( pPosAry, rSalBitmap );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, const SalBitmap& rTransparentBitmap )
+{
+ if( !CheckContext() )
+ return;
+
+ const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
+ const AquaSalBitmap& rMask = static_cast<const AquaSalBitmap&>(rTransparentBitmap);
+ CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) );
+ if( !xMaskedImage )
+ return;
+
+ const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xMaskedImage );
+ CGImageRelease( xMaskedImage );
+ RefreshRect( aDstRect );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawMask( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, SalColor nMaskColor )
+{
+ if( !CheckContext() )
+ return;
+
+ const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
+ CGImageRef xImage = rBitmap.CreateColorMask( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, nMaskColor );
+ if( !xImage )
+ return;
+
+ const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xImage );
+ CGImageRelease( xImage );
+ RefreshRect( aDstRect );
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* AquaSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
+{
+ DBG_ASSERT( mxLayer, "AquaSalGraphics::getBitmap() with no layer" );
+
+ ApplyXorContext();
+
+ AquaSalBitmap* pBitmap = new AquaSalBitmap;
+ if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY, !mbWindow ) )
+ {
+ delete pBitmap;
+ pBitmap = NULL;
+ }
+
+ return pBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+SalColor AquaSalGraphics::getPixel( long nX, long nY )
+{
+ // return default value on printers or when out of bounds
+ if( !mxLayer
+ || (nX < 0) || (nX >= mnWidth)
+ || (nY < 0) || (nY >= mnHeight))
+ return COL_BLACK;
+
+ // prepare creation of matching a CGBitmapContext
+ CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big;
+#if __BIG_ENDIAN__
+ struct{ unsigned char b, g, r, a; } aPixel;
+#else
+ struct{ unsigned char a, r, g, b; } aPixel;
+#endif
+
+ // create a one-pixel bitmap context
+ // TODO: is it worth to cache it?
+ CGContextRef xOnePixelContext = ::CGBitmapContextCreate( &aPixel,
+ 1, 1, 8, sizeof(aPixel), aCGColorSpace, aCGBmpInfo );
+
+ // update this graphics layer
+ ApplyXorContext();
+
+ // copy the requested pixel into the bitmap context
+ if( IsFlipped() )
+ nY = mnHeight - nY;
+ const CGPoint aCGPoint = {-nX, -nY};
+ CGContextDrawLayerAtPoint( xOnePixelContext, aCGPoint, mxLayer );
+ CGContextRelease( xOnePixelContext );
+
+ SalColor nSalColor = MAKE_SALCOLOR( aPixel.r, aPixel.g, aPixel.b );
+ return nSalColor;
+}
+
+// -----------------------------------------------------------------------
+
+
+static void DrawPattern50( void* info, CGContextRef rContext )
+{
+ static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } };
+ CGContextAddRects( rContext, aRects, 2 );
+ CGContextFillPath( rContext );
+}
+
+void AquaSalGraphics::Pattern50Fill()
+{
+ static const float aFillCol[4] = { 1,1,1,1 };
+ static const CGPatternCallbacks aCallback = { 0, &DrawPattern50, NULL };
+ if( ! GetSalData()->mxP50Space )
+ GetSalData()->mxP50Space = CGColorSpaceCreatePattern( GetSalData()->mxRGBSpace );
+ if( ! GetSalData()->mxP50Pattern )
+ GetSalData()->mxP50Pattern = CGPatternCreate( NULL, CGRectMake( 0, 0, 4, 4 ),
+ CGAffineTransformIdentity, 4, 4,
+ kCGPatternTilingConstantSpacing,
+ false, &aCallback );
+
+ CGContextSetFillColorSpace( mrContext, GetSalData()->mxP50Space );
+ CGContextSetFillPattern( mrContext, GetSalData()->mxP50Pattern, aFillCol );
+ CGContextFillPath( mrContext );
+}
+
+void AquaSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
+{
+ if ( CheckContext() )
+ {
+ CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight);
+ CGContextSaveGState(mrContext);
+
+ if ( nFlags & SAL_INVERT_TRACKFRAME )
+ {
+ const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 );
+ CGContextSetLineDash ( mrContext, 0, dashLengths, 2 );
+ CGContextSetLineWidth( mrContext, 2.0);
+ CGContextStrokeRect ( mrContext, aCGRect );
+ }
+ else if ( nFlags & SAL_INVERT_50 )
+ {
+ //CGContextSetAllowsAntialiasing( mrContext, false );
+ CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
+ CGContextAddRect( mrContext, aCGRect );
+ Pattern50Fill();
+ }
+ else // just invert
+ {
+ CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
+ CGContextSetRGBFillColor ( mrContext,1.0, 1.0, 1.0 , 1.0 );
+ CGContextFillRect ( mrContext, aCGRect );
+ }
+ CGContextRestoreGState( mrContext);
+ RefreshRect( aCGRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nSalFlags )
+{
+ CGPoint* CGpoints ;
+ if ( CheckContext() )
+ {
+ CGContextSaveGState(mrContext);
+ CGpoints = makeCGptArray(nPoints,pPtAry);
+ CGContextAddLines ( mrContext, CGpoints, nPoints );
+ if ( nSalFlags & SAL_INVERT_TRACKFRAME )
+ {
+ const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 );
+ CGContextSetLineDash ( mrContext, 0, dashLengths, 2 );
+ CGContextSetLineWidth( mrContext, 2.0);
+ CGContextStrokePath ( mrContext );
+ }
+ else if ( nSalFlags & SAL_INVERT_50 )
+ {
+ CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
+ Pattern50Fill();
+ }
+ else // just invert
+ {
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ CGContextSetRGBFillColor( mrContext, 1.0, 1.0, 1.0, 1.0 );
+ CGContextFillPath( mrContext );
+ }
+ const CGRect aRefreshRect = CGContextGetClipBoundingBox(mrContext);
+ CGContextRestoreGState( mrContext);
+ delete [] CGpoints;
+ RefreshRect( aRefreshRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight,
+ void* pEpsData, ULONG nByteCount )
+{
+ // convert the raw data to an NSImageRef
+ NSData* xNSData = [NSData dataWithBytes:(void*)pEpsData length:(int)nByteCount];
+ NSImageRep* xEpsImage = [NSEPSImageRep imageRepWithData: xNSData];
+ if( !xEpsImage )
+ return false;
+
+ // get the target context
+ if( !CheckContext() )
+ return false;
+
+ // NOTE: flip drawing, else the nsimage would be drawn upside down
+ CGContextSaveGState( mrContext );
+// CGContextTranslateCTM( mrContext, 0, +mnHeight );
+ CGContextScaleCTM( mrContext, +1, -1 );
+ nY = /*mnHeight*/ - (nY + nHeight);
+
+ // prepare the target context
+ NSGraphicsContext* pOrigNSCtx = [NSGraphicsContext currentContext];
+ NSGraphicsContext* pDrawNSCtx = [NSGraphicsContext graphicsContextWithGraphicsPort: mrContext flipped: IsFlipped()];
+ [NSGraphicsContext setCurrentContext: pDrawNSCtx];
+ // draw the EPS
+ const NSRect aDstRect = {{nX,nY},{nWidth,nHeight}};
+ const BOOL bOK = [xEpsImage drawInRect: aDstRect];
+ CGContextRestoreGState( mrContext );
+ // mark the destination rectangle as updated
+ RefreshRect( aDstRect );
+ // restore the NSGraphicsContext, TODO: do we need this?
+ [NSGraphicsContext setCurrentContext: pOrigNSCtx];
+
+ return bOK;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
+{
+ // An image mask can't have a depth > 8 bits (should be 1 to 8 bits)
+ if( rAlphaBmp.GetBitCount() > 8 )
+ return false;
+
+ // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx)
+ // horizontal/vertical mirroring not implemented yet
+ if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 )
+ return false;
+
+ const AquaSalBitmap& rSrcSalBmp = static_cast<const AquaSalBitmap&>(rSrcBitmap);
+ const AquaSalBitmap& rMaskSalBmp = static_cast<const AquaSalBitmap&>(rAlphaBmp);
+
+ CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask( rMaskSalBmp, rTR.mnSrcX, rTR.mnSrcY, rTR.mnSrcWidth, rTR.mnSrcHeight );
+ if( !xMaskedImage )
+ return false;
+
+ if ( CheckContext() )
+ {
+ const CGRect aDstRect = {{rTR.mnDestX, rTR.mnDestY}, {rTR.mnDestWidth, rTR.mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xMaskedImage );
+ RefreshRect( aDstRect );
+ }
+
+ CGImageRelease(xMaskedImage);
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool AquaSalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency )
+{
+ if( !CheckContext() )
+ return true;
+
+ // save the current state
+ CGContextSaveGState( mrContext );
+ CGContextSetAlpha( mrContext, (100-nTransparency) * (1.0/100) );
+
+ CGRect aRect = {{nX,nY},{nWidth-1,nHeight-1}};
+ if( IsPenVisible() )
+ {
+ aRect.origin.x += 0.5;
+ aRect.origin.y += 0.5;
+ }
+
+ CGContextBeginPath( mrContext );
+ CGContextAddRect( mrContext, aRect );
+ CGContextDrawPath( mrContext, kCGPathFill );
+
+ // restore state
+ CGContextRestoreGState(mrContext);
+ RefreshRect( aRect );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetTextColor( SalColor nSalColor )
+{
+ RGBColor color;
+ color.red = (unsigned short) ( SALCOLOR_RED(nSalColor) * 65535.0 / 255.0 );
+ color.green = (unsigned short) ( SALCOLOR_GREEN(nSalColor) * 65535.0 / 255.0 );
+ color.blue = (unsigned short) ( SALCOLOR_BLUE(nSalColor) * 65535.0 / 255.0 );
+
+ ATSUAttributeTag aTag = kATSUColorTag;
+ ByteCount aValueSize = sizeof( color );
+ ATSUAttributeValuePtr aValue = &color;
+
+ OSStatus err = ATSUSetAttributes( maATSUStyle, 1, &aTag, &aValueSize, &aValue );
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::SetTextColor() : Could not set font attributes!\n");
+ if( err != noErr )
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
+{
+ // get the ATSU font metrics (in point units)
+ // of the font that has eventually been size-limited
+
+ ATSUFontID fontId;
+ OSStatus err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(ATSUFontID), &fontId, 0 );
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font id\n");
+
+ ATSFontMetrics aMetrics;
+ ATSFontRef rFont = FMGetATSFontRefFromFont( fontId );
+ err = ATSFontGetHorizontalMetrics ( rFont, kATSOptionFlagsDefault, &aMetrics );
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font metrics\n");
+ if( err != noErr )
+ return;
+
+ // all ATS fonts are scalable fonts
+ pMetric->mbScalableFont = true;
+ // TODO: check if any kerning is possible
+ pMetric->mbKernableFont = true;
+
+ // convert into VCL font metrics (in unscaled pixel units)
+
+ Fixed ptSize;
+ err = ATSUGetAttribute( maATSUStyle, kATSUSizeTag, sizeof(Fixed), &ptSize, 0);
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font size\n");
+ const double fPointSize = Fix2X( ptSize );
+
+ // convert quartz units to pixel units
+ // please see the comment in AquaSalGraphics::SetFont() for details
+ const double fPixelSize = (mfFontScale * mfFakeDPIScale * fPointSize);
+ pMetric->mnAscent = static_cast<long>(+aMetrics.ascent * fPixelSize + 0.5);
+ pMetric->mnDescent = static_cast<long>(-aMetrics.descent * fPixelSize + 0.5);
+ const long nExtDescent = static_cast<long>((-aMetrics.descent + aMetrics.leading) * fPixelSize + 0.5);
+ pMetric->mnExtLeading = nExtDescent - pMetric->mnDescent;
+ pMetric->mnIntLeading = 0;
+ // ATSFontMetrics.avgAdvanceWidth is obsolete, so it is usually set to zero
+ // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
+ // setting this width to the pixel height of the fontsize is good enough
+ // it also makes the calculation of the stretch factor simple
+ pMetric->mnWidth = static_cast<long>(mfFontStretch * fPixelSize + 0.5);
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static bool AddTempFontDir( const char* pDir )
+{
+ FSRef aPathFSRef;
+ Boolean bIsDirectory = true;
+ OSStatus eStatus = FSPathMakeRef( reinterpret_cast<const UInt8*>(pDir), &aPathFSRef, &bIsDirectory );
+ DBG_ASSERTWARNING( (eStatus==noErr) && bIsDirectory, "vcl AddTempFontDir() with invalid directory name!" );
+ if( eStatus != noErr )
+ return false;
+
+ // TODO: deactivate ATSFontContainerRef when closing app
+ ATSFontContainerRef aATSFontContainer;
+
+ const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+ eStatus = ::ATSFontActivateFromFileReference( &aPathFSRef,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &aATSFontContainer );
+#else
+ FSSpec aPathFSSpec;
+ eStatus = ::FSGetCatalogInfo( &aPathFSRef, kFSCatInfoNone,
+ NULL, NULL, &aPathFSSpec, NULL );
+ if( eStatus != noErr )
+ return false;
+
+ eStatus = ::ATSFontActivateFromFileSpecification( &aPathFSSpec,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &aATSFontContainer );
+#endif
+ if( eStatus != noErr )
+ return false;
+
+ return true;
+}
+
+static bool AddLocalTempFontDirs( void )
+{
+ static bool bFirst = true;
+ if( !bFirst )
+ return false;
+ bFirst = false;
+
+ // add private font files found in brand and base layer
+
+ rtl::OUString aBrandStr( RTL_CONSTASCII_USTRINGPARAM( "$BRAND_BASE_DIR" ) );
+ rtl_bootstrap_expandMacros( &aBrandStr.pData );
+ rtl::OUString aBrandSysPath;
+ OSL_VERIFY( osl_getSystemPathFromFileURL( aBrandStr.pData, &aBrandSysPath.pData ) == osl_File_E_None );
+
+ rtl::OStringBuffer aBrandFontDir( aBrandSysPath.getLength()*2 );
+ aBrandFontDir.append( rtl::OUStringToOString( aBrandSysPath, RTL_TEXTENCODING_UTF8 ) );
+ aBrandFontDir.append( "/share/fonts/truetype/" );
+ bool bBrandSuccess = AddTempFontDir( aBrandFontDir.getStr() );
+
+ rtl::OUString aBaseStr( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR" ) );
+ rtl_bootstrap_expandMacros( &aBaseStr.pData );
+ rtl::OUString aBaseSysPath;
+ OSL_VERIFY( osl_getSystemPathFromFileURL( aBaseStr.pData, &aBaseSysPath.pData ) == osl_File_E_None );
+
+ rtl::OStringBuffer aBaseFontDir( aBaseSysPath.getLength()*2 );
+ aBaseFontDir.append( rtl::OUStringToOString( aBaseSysPath, RTL_TEXTENCODING_UTF8 ) );
+ aBaseFontDir.append( "/share/fonts/truetype/" );
+ bool bBaseSuccess = AddTempFontDir( aBaseFontDir.getStr() );
+
+ return bBrandSuccess && bBaseSuccess;
+}
+
+void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
+{
+ DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
+
+ AddLocalTempFontDirs();
+
+ // The idea is to cache the list of system fonts once it has been generated.
+ // SalData seems to be a good place for this caching. However we have to
+ // carefully make the access to the font list thread-safe. If we register
+ // a font-change event handler to update the font list in case fonts have
+ // changed on the system we have to lock access to the list. The right
+ // way to do that is the solar mutex since GetDevFontList is protected
+ // through it as should be all event handlers
+
+ SalData* pSalData = GetSalData();
+ if (pSalData->mpFontList == NULL)
+ pSalData->mpFontList = new SystemFontList();
+
+ // Copy all ImplFontData objects contained in the SystemFontList
+ pSalData->mpFontList->AnnounceFonts( *pFontList );
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFontFileURL, const String& rFontName )
+{
+ ::rtl::OUString aUSytemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+
+ FSRef aNewRef;
+ Boolean bIsDirectory = true;
+ ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
+ OSStatus eStatus = FSPathMakeRef( (UInt8*)aCFileName.getStr(), &aNewRef, &bIsDirectory );
+ DBG_ASSERT( (eStatus==noErr) && !bIsDirectory, "vcl AddTempDevFont() with invalid fontfile name!" );
+ if( eStatus != noErr )
+ return false;
+
+ ATSFontContainerRef oContainer;
+
+ const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+ eStatus = ::ATSFontActivateFromFileReference( &aNewRef,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &oContainer );
+#else
+ FSSpec aFontFSSpec;
+ eStatus = ::FSGetCatalogInfo( &aNewRef, kFSCatInfoNone,
+ NULL, NULL, &aFontFSSpec, NULL );
+ if( eStatus != noErr )
+ return false;
+
+ eStatus = ::ATSFontActivateFromFileSpecification( &aFontFSSpec,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &oContainer );
+#endif
+ if( eStatus != noErr )
+ return false;
+
+ // TODO: ATSFontDeactivate( oContainer ) when fonts are no longer needed
+ // TODO: register new ImplMacFontdata in pFontList
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+// callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline()
+struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
+
+static OSStatus GgoLineToProc( const Float32Point* pPoint, void* pData )
+{
+ basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
+ const basegfx::B2DPoint aB2DPoint( pPoint->x, pPoint->y );
+ rPolygon.append( aB2DPoint );
+ return noErr;
+}
+
+static OSStatus GgoCurveToProc( const Float32Point* pCP1, const Float32Point* pCP2,
+ const Float32Point* pPoint, void* pData )
+{
+ basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
+ const sal_uInt32 nPointCount = rPolygon.count();
+ const basegfx::B2DPoint aB2DControlPoint1( pCP1->x, pCP1->y );
+ rPolygon.setNextControlPoint( nPointCount-1, aB2DControlPoint1 );
+ const basegfx::B2DPoint aB2DEndPoint( pPoint->x, pPoint->y );
+ rPolygon.append( aB2DEndPoint );
+ const basegfx::B2DPoint aB2DControlPoint2( pCP2->x, pCP2->y );
+ rPolygon.setPrevControlPoint( nPointCount, aB2DControlPoint2 );
+ return noErr;
+}
+
+static OSStatus GgoClosePathProc( void* pData )
+{
+ GgoData* pGgoData = static_cast<GgoData*>(pData);
+ basegfx::B2DPolygon& rPolygon = pGgoData->maPolygon;
+ if( rPolygon.count() > 0 )
+ pGgoData->mpPolyPoly->append( rPolygon );
+ rPolygon.clear();
+ return noErr;
+}
+
+static OSStatus GgoMoveToProc( const Float32Point* pPoint, void* pData )
+{
+ GgoClosePathProc( pData );
+ OSStatus eStatus = GgoLineToProc( pPoint, pData );
+ return eStatus;
+}
+
+BOOL AquaSalGraphics::GetGlyphOutline( long nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ GgoData aGgoData;
+ aGgoData.mpPolyPoly = &rPolyPoly;
+ rPolyPoly.clear();
+
+ ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback when CWS pdffix02 is integrated
+ OSStatus eGgoStatus = noErr;
+ OSStatus eStatus = ATSUGlyphGetCubicPaths( rATSUStyle, nGlyphId,
+ GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc,
+ &aGgoData, &eGgoStatus );
+ if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved?
+ return false;
+
+ GgoClosePathProc( &aGgoData );
+ if( mfFontScale != 1.0 ) {
+ rPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(+mfFontScale, +mfFontScale));
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+long AquaSalGraphics::GetGraphicsWidth() const
+{
+ long w = 0;
+ if( mrContext && (mbWindow || mbVirDev) )
+ {
+ w = mnWidth;
+ }
+
+ if( w == 0 )
+ {
+ if( mbWindow && mpFrame )
+ w = mpFrame->maGeometry.nWidth;
+ }
+
+ return w;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalGraphics::GetGlyphBoundRect( long nGlyphId, Rectangle& rRect )
+{
+ ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback
+ GlyphID aGlyphId = nGlyphId;
+ ATSGlyphScreenMetrics aGlyphMetrics;
+ OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle,
+ 1, &aGlyphId, 0, FALSE, !mbNonAntialiasedText, &aGlyphMetrics );
+ if( eStatus != noErr )
+ return false;
+
+ const long nMinX = (long)(+aGlyphMetrics.topLeft.x * mfFontScale - 0.5);
+ const long nMaxX = (long)(aGlyphMetrics.width * mfFontScale + 0.5) + nMinX;
+ const long nMinY = (long)(-aGlyphMetrics.topLeft.y * mfFontScale - 0.5);
+ const long nMaxY = (long)(aGlyphMetrics.height * mfFontScale + 0.5) + nMinY;
+ rRect = Rectangle( nMinX, nMinY, nMaxX, nMaxY );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetDevFontSubstList( OutputDevice* )
+{
+ // nothing to do since there are no device-specific fonts on Aqua
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+USHORT AquaSalGraphics::SetFont( ImplFontSelectData* pReqFont, int nFallbackLevel )
+{
+ if( !pReqFont )
+ {
+ ATSUClearStyle( maATSUStyle );
+ mpMacFontData = NULL;
+ return 0;
+ }
+
+ // store the requested device font entry
+ const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>( pReqFont->mpFontData );
+ mpMacFontData = pMacFont;
+
+ // convert pixel units (as seen by upper layers) to typographic point units
+ double fScaledAtsHeight = pReqFont->mfExactHeight;
+ // avoid Fixed16.16 overflows by limiting the ATS font size
+ static const float fMaxAtsHeight = 144.0;
+ if( fScaledAtsHeight <= fMaxAtsHeight )
+ mfFontScale = 1.0;
+ else
+ {
+ mfFontScale = fScaledAtsHeight / fMaxAtsHeight;
+ fScaledAtsHeight = fMaxAtsHeight;
+ }
+ Fixed fFixedSize = FloatToFixed( fScaledAtsHeight );
+ // enable bold-emulation if needed
+ Boolean bFakeBold = FALSE;
+ if( (pReqFont->GetWeight() >= WEIGHT_BOLD)
+ && (pMacFont->GetWeight() < WEIGHT_SEMIBOLD) )
+ bFakeBold = TRUE;
+ // enable italic-emulation if needed
+ Boolean bFakeItalic = FALSE;
+ if( ((pReqFont->GetSlant() == ITALIC_NORMAL) || (pReqFont->GetSlant() == ITALIC_OBLIQUE))
+ && !((pMacFont->GetSlant() == ITALIC_NORMAL) || (pMacFont->GetSlant() == ITALIC_OBLIQUE)) )
+ bFakeItalic = TRUE;
+
+ // enable/disable antialiased text
+ mbNonAntialiasedText = pReqFont->mbNonAntialiased;
+ UInt32 nStyleRenderingOptions = kATSStyleNoOptions;
+ if( pReqFont->mbNonAntialiased )
+ nStyleRenderingOptions |= kATSStyleNoAntiAliasing;
+
+ // set horizontal/vertical mode
+ ATSUVerticalCharacterType aVerticalCharacterType = kATSUStronglyHorizontal;
+ if( pReqFont->mbVertical )
+ aVerticalCharacterType = kATSUStronglyVertical;
+
+ // prepare ATS-fontid as type matching to the kATSUFontTag request
+ ATSUFontID nFontID = static_cast<ATSUFontID>(pMacFont->GetFontId());
+
+ // update ATSU style attributes with requested font parameters
+ // TODO: no need to set styles which are already defaulted
+
+ const ATSUAttributeTag aTag[] =
+ {
+ kATSUFontTag,
+ kATSUSizeTag,
+ kATSUQDBoldfaceTag,
+ kATSUQDItalicTag,
+ kATSUStyleRenderingOptionsTag,
+ kATSUVerticalCharacterTag
+ };
+
+ const ByteCount aValueSize[] =
+ {
+ sizeof(ATSUFontID),
+ sizeof(fFixedSize),
+ sizeof(bFakeBold),
+ sizeof(bFakeItalic),
+ sizeof(nStyleRenderingOptions),
+ sizeof(aVerticalCharacterType)
+ };
+
+ const ATSUAttributeValuePtr aValue[] =
+ {
+ &nFontID,
+ &fFixedSize,
+ &bFakeBold,
+ &bFakeItalic,
+ &nStyleRenderingOptions,
+ &aVerticalCharacterType
+ };
+
+ static const int nTagCount = sizeof(aTag) / sizeof(*aTag);
+ OSStatus eStatus = ATSUSetAttributes( maATSUStyle, nTagCount,
+ aTag, aValueSize, aValue );
+ // reset ATSUstyle if there was an error
+ if( eStatus != noErr )
+ {
+ DBG_WARNING( "AquaSalGraphics::SetFont() : Could not set font attributes!\n");
+ ATSUClearStyle( maATSUStyle );
+ mpMacFontData = NULL;
+ return 0;
+ }
+
+ // prepare font stretching
+ const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag;
+ if( (pReqFont->mnWidth == 0) || (pReqFont->mnWidth == pReqFont->mnHeight) )
+ {
+ mfFontStretch = 1.0;
+ ATSUClearAttributes( maATSUStyle, 1, &aMatrixTag );
+ }
+ else
+ {
+ mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
+ CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
+ const ATSUAttributeValuePtr aAttr = &aMatrix;
+ const ByteCount aMatrixBytes = sizeof(aMatrix);
+ eStatus = ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr );
+ DBG_ASSERT( (eStatus==noErr), "AquaSalGraphics::SetFont() : Could not set font matrix\n");
+ }
+
+ // prepare font rotation
+ mnATSUIRotation = FloatToFixed( pReqFont->mnOrientation / 10.0 );
+
+#if OSL_DEBUG_LEVEL > 3
+ fprintf( stderr, "SetFont to (\"%s\", \"%s\", fontid=%d) for (\"%s\" \"%s\" weight=%d, slant=%d size=%dx%d orientation=%d)\n",
+ ::rtl::OUStringToOString( pMacFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ ::rtl::OUStringToOString( pMacFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ (int)nFontID,
+ ::rtl::OUStringToOString( pReqFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ ::rtl::OUStringToOString( pReqFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ pReqFont->GetWeight(),
+ pReqFont->GetSlant(),
+ pReqFont->mnHeight,
+ pReqFont->mnWidth,
+ pReqFont->mnOrientation);
+#endif
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
+{
+ if( !mpMacFontData )
+ return ImplFontCharMap::GetDefaultMap();
+
+ return mpMacFontData->GetImplFontCharMap();
+}
+
+// -----------------------------------------------------------------------
+
+// fake a SFNT font directory entry for a font table
+// see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html#Directory
+static void FakeDirEntry( FourCharCode eFCC, ByteCount nOfs, ByteCount nLen,
+ const unsigned char* /*pData*/, unsigned char*& rpDest )
+{
+ // write entry tag
+ rpDest[ 0] = (char)(eFCC >> 24);
+ rpDest[ 1] = (char)(eFCC >> 16);
+ rpDest[ 2] = (char)(eFCC >> 8);
+ rpDest[ 3] = (char)(eFCC >> 0);
+ // TODO: get entry checksum and write it
+ // not too important since the subsetter doesn't care currently
+ // for( pData+nOfs ... pData+nOfs+nLen )
+ // write entry offset
+ rpDest[ 8] = (char)(nOfs >> 24);
+ rpDest[ 9] = (char)(nOfs >> 16);
+ rpDest[10] = (char)(nOfs >> 8);
+ rpDest[11] = (char)(nOfs >> 0);
+ // write entry length
+ rpDest[12] = (char)(nLen >> 24);
+ rpDest[13] = (char)(nLen >> 16);
+ rpDest[14] = (char)(nLen >> 8);
+ rpDest[15] = (char)(nLen >> 0);
+ // advance to next entry
+ rpDest += 16;
+}
+
+static bool GetRawFontData( const ImplFontData* pFontData,
+ ByteVector& rBuffer, bool* pJustCFF )
+{
+ const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
+ const ATSUFontID nFontId = static_cast<ATSUFontID>(pMacFont->GetFontId());
+ ATSFontRef rFont = FMGetATSFontRefFromFont( nFontId );
+
+ ByteCount nCffLen = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, 0, NULL, &nCffLen);
+ if( pJustCFF != NULL )
+ {
+ *pJustCFF = (eStatus == noErr) && (nCffLen > 0);
+ if( *pJustCFF )
+ {
+ rBuffer.resize( nCffLen );
+ eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[0], &nCffLen);
+ if( (eStatus != noErr) || (nCffLen <= 0) )
+ return false;
+ return true;
+ }
+ }
+
+ // get font table availability and size in bytes
+ ByteCount nHeadLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, 0, NULL, &nHeadLen);
+ if( (eStatus != noErr) || (nHeadLen <= 0) )
+ return false;
+ ByteCount nMaxpLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, 0, NULL, &nMaxpLen);
+ if( (eStatus != noErr) || (nMaxpLen <= 0) )
+ return false;
+ ByteCount nCmapLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nCmapLen);
+ if( (eStatus != noErr) || (nCmapLen <= 0) )
+ return false;
+ ByteCount nNameLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, 0, NULL, &nNameLen);
+ if( (eStatus != noErr) || (nNameLen <= 0) )
+ return false;
+ ByteCount nHheaLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, 0, NULL, &nHheaLen);
+ if( (eStatus != noErr) || (nHheaLen <= 0) )
+ return false;
+ ByteCount nHmtxLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, 0, NULL, &nHmtxLen);
+ if( (eStatus != noErr) || (nHmtxLen <= 0) )
+ return false;
+
+ // get the glyph outline tables
+ ByteCount nLocaLen = 0;
+ ByteCount nGlyfLen = 0;
+ if( (eStatus != noErr) || (nCffLen <= 0) )
+ {
+ eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, 0, NULL, &nLocaLen);
+ if( (eStatus != noErr) || (nLocaLen <= 0) )
+ return false;
+ eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, 0, NULL, &nGlyfLen);
+ if( (eStatus != noErr) || (nGlyfLen <= 0) )
+ return false;
+ }
+
+ ByteCount nPrepLen=0, nCvtLen=0, nFpgmLen=0;
+ if( nGlyfLen ) // TODO: reduce PDF size by making hint subsetting optional
+ {
+ eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, 0, NULL, &nPrepLen);
+ eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, 0, NULL, &nCvtLen);
+ eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, 0, NULL, &nFpgmLen);
+ }
+
+ // prepare a byte buffer for a fake font
+ int nTableCount = 7;
+ nTableCount += (nPrepLen>0) + (nCvtLen>0) + (nFpgmLen>0) + (nGlyfLen>0);
+ const ByteCount nFdirLen = 12 + 16*nTableCount;
+ ByteCount nTotalLen = nFdirLen;
+ nTotalLen += nHeadLen + nMaxpLen + nNameLen + nCmapLen;
+ if( nGlyfLen )
+ nTotalLen += nLocaLen + nGlyfLen;
+ else
+ nTotalLen += nCffLen;
+ nTotalLen += nHheaLen + nHmtxLen;
+ nTotalLen += nPrepLen + nCvtLen + nFpgmLen;
+ rBuffer.resize( nTotalLen );
+
+ // fake a SFNT font directory header
+ if( nTableCount < 16 )
+ {
+ int nLog2 = 0;
+ while( (nTableCount >> nLog2) > 1 ) ++nLog2;
+ rBuffer[ 1] = 1; // Win-TTF style scaler
+ rBuffer[ 5] = nTableCount; // table count
+ rBuffer[ 7] = nLog2*16; // searchRange
+ rBuffer[ 9] = nLog2; // entrySelector
+ rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
+ }
+
+ // get font table raw data and update the fake directory entries
+ ByteCount nOfs = nFdirLen;
+ unsigned char* pFakeEntry = &rBuffer[12];
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nCmapLen, (void*)&rBuffer[nOfs], &nCmapLen);
+ FakeDirEntry( GetTag("cmap"), nOfs, nCmapLen, &rBuffer[0], pFakeEntry );
+ nOfs += nCmapLen;
+ if( nCvtLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, nCvtLen, (void*)&rBuffer[nOfs], &nCvtLen);
+ FakeDirEntry( GetTag("cvt "), nOfs, nCvtLen, &rBuffer[0], pFakeEntry );
+ nOfs += nCvtLen;
+ }
+ if( nFpgmLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, nFpgmLen, (void*)&rBuffer[nOfs], &nFpgmLen);
+ FakeDirEntry( GetTag("fpgm"), nOfs, nFpgmLen, &rBuffer[0], pFakeEntry );
+ nOfs += nFpgmLen;
+ }
+ if( nCffLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[nOfs], &nCffLen);
+ FakeDirEntry( GetTag("CFF "), nOfs, nCffLen, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfLen;
+ } else {
+ eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, nGlyfLen, (void*)&rBuffer[nOfs], &nGlyfLen);
+ FakeDirEntry( GetTag("glyf"), nOfs, nGlyfLen, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, nLocaLen, (void*)&rBuffer[nOfs], &nLocaLen);
+ FakeDirEntry( GetTag("loca"), nOfs, nLocaLen, &rBuffer[0], pFakeEntry );
+ nOfs += nLocaLen;
+ }
+ eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, nHeadLen, (void*)&rBuffer[nOfs], &nHeadLen);
+ FakeDirEntry( GetTag("head"), nOfs, nHeadLen, &rBuffer[0], pFakeEntry );
+ nOfs += nHeadLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, nHheaLen, (void*)&rBuffer[nOfs], &nHheaLen);
+ FakeDirEntry( GetTag("hhea"), nOfs, nHheaLen, &rBuffer[0], pFakeEntry );
+ nOfs += nHheaLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, nHmtxLen, (void*)&rBuffer[nOfs], &nHmtxLen);
+ FakeDirEntry( GetTag("hmtx"), nOfs, nHmtxLen, &rBuffer[0], pFakeEntry );
+ nOfs += nHmtxLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, nMaxpLen, (void*)&rBuffer[nOfs], &nMaxpLen);
+ FakeDirEntry( GetTag("maxp"), nOfs, nMaxpLen, &rBuffer[0], pFakeEntry );
+ nOfs += nMaxpLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, nNameLen, (void*)&rBuffer[nOfs], &nNameLen);
+ FakeDirEntry( GetTag("name"), nOfs, nNameLen, &rBuffer[0], pFakeEntry );
+ nOfs += nNameLen;
+ if( nPrepLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, nPrepLen, (void*)&rBuffer[nOfs], &nPrepLen);
+ FakeDirEntry( GetTag("prep"), nOfs, nPrepLen, &rBuffer[0], pFakeEntry );
+ nOfs += nPrepLen;
+ }
+
+ DBG_ASSERT( (nOfs==nTotalLen), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalLen)");
+
+ return true;
+}
+
+BOOL AquaSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFontData, long* pGlyphIDs, sal_uInt8* pEncoding,
+ sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
+{
+ // TODO: move more of the functionality here into the generic subsetter code
+
+ // prepare the requested file name for writing the font-subset file
+ rtl::OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+ return FALSE;
+ const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+ const ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
+
+ // get the raw-bytes from the font to be subset
+ ByteVector aBuffer;
+ bool bCffOnly = false;
+ if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) )
+ return sal_False;
+
+ // handle CFF-subsetting
+ if( bCffOnly )
+ {
+ // provide the raw-CFF data to the subsetter
+ ByteCount nCffLen = aBuffer.size();
+ rInfo.LoadFont( FontSubsetInfo::CFF_FONT, &aBuffer[0], nCffLen );
+
+ // NOTE: assuming that all glyphids requested on Aqua are fully translated
+
+ // make the subsetter provide the requested subset
+ FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+ bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
+ pGlyphIDs, pEncoding, nGlyphCount, pGlyphWidths );
+ fclose( pOutFile );
+ return bRC;
+ }
+
+ // TODO: modernize psprint's horrible fontsubset C-API
+ // this probably only makes sense after the switch to another SCM
+ // that can preserve change history after file renames
+
+ // prepare data for psprint's font subsetter
+ TrueTypeFont* pSftFont = NULL;
+ int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
+ if( nRC != SF_OK )
+ return sal_False;
+
+ // get details about the subsetted font
+ TTGlobalFontInfo aTTInfo;
+ ::GetTTGlobalFontInfo( pSftFont, &aTTInfo );
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ rInfo.m_aPSName = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 );
+ rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
+ Point( aTTInfo.xMax, aTTInfo.yMax ) );
+ rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
+ rInfo.m_nAscent = +aTTInfo.winAscent;
+ rInfo.m_nDescent = -aTTInfo.winDescent;
+ // mac fonts usually do not have an OS2-table
+ // => get valid ascent/descent values from other tables
+ if( !rInfo.m_nAscent )
+ rInfo.m_nAscent = +aTTInfo.typoAscender;
+ if( !rInfo.m_nAscent )
+ rInfo.m_nAscent = +aTTInfo.ascender;
+ if( !rInfo.m_nDescent )
+ rInfo.m_nDescent = +aTTInfo.typoDescender;
+ if( !rInfo.m_nDescent )
+ rInfo.m_nDescent = -aTTInfo.descender;
+
+ // subset glyphs and get their properties
+ // take care that subset fonts require the NotDef glyph in pos 0
+ int nOrigCount = nGlyphCount;
+ USHORT aShortIDs[ 256 ];
+ sal_uInt8 aTempEncs[ 256 ];
+
+ int nNotDef = -1;
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ aTempEncs[i] = pEncoding[i];
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR )
+ {
+ bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0;
+ nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ if( nGlyphIdx == 0 && pFontData->IsSymbolFont() )
+ {
+ // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
+ nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 );
+ nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ }
+ }
+ aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
+ if( !nGlyphIdx )
+ if( nNotDef < 0 )
+ nNotDef = i; // first NotDef glyph found
+ }
+
+ if( nNotDef != 0 )
+ {
+ // add fake NotDef glyph if needed
+ if( nNotDef < 0 )
+ nNotDef = nGlyphCount++;
+
+ // NotDef glyph must be in pos 0 => swap glyphids
+ aShortIDs[ nNotDef ] = aShortIDs[0];
+ aTempEncs[ nNotDef ] = aTempEncs[0];
+ aShortIDs[0] = 0;
+ aTempEncs[0] = 0;
+ }
+ DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
+
+ // TODO: where to get bVertical?
+ const bool bVertical = false;
+
+ // fill the pGlyphWidths array
+ // while making sure that the NotDef glyph is at index==0
+ TTSimpleGlyphMetrics* pGlyphMetrics =
+ ::GetTTSimpleGlyphMetrics( pSftFont, aShortIDs, nGlyphCount, bVertical );
+ if( !pGlyphMetrics )
+ return FALSE;
+ sal_uInt16 nNotDefAdv = pGlyphMetrics[0].adv;
+ pGlyphMetrics[0].adv = pGlyphMetrics[nNotDef].adv;
+ pGlyphMetrics[nNotDef].adv = nNotDefAdv;
+ for( int i = 0; i < nOrigCount; ++i )
+ pGlyphWidths[i] = pGlyphMetrics[i].adv;
+ free( pGlyphMetrics );
+
+ // write subset into destination file
+ nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.GetBuffer(), aShortIDs,
+ aTempEncs, nGlyphCount, 0, NULL, 0 );
+ ::CloseTTFont(pSftFont);
+ return (nRC == SF_OK);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetGlyphWidths( const ImplFontData* pFontData, bool bVertical,
+ Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
+{
+ rGlyphWidths.clear();
+ rUnicodeEnc.clear();
+
+ if( pFontData->IsSubsettable() )
+ {
+ ByteVector aBuffer;
+ if( !GetRawFontData( pFontData, aBuffer, NULL ) )
+ return;
+
+ // TODO: modernize psprint's horrible fontsubset C-API
+ // this probably only makes sense after the switch to another SCM
+ // that can preserve change history after file renames
+
+ // use the font subsetter to get the widths
+ TrueTypeFont* pSftFont = NULL;
+ int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
+ if( nRC != SF_OK )
+ return;
+
+ const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
+ if( nGlyphCount > 0 )
+ {
+ // get glyph metrics
+ rGlyphWidths.resize(nGlyphCount);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
+ for( int i = 0; i < nGlyphCount; i++ )
+ aGlyphIds[i] = static_cast<sal_uInt16>(i);
+ const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
+ pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
+ if( pGlyphMetrics )
+ {
+ for( int i = 0; i < nGlyphCount; ++i )
+ rGlyphWidths[i] = pGlyphMetrics[i].adv;
+ free( (void*)pGlyphMetrics );
+ }
+
+ const ImplFontCharMap* pMap = mpMacFontData->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
+
+ // get unicode<->glyph encoding
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
+ {
+ if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
+ break;
+ sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
+ sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
+ if( nGlyph > 0 )
+ rUnicodeEnc[ nUcsChar ] = nGlyph;
+ }
+ }
+
+ ::CloseTTFont( pSftFont );
+ }
+ else if( pFontData->IsEmbeddable() )
+ {
+ // get individual character widths
+#if 0 // FIXME
+ rWidths.reserve( 224 );
+ for( sal_Unicode i = 32; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) )
+ {
+ rUnicodeEnc[ i ] = rWidths.size();
+ rWidths.push_back( nCharWidth );
+ }
+ }
+#else
+ DBG_ERROR("not implemented for non-subsettable fonts!\n");
+#endif
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
+ const ImplFontData* pFontData, const Ucs2OStrMap** ppNonEncoded )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+const void* AquaSalGraphics::GetEmbedFontData( const ImplFontData* pFontData,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::FreeEmbedFontData( const void* pData, long nDataLen )
+{
+ // TODO: implementing this only makes sense when the implementation of
+ // AquaSalGraphics::GetEmbedFontData() returns non-NULL
+ DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
+}
+
+// -----------------------------------------------------------------------
+
+SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
+{
+ SystemFontData aSysFontData;
+ OSStatus err;
+ aSysFontData.nSize = sizeof( SystemFontData );
+
+ // NOTE: Native ATSU font fallbacks are used, not the VCL fallbacks.
+ ATSUFontID fontId;
+ err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(fontId), &fontId, 0 );
+ if (err) fontId = 0;
+ aSysFontData.aATSUFontID = (void *) fontId;
+
+ Boolean bFbold;
+ err = ATSUGetAttribute( maATSUStyle, kATSUQDBoldfaceTag, sizeof(bFbold), &bFbold, 0 );
+ if (err) bFbold = FALSE;
+ aSysFontData.bFakeBold = (bool) bFbold;
+
+ Boolean bFItalic;
+ err = ATSUGetAttribute( maATSUStyle, kATSUQDItalicTag, sizeof(bFItalic), &bFItalic, 0 );
+ if (err) bFItalic = FALSE;
+ aSysFontData.bFakeItalic = (bool) bFItalic;
+
+ ATSUVerticalCharacterType aVerticalCharacterType;
+ err = ATSUGetAttribute( maATSUStyle, kATSUVerticalCharacterTag, sizeof(aVerticalCharacterType), &aVerticalCharacterType, 0 );
+ if (!err && aVerticalCharacterType == kATSUStronglyVertical) {
+ aSysFontData.bVerticalCharacterType = true;
+ } else {
+ aSysFontData.bVerticalCharacterType = false;
+ }
+
+ aSysFontData.bAntialias = !mbNonAntialiasedText;
+
+ return aSysFontData;
+}
+
+// -----------------------------------------------------------------------
+
+SystemGraphicsData AquaSalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.rCGContext = mrContext;
+ return aRes;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
+{
+ // return early if XOR mode remains unchanged
+ if( mbPrinter )
+ return;
+
+ if( ! bSet && mnXorMode == 2 )
+ {
+ CGContextSetBlendMode( mrContext, kCGBlendModeNormal );
+ mnXorMode = 0;
+ return;
+ }
+ else if( bSet && bInvertOnly && mnXorMode == 0)
+ {
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ mnXorMode = 2;
+ return;
+ }
+
+ if( (mpXorEmulation == NULL) && !bSet )
+ return;
+ if( (mpXorEmulation != NULL) && (bSet == mpXorEmulation->IsEnabled()) )
+ return;
+ if( !CheckContext() )
+ return;
+
+ // prepare XOR emulation
+ if( !mpXorEmulation )
+ {
+ mpXorEmulation = new XorEmulation();
+ mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
+ }
+
+ // change the XOR mode
+ if( bSet )
+ {
+ mpXorEmulation->Enable();
+ mrContext = mpXorEmulation->GetMaskContext();
+ mnXorMode = 1;
+ }
+ else
+ {
+ mpXorEmulation->UpdateTarget();
+ mpXorEmulation->Disable();
+ mrContext = mpXorEmulation->GetTargetContext();
+ mnXorMode = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// apply the XOR mask to the target context if active and dirty
+void AquaSalGraphics::ApplyXorContext()
+{
+ if( !mpXorEmulation )
+ return;
+ if( mpXorEmulation->UpdateTarget() )
+ RefreshRect( 0, 0, mnWidth, mnHeight ); // TODO: refresh minimal changerect
+}
+
+// ======================================================================
+
+XorEmulation::XorEmulation()
+: mxTargetLayer( NULL )
+, mxTargetContext( NULL )
+, mxMaskContext( NULL )
+, mxTempContext( NULL )
+, mpMaskBuffer( NULL )
+, mpTempBuffer( NULL )
+, mnBufferLongs( 0 )
+, mbIsEnabled( false )
+{}
+
+// ----------------------------------------------------------------------
+
+XorEmulation::~XorEmulation()
+{
+ Disable();
+ SetTarget( 0, 0, 0, NULL, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth,
+ CGContextRef xTargetContext, CGLayerRef xTargetLayer )
+{
+ // prepare to replace old mask+temp context
+ if( mxMaskContext )
+ {
+ // cleanup the mask context
+ CGContextRelease( mxMaskContext );
+ delete[] mpMaskBuffer;
+ mxMaskContext = NULL;
+ mpMaskBuffer = NULL;
+
+ // cleanup the temp context if needed
+ if( mxTempContext )
+ {
+ CGContextRelease( mxTempContext );
+ delete[] mpTempBuffer;
+ mxTempContext = NULL;
+ mpTempBuffer = NULL;
+ }
+ }
+
+ // return early if there is nothing more to do
+ if( !xTargetContext )
+ return;
+
+ // retarget drawing operations to the XOR mask
+ mxTargetLayer = xTargetLayer;
+ mxTargetContext = xTargetContext;
+
+ // prepare creation of matching CGBitmaps
+ CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
+ int nBitDepth = nTargetDepth;
+ if( !nBitDepth )
+ nBitDepth = 32;
+ int nBytesPerRow = (nBitDepth == 16) ? 2 : 4;
+ const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8;
+ if( nBitDepth <= 8 )
+ {
+ aCGColorSpace = GetSalData()->mxGraySpace;
+ aCGBmpInfo = kCGImageAlphaNone;
+ nBytesPerRow = 1;
+ }
+ nBytesPerRow *= nWidth;
+ mnBufferLongs = (nHeight * nBytesPerRow + sizeof(ULONG)-1) / sizeof(ULONG);
+
+ // create a XorMask context
+ mpMaskBuffer = new ULONG[ mnBufferLongs ];
+ mxMaskContext = ::CGBitmapContextCreate( mpMaskBuffer,
+ nWidth, nHeight, nBitsPerComponent, nBytesPerRow,
+ aCGColorSpace, aCGBmpInfo );
+ // reset the XOR mask to black
+ memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(ULONG) );
+
+ // a bitmap context will be needed for manual XORing
+ // create one unless the target context is a bitmap context
+ if( nTargetDepth )
+ mpTempBuffer = (ULONG*)CGBitmapContextGetData( mxTargetContext );
+ if( !mpTempBuffer )
+ {
+ // create a bitmap context matching to the target context
+ mpTempBuffer = new ULONG[ mnBufferLongs ];
+ mxTempContext = ::CGBitmapContextCreate( mpTempBuffer,
+ nWidth, nHeight, nBitsPerComponent, nBytesPerRow,
+ aCGColorSpace, aCGBmpInfo );
+ }
+
+ // initialize XOR mask context for drawing
+ CGContextSetFillColorSpace( mxMaskContext, aCGColorSpace );
+ CGContextSetStrokeColorSpace( mxMaskContext, aCGColorSpace );
+ CGContextSetShouldAntialias( mxMaskContext, false );
+
+ // improve the XorMask's XOR emulation a litte
+ // NOTE: currently only enabled for monochrome contexts
+ if( aCGColorSpace == GetSalData()->mxGraySpace )
+ CGContextSetBlendMode( mxMaskContext, kCGBlendModeDifference );
+
+ // intialize the transformation matrix to the drawing target
+ const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext );
+ CGContextConcatCTM( mxMaskContext, aCTM );
+ if( mxTempContext )
+ CGContextConcatCTM( mxTempContext, aCTM );
+
+ // initialize the default XorMask graphics state
+ CGContextSaveGState( mxMaskContext );
+}
+
+// ----------------------------------------------------------------------
+
+bool XorEmulation::UpdateTarget()
+{
+ if( !IsEnabled() )
+ return false;
+
+ // update the temp bitmap buffer if needed
+ if( mxTempContext )
+ CGContextDrawLayerAtPoint( mxTempContext, CGPointZero, mxTargetLayer );
+
+ // do a manual XOR with the XorMask
+ // this approach suffices for simple color manipulations
+ // and also the complex-clipping-XOR-trick used in metafiles
+ const ULONG* pSrc = mpMaskBuffer;
+ ULONG* pDst = mpTempBuffer;
+ for( int i = mnBufferLongs; --i >= 0;)
+ *(pDst++) ^= *(pSrc++);
+
+ // write back the XOR results to the target context
+ if( mxTempContext )
+ {
+ CGImageRef xXorImage = CGBitmapContextCreateImage( mxTempContext );
+ const int nWidth = (int)CGImageGetWidth( xXorImage );
+ const int nHeight = (int)CGImageGetHeight( xXorImage );
+ // TODO: update minimal changerect
+ const CGRect aFullRect = {{0,0},{nWidth,nHeight}};
+ CGContextDrawImage( mxTargetContext, aFullRect, xXorImage );
+ CGImageRelease( xXorImage );
+ }
+
+ // reset the XorMask to black again
+ // TODO: not needed for last update
+ memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(ULONG) );
+
+ // TODO: return FALSE if target was not changed
+ return true;
+}
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salgdiutils.cxx b/vcl/aqua/source/gdi/salgdiutils.cxx
new file mode 100755
index 000000000000..f7c234d2c4c4
--- /dev/null
+++ b/vcl/aqua/source/gdi/salgdiutils.cxx
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salgdi.h"
+#include "salframe.h"
+
+#include "basebmp/scanlineformats.hxx"
+#include "basebmp/color.hxx"
+#include "basegfx/range/b2drectangle.hxx"
+#include "basegfx/range/b2irange.hxx"
+#include "basegfx/vector/b2ivector.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include <boost/bind.hpp>
+
+#include "vcl/svapp.hxx"
+#include "saldata.hxx"
+
+// ----------------------------------------------------------------------
+
+void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame )
+{
+ mpFrame = pFrame;
+
+ mbWindow = true;
+ mbPrinter = false;
+ mbVirDev = false;
+}
+
+void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, long nDPIX, long nDPIY, double fScale )
+{
+ mbWindow = false;
+ mbPrinter = true;
+ mbVirDev = false;
+
+ mrContext = xContext;
+ mfFakeDPIScale = fScale;
+ mnRealDPIX = nDPIX;
+ mnRealDPIY = nDPIY;
+
+ // a previously set clip path is now invalid
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+
+ if( mrContext )
+ {
+ CGContextSetFillColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSetStrokeColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSaveGState( mrContext );
+ SetState();
+ }
+}
+
+void AquaSalGraphics::SetVirDevGraphics( CGLayerRef xLayer, CGContextRef xContext,
+ int nBitmapDepth )
+{
+ mbWindow = false;
+ mbPrinter = false;
+ mbVirDev = true;
+
+ // set graphics properties
+ mxLayer = xLayer;
+ mrContext = xContext;
+ mnBitmapDepth = nBitmapDepth;
+
+ // return early if the virdev is being destroyed
+ if( !xContext )
+ return;
+
+ // get new graphics properties
+ if( !mxLayer )
+ {
+ mnWidth = CGBitmapContextGetWidth( mrContext );
+ mnHeight = CGBitmapContextGetHeight( mrContext );
+ }
+ else
+ {
+ const CGSize aSize = CGLayerGetSize( mxLayer );
+ mnWidth = static_cast<int>(aSize.width);
+ mnHeight = static_cast<int>(aSize.height);
+ }
+
+ // prepare graphics for drawing
+ const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGContextSetFillColorSpace( mrContext, aCGColorSpace );
+ CGContextSetStrokeColorSpace( mrContext, aCGColorSpace );
+
+ // re-enable XorEmulation for the new context
+ if( mpXorEmulation )
+ {
+ mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
+ if( mpXorEmulation->IsEnabled() )
+ mrContext = mpXorEmulation->GetMaskContext();
+ }
+
+ // initialize stack of CGContext states
+ CGContextSaveGState( mrContext );
+ SetState();
+}
+
+// ----------------------------------------------------------------------
+
+void AquaSalGraphics::InvalidateContext()
+{
+ UnsetState();
+ mrContext = 0;
+}
+
+// ----------------------------------------------------------------------
+
+void AquaSalGraphics::UnsetState()
+{
+ if( mrContext )
+ {
+ CGContextRestoreGState( mrContext );
+ mrContext = 0;
+ }
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+}
+
+void AquaSalGraphics::SetState()
+{
+ CGContextRestoreGState( mrContext );
+ CGContextSaveGState( mrContext );
+
+ // setup clipping
+ if( mxClipPath )
+ {
+ CGContextBeginPath( mrContext ); // discard any existing path
+ CGContextAddPath( mrContext, mxClipPath ); // set the current path to the clipping path
+ CGContextClip( mrContext ); // use it for clipping
+ }
+
+ // set RGB colorspace and line and fill colors
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+ CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
+ CGContextSetShouldAntialias( mrContext, false );
+ if( mnXorMode == 2 )
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+}
+
+// ----------------------------------------------------------------------
+
+bool AquaSalGraphics::CheckContext()
+{
+ if( mbWindow && mpFrame != NULL )
+ {
+ const unsigned int nWidth = mpFrame->maGeometry.nWidth;
+ const unsigned int nHeight = mpFrame->maGeometry.nHeight;
+
+ CGContextRef rReleaseContext = 0;
+ CGLayerRef rReleaseLayer = NULL;
+
+ // check if a new drawing context is needed (e.g. after a resize)
+ if( (unsigned(mnWidth) != nWidth) || (unsigned(mnHeight) != nHeight) )
+ {
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ // prepare to release the corresponding resources
+ rReleaseContext = mrContext;
+ rReleaseLayer = mxLayer;
+ mrContext = NULL;
+ mxLayer = NULL;
+ }
+
+ if( !mrContext )
+ {
+ const CGSize aLayerSize = {nWidth,nHeight};
+ NSGraphicsContext* pNSGContext = [NSGraphicsContext graphicsContextWithWindow: mpFrame->getWindow()];
+ CGContextRef xCGContext = reinterpret_cast<CGContextRef>([pNSGContext graphicsPort]);
+ mxLayer = CGLayerCreateWithContext( xCGContext, aLayerSize, NULL );
+ if( mxLayer )
+ mrContext = CGLayerGetContext( mxLayer );
+
+ if( mrContext )
+ {
+ // copy original layer to resized layer
+ if( rReleaseLayer )
+ CGContextDrawLayerAtPoint( mrContext, CGPointZero, rReleaseLayer );
+
+ CGContextTranslateCTM( mrContext, 0, nHeight );
+ CGContextScaleCTM( mrContext, 1.0, -1.0 );
+ CGContextSetFillColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSetStrokeColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSaveGState( mrContext );
+ SetState();
+
+ // re-enable XOR emulation for the new context
+ if( mpXorEmulation )
+ mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
+ }
+ }
+
+ if( rReleaseLayer )
+ CGLayerRelease( rReleaseLayer );
+ else if( rReleaseContext )
+ CGContextRelease( rReleaseContext );
+ }
+
+ DBG_ASSERT( mrContext || mbPrinter, "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!\n" );
+ return (mrContext != NULL);
+}
+
+
+void AquaSalGraphics::RefreshRect(float lX, float lY, float lWidth, float lHeight)
+{
+ if( ! mbWindow ) // view only on Window graphics
+ return;
+
+ if( mpFrame )
+ {
+ // update a little more around the designated rectangle
+ // this helps with antialiased rendering
+ const Rectangle aVclRect(Point(static_cast<long int>(lX-1),
+ static_cast<long int>(lY-1) ),
+ Size( static_cast<long int>(lWidth+2),
+ static_cast<long int>(lHeight+2) ) );
+ mpFrame->maInvalidRect.Union( aVclRect );
+ }
+}
+
+CGPoint* AquaSalGraphics::makeCGptArray(ULONG nPoints, const SalPoint* pPtAry)
+{
+ CGPoint *CGpoints = new (CGPoint[nPoints]);
+ if ( CGpoints )
+ {
+ for(ULONG i=0;i<nPoints;i++)
+ {
+ CGpoints[i].x = (float)(pPtAry[i].mnX);
+ CGpoints[i].y = (float)(pPtAry[i].mnY);
+ }
+ }
+ return CGpoints;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::UpdateWindow( NSRect& rRect )
+{
+ if( !mpFrame )
+ return;
+ NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
+ if( (mxLayer != NULL) && (pContext != NULL) )
+ {
+ CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
+
+ CGMutablePathRef rClip = mpFrame->getClipPath();
+ if( rClip )
+ {
+ CGContextSaveGState( rCGContext );
+ CGContextBeginPath( rCGContext );
+ CGContextAddPath( rCGContext, rClip );
+ CGContextClip( rCGContext );
+ }
+
+ ApplyXorContext();
+ CGContextDrawLayerAtPoint( rCGContext, CGPointZero, mxLayer );
+ if( rClip ) // cleanup clipping
+ CGContextRestoreGState( rCGContext );
+ }
+ else
+ DBG_ASSERT( mpFrame->mbInitShow, "UpdateWindow called on uneligible graphics" );
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/aqua/source/gdi/salmathutils.cxx b/vcl/aqua/source/gdi/salmathutils.cxx
new file mode 100755
index 000000000000..8df44acbf730
--- /dev/null
+++ b/vcl/aqua/source/gdi/salmathutils.cxx
@@ -0,0 +1,163 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salmathutils.hxx"
+
+#include <stdlib.h>
+
+// =======================================================================
+
+// =======================================================================
+
+#define Swap( x, y ) { x ^= y; y ^= x; x ^= y; }
+
+// =======================================================================
+
+// =======================================================================
+
+// Storage free swapping using XOR
+
+void CSwap ( char &rX, char &rY )
+{
+ Swap( rX, rY );
+} // CSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void UCSwap ( unsigned char &rX, unsigned char &rY )
+{
+ Swap( rX, rY );
+} // UCSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void SSwap ( short &rX, short &rY )
+{
+ Swap( rX, rY );
+} // SSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void USSwap ( unsigned short &rX, unsigned short &rY )
+{
+ Swap( rX, rY );
+} // USSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void LSwap ( long &rX, long &rY )
+{
+ Swap( rX, rY );
+} // LSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void ULSwap ( unsigned long &rX, unsigned long &rY )
+{
+ Swap( rX, rY );
+} // ULSwap
+
+// =======================================================================
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+//
+// This way of measuring distance is also called the "Manhattan distance."
+// Manhattan distance takes advantage of the fact that the sum of the
+// lengths of the three components of a 3D vector is a rough approxima-
+// tion of the vector's length.
+//
+// -----------------------------------------------------------------------
+
+unsigned long Euclidian2Norm ( const LRectCoorVector pVec )
+{
+ unsigned long ndist = 0;
+
+ if ( pVec )
+ {
+ long nDX = 0;
+ long nDY = 0;
+ long nDZ = 0;
+ unsigned long nMax = 0;
+ unsigned long nMed = 0;
+ unsigned long nMin = 0;
+
+ // Find |x'-x|, |y'-y|, and |z'-z| from (x,y,z) and (x',y',z')
+
+ nDX = pVec[1].x - pVec[0].x;
+ nDY = pVec[1].y - pVec[0].y;
+ nDZ = pVec[1].z - pVec[0].z;
+
+ nMax = (unsigned long)abs( nDX );
+ nMed = (unsigned long)abs( nDY );
+ nMin = (unsigned long)abs( nDZ );
+
+ // Sort them (3 compares, 0-3 swaps)
+
+ if ( nMax < nMed )
+ {
+ Swap( nMax, nMed );
+ } // if
+
+ if ( nMax < nMin )
+ {
+ Swap( nMax, nMin );
+ } // if
+
+ // Approximate Euclidian distance:
+ //
+ // d = max + (11/32)*med + (1/4)*min
+ //
+ // with +/- 8% error, where the exact formulae for d is
+ //
+ // || (x',y',z') - (x,y,z) || = { |x'-x|^2 + |y'-y|^2 + |z'-z|^2 }^(1/2)
+
+ ndist = nMax + ( nMin >> 2UL )
+ + ( ( ( nMed << 3UL ) + ( nMed << 1UL ) + nMed ) >> 5UL );
+ } // if
+
+ return ndist;
+} // RGBDistance
+
+// =======================================================================
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salnativewidgets.cxx b/vcl/aqua/source/gdi/salnativewidgets.cxx
new file mode 100644
index 000000000000..6e206977b5c4
--- /dev/null
+++ b/vcl/aqua/source/gdi/salnativewidgets.cxx
@@ -0,0 +1,1527 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "salconst.h"
+#include "salgdi.h"
+#include "salnativewidgets.h"
+#include "saldata.hxx"
+#include "salframe.h"
+
+#include "vcl/salnativewidgets.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/timer.hxx"
+
+#include "premac.h"
+#include <Carbon/Carbon.h>
+#include "postmac.h"
+
+class AquaBlinker : public Timer
+{
+ AquaSalFrame* mpFrame;
+ Rectangle maInvalidateRect;
+
+ AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect )
+ : mpFrame( pFrame ), maInvalidateRect( rRect )
+ {
+ mpFrame->maBlinkers.push_back( this );
+ }
+
+ public:
+
+ static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 );
+
+ virtual void Timeout()
+ {
+ Stop();
+ if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown )
+ {
+ mpFrame->maBlinkers.remove( this );
+ mpFrame->SendPaintEvent( &maInvalidateRect );
+ }
+ delete this;
+ }
+};
+
+void AquaBlinker::Blink( AquaSalFrame* pFrame, const Rectangle& rRect, int nTimeout )
+{
+ // prevent repeated paints from triggering themselves all the time
+ for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin();
+ it != pFrame->maBlinkers.end(); ++it )
+ {
+ if( (*it)->maInvalidateRect == rRect )
+ return;
+ }
+ AquaBlinker* pNew = new AquaBlinker( pFrame, rRect );
+ pNew->SetTimeout( nTimeout );
+ pNew->Start();
+}
+
+ControlPart ImplgetCounterPart( ControlPart nPart )
+{
+ ControlPart nCounterPart = 0;
+ switch (nPart)
+ {
+ case PART_BUTTON_UP:
+ nCounterPart = PART_BUTTON_DOWN;
+ break;
+ case PART_BUTTON_DOWN:
+ nCounterPart = PART_BUTTON_UP;
+ break;
+ case PART_BUTTON_LEFT:
+ nCounterPart = PART_BUTTON_RIGHT;
+ break;
+ case PART_BUTTON_RIGHT:
+ nCounterPart = PART_BUTTON_LEFT;
+ break;
+ }
+ return nCounterPart;
+}
+
+
+// Helper returns an HIRect
+
+static HIRect ImplGetHIRectFromRectangle(Rectangle aRect)
+{
+ HIRect aHIRect;
+ aHIRect.origin.x = static_cast<float>(aRect.Left());
+ aHIRect.origin.y = static_cast<float>(aRect.Top());
+ aHIRect.size.width = static_cast<float>(aRect.GetWidth());
+ aHIRect.size.height = static_cast<float>(aRect.GetHeight());
+ return aHIRect;
+}
+
+static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue )
+{
+ switch( aButtonValue )
+ {
+ case BUTTONVALUE_ON:
+ return kThemeButtonOn;
+ break;
+
+ case BUTTONVALUE_OFF:
+ return kThemeButtonOff;
+ break;
+
+ case BUTTONVALUE_MIXED:
+ case BUTTONVALUE_DONTKNOW:
+ default:
+ return kThemeButtonMixed;
+ break;
+ }
+}
+
+static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart,
+ const Rectangle& rControlRect, Rectangle& rResultRect )
+{
+ bool bRetVal = true;
+ rResultRect = rControlRect;
+
+ switch( nPart )
+ {
+ case PART_BUTTON_UP:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Top() = rControlRect.Bottom() - 2*BUTTON_HEIGHT;
+ rResultRect.Bottom() = rResultRect.Top() + BUTTON_HEIGHT;
+ break;
+
+ case PART_BUTTON_DOWN:
+ rResultRect.Top() = rControlRect.Bottom() - BUTTON_HEIGHT;
+ break;
+
+ case PART_BUTTON_LEFT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Left() = rControlRect.Right() - 2*BUTTON_WIDTH;
+ rResultRect.Right() = rResultRect.Left() + BUTTON_WIDTH;
+ break;
+
+ case PART_BUTTON_RIGHT:
+ rResultRect.Left() = rControlRect.Right() - BUTTON_WIDTH;
+ break;
+
+ case PART_TRACK_HORZ_AREA:
+ rResultRect.Right() -= BUTTON_WIDTH + 1;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Right() -= BUTTON_WIDTH;
+ else
+ rResultRect.Left() += BUTTON_WIDTH + 1;
+ break;
+
+ case PART_TRACK_VERT_AREA:
+ rResultRect.Bottom() -= BUTTON_HEIGHT + 1;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Bottom() -= BUTTON_HEIGHT;
+ else
+ rResultRect.Top() += BUTTON_HEIGHT + 1;
+ break;
+ case PART_THUMB_HORZ:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ rResultRect.Left() += 8;
+ rResultRect.Right() += 6;
+ }
+ else
+ {
+ rResultRect.Left() += 4;
+ rResultRect.Right() += 4;
+ }
+ break;
+ case PART_THUMB_VERT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ rResultRect.Top() += 8;
+ rResultRect.Bottom() += 8;
+ }
+ else
+ {
+ rResultRect.Top() += 4;
+ rResultRect.Bottom() += 4;
+ }
+ break;
+ case PART_TRACK_HORZ_LEFT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Right() += 8;
+ else
+ rResultRect.Right() += 4;
+ break;
+ case PART_TRACK_HORZ_RIGHT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Left() += 6;
+ else
+ rResultRect.Left() += 4;
+ break;
+ case PART_TRACK_VERT_UPPER:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Bottom() += 8;
+ else
+ rResultRect.Bottom() += 4;
+ break;
+ case PART_TRACK_VERT_LOWER:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Top() += 8;
+ else
+ rResultRect.Top() += 4;
+ break;
+ default:
+ bRetVal = false;
+ }
+
+ return bRetVal;
+}
+
+/*
+ * IsNativeControlSupported()
+ * --------------------------
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart.
+ *
+ */
+BOOL AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ bool bOk = FALSE;
+
+ // Native controls are now defaults
+ // If you want to disable experimental native controls code,
+ // just set the environment variable SAL_NO_NWF to something
+ // and vcl controls will be used as default again.
+
+ switch( nType )
+ {
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ case CTRL_LISTNODE:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+
+ case CTRL_SCROLLBAR:
+ if( nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT ||
+ nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_THREE_BUTTONS )
+ return true;
+ break;
+
+ case CTRL_SLIDER:
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ return true;
+ break;
+
+ case CTRL_EDITBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_MULTILINE_EDITBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_ALL_BUTTONS ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_SPINBUTTONS:
+ return false;
+ break;
+
+ case CTRL_COMBOBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_LISTBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_WINDOW ||
+ nPart == HAS_BACKGROUND_TEXTURE ||
+ nPart == PART_SUB_EDIT
+ )
+ return true;
+ break;
+
+ case CTRL_TAB_ITEM:
+ case CTRL_TAB_PANE:
+ case CTRL_TAB_BODY: // see vcl/source/window/tabpage.cxx
+ case CTRL_FIXEDBORDER:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_TABS_DRAW_RTL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ // when PART_BUTTON is used, toolbar icons are not highlighted when mouse rolls over.
+ // More Aqua compliant
+ case CTRL_TOOLBAR:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT)
+ return true;
+ break;
+
+ case CTRL_WINDOW_BACKGROUND:
+ if ( nPart == PART_BACKGROUND_WINDOW ||
+ nPart == PART_BACKGROUND_DIALOG )
+ return true;
+ break;
+
+ case CTRL_MENUBAR:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+
+ case CTRL_TOOLTIP: // ** TO DO
+ #if 0
+ if( nPart == PART_ENTIRE_CONTROL ) // we don't currently support the tooltip
+ return true;
+ #endif
+ break;
+
+ case CTRL_MENU_POPUP:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_MENU_ITEM ||
+ nPart == PART_MENU_ITEM_CHECK_MARK ||
+ nPart == PART_MENU_ITEM_RADIO_MARK)
+ return true;
+ break;
+ case CTRL_PROGRESS:
+ case CTRL_INTROPROGRESS:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+ case CTRL_FRAME:
+ if( nPart == PART_BORDER )
+ return true;
+ break;
+ case CTRL_LISTNET:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+ }
+
+ return bOk;
+}
+
+/*
+ * HitTestNativeControl()
+ *
+ * If the return value is TRUE, bIsInside contains information whether
+ * aPos was or was not inside the native widget specified by the
+ * nType/nPart combination.
+ */
+BOOL AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ const Point& rPos, BOOL& rIsInside )
+{
+ if ( nType == CTRL_SCROLLBAR )
+ {
+ Rectangle aRect;
+ bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect );
+ rIsInside = bValid ? aRect.IsInside( rPos ) : FALSE;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ // in double max mode the actual trough is a little smaller than the track
+ // there is some visual filler that is not sensitive
+ if( bValid && rIsInside )
+ {
+ if( nPart == PART_TRACK_HORZ_AREA )
+ {
+ // the left 4 pixels are not hit sensitive
+ if( rPos.X() - aRect.Left() < 4 )
+ rIsInside = FALSE;
+ }
+ else if( nPart == PART_TRACK_VERT_AREA )
+ {
+ // the top 4 pixels are not hit sensitive
+ if( rPos.Y() - aRect.Top() < 4 )
+ rIsInside = FALSE;
+ }
+ }
+ }
+ return bValid;
+ } // CTRL_SCROLLBAR
+
+ return FALSE;
+}
+
+/*
+ kThemeStateInactive = 0,
+ kThemeStateActive = 1,
+ kThemeStatePressed = 2,
+ kThemeStateRollover = 6,
+ kThemeStateUnavailable = 7,
+ kThemeStateUnavailableInactive = 8
+ kThemeStatePressedUp = 2,
+ kThemeStatePressedDown = 3
+
+#define CTRL_STATE_ENABLED 0x0001
+#define CTRL_STATE_FOCUSED 0x0002
+#define CTRL_STATE_PRESSED 0x0004
+#define CTRL_STATE_ROLLOVER 0x0008
+#define CTRL_STATE_HIDDEN 0x0010
+#define CTRL_STATE_DEFAULT 0x0020
+#define CTRL_STATE_SELECTED 0x0040
+#define CTRL_CACHING_ALLOWED 0x8000 // set when the control is completely visible (i.e. not clipped)
+*/
+UInt32 AquaSalGraphics::getState( ControlState nState )
+{
+ bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true;
+ if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
+ {
+ if( (nState & CTRL_STATE_HIDDEN) == 0 )
+ return kThemeStateInactive;
+ else
+ return kThemeStateUnavailableInactive;
+ }
+
+ if( (nState & CTRL_STATE_HIDDEN) != 0 )
+ return kThemeStateUnavailable;
+
+ if( (nState & CTRL_STATE_PRESSED) != 0 )
+ return kThemeStatePressed;
+
+ return kThemeStateActive;
+}
+
+UInt32 AquaSalGraphics::getTrackState( ControlState nState )
+{
+ bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true;
+ if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
+ return kThemeTrackInactive;
+
+ return kThemeTrackActive;
+}
+
+/*
+ * DrawNativeControl()
+ *
+ * Draws the requested control described by nPart/nState.
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL AquaSalGraphics::drawNativeControl(ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption )
+{
+ BOOL bOK = FALSE;
+
+ if( ! CheckContext() )
+ return false;
+
+ CGContextSaveGState( mrContext );
+
+ Rectangle buttonRect = rControlRegion;
+ HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
+
+ /** Scrollbar parts code equivalent **
+ PART_BUTTON_UP 101
+ PART_BUTTON_DOWN 102
+ PART_THUMB_VERT 211
+ PART_TRACK_VERT_UPPER 201
+ PART_TRACK_VERT_LOWER 203
+
+ PART_DRAW_BACKGROUND_HORZ 1000
+ PART_DRAW_BACKGROUND_VERT 1001
+ **/
+
+ switch( nType )
+ {
+
+ case CTRL_COMBOBOX:
+ if ( nPart == HAS_BACKGROUND_TEXTURE ||
+ nPart == PART_ENTIRE_CONTROL )
+ {
+ HIThemeButtonDrawInfo aComboInfo;
+ aComboInfo.version = 0;
+ aComboInfo.kind = kThemeComboBox;
+ aComboInfo.state = getState( nState );
+ aComboInfo.value = kThemeButtonOn;
+ aComboInfo.adornment = kThemeAdornmentNone;
+
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aComboInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_FIXEDBORDER:
+ case CTRL_TOOLBAR:
+ {
+ HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
+ aMenuItemDrawInfo.version = 0;
+ aMenuItemDrawInfo.state = kThemeMenuActive;
+ aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
+ HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_WINDOW_BACKGROUND:
+ {
+ HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
+ aThemeBackgroundInfo.version = 0;
+ aThemeBackgroundInfo.state = getState( nState );
+ aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundInactive;
+ // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
+ rc.size.width += 2;
+ rc.size.height += 2;
+
+ HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
+ CGContextFillRect( mrContext, rc );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_MENUBAR:
+ case CTRL_MENU_POPUP:
+ {
+ if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE ))
+ {
+ // FIXME: without this magical offset there is a 2 pixel black border on the right
+ rc.size.width += 2;
+
+ HIThemeMenuDrawInfo aMenuInfo;
+ aMenuInfo.version = 0;
+ aMenuInfo.menuType = kThemeMenuTypePullDown;
+
+ HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
+ // the Aqua grey theme when the item is selected is drawn here.
+ aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
+
+ if ((nPart == PART_MENU_ITEM ) && (nState & CTRL_STATE_SELECTED))
+ {
+ // the blue theme when the item is selected is drawn here.
+ aMenuItemDrawInfo.state = kThemeMenuSelected;
+ }
+ else
+ {
+ // normal color for non selected item
+ aMenuItemDrawInfo.state = kThemeMenuActive;
+ }
+
+ // repaints the background of the pull down menu
+ HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);
+
+ // repaints the item either blue (selected) and/or Aqua grey (active only)
+ HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);
+
+ bOK = true;
+ }
+ else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
+ if( nState & CTRL_STATE_PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
+ HIThemeTextInfo aTextInfo;
+ aTextInfo.version = 0;
+ aTextInfo.state = ((nState & CTRL_STATE_ENABLED)==0) ? kThemeStateInactive: kThemeStateActive;
+ aTextInfo.fontID = kThemeMenuItemMarkFont;
+ aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
+ aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
+ aTextInfo.options=kHIThemeTextBoxOptionNone;
+ aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
+ //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
+
+ if( nState & CTRL_STATE_SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
+
+ UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713;
+ CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
+ HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal);
+ if (cfString)
+ CFRelease(cfString);
+
+ bOK = true;
+ }
+ }
+ }
+ break;
+
+ case CTRL_PUSHBUTTON:
+ {
+ // [ FIXME] : instead of use a value, vcl can retrieve corect values on the fly (to be implemented)
+ const int PB_Mini_Height = 15;
+ const int PB_Norm_Height = 21;
+
+ HIThemeButtonDrawInfo aPushInfo;
+ aPushInfo.version = 0;
+
+ // no animation
+ aPushInfo.animation.time.start = 0;
+ aPushInfo.animation.time.current = 0;
+ PushButtonValue* pPBVal = aValue.getType() == CTRL_PUSHBUTTON ? (PushButtonValue*)&aValue : NULL;
+ int nPaintHeight = static_cast<int>(rc.size.height);
+
+ if( pPBVal && pPBVal->mbBevelButton )
+ {
+ aPushInfo.kind = kThemeRoundedBevelButton;
+ }
+ else if( rc.size.height <= PB_Norm_Height )
+ {
+ aPushInfo.kind = kThemePushButtonMini;
+ nPaintHeight = PB_Mini_Height;
+ }
+ else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
+ {
+ aPushInfo.kind = kThemePushButtonNormal;
+ nPaintHeight = PB_Norm_Height;
+
+ // avoid clipping when focused
+ rc.origin.x += FOCUS_RING_WIDTH/2;
+ rc.size.width -= FOCUS_RING_WIDTH;
+
+ if( (nState & CTRL_STATE_DEFAULT) != 0 )
+ {
+ AquaBlinker::Blink( mpFrame, buttonRect );
+ // show correct animation phase
+ aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ }
+ }
+ else
+ aPushInfo.kind = kThemeBevelButton;
+
+ // translate the origin for controls with fixed paint height
+ // so content ends up somewhere sensible
+ int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
+ rc.origin.y += delta_y/2;
+
+ aPushInfo.state = getState( nState );
+ aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
+
+ aPushInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aPushInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ {
+ HIThemeButtonDrawInfo aInfo;
+ aInfo.version = 0;
+ switch( nType )
+ {
+ case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
+ else aInfo.kind = kThemeSmallRadioButton;
+ break;
+ case CTRL_CHECKBOX: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
+ else aInfo.kind = kThemeSmallCheckBox;
+ break;
+ }
+
+ aInfo.state = getState( nState );
+
+ ButtonValue aButtonValue = aValue.getTristateVal();
+ aInfo.value = ImplGetButtonValue( aButtonValue );
+
+ aInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aInfo.adornment |= kThemeAdornmentFocus;
+ HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_LISTNODE:
+ {
+ ButtonValue aButtonValue = aValue.getTristateVal();
+
+ if( Application::GetSettings().GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF )
+ {
+ // FIXME: a value of kThemeDisclosureLeft
+ // should draw a theme compliant left disclosure triangle
+ // sadly this does not seem to work, so we'll draw a left
+ // grey equilateral triangle here ourselves.
+ // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
+
+ CGContextSetShouldAntialias( mrContext, true );
+ float aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
+ CGContextSetFillColor( mrContext, aGrey );
+ CGContextBeginPath( mrContext );
+ float x = rc.origin.x + rc.size.width;
+ float y = rc.origin.y;
+ CGContextMoveToPoint( mrContext, x, y );
+ y += rc.size.height;
+ CGContextAddLineToPoint( mrContext, x, y );
+ x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
+ y -= rc.size.height/2;
+ CGContextAddLineToPoint( mrContext, x, y );
+ CGContextDrawPath( mrContext, kCGPathEOFill );
+ }
+ else
+ {
+ HIThemeButtonDrawInfo aInfo;
+ aInfo.version = 0;
+ aInfo.kind = kThemeDisclosureTriangle;
+ aInfo.value = kThemeDisclosureRight;
+ aInfo.state = getState( nState );
+
+ aInfo.adornment = kThemeAdornmentNone;
+
+ switch( aButtonValue ) {
+ case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded
+ break;
+ case BUTTONVALUE_OFF:
+ // FIXME: this should have drawn a theme compliant disclosure triangle
+ // (see above)
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
+ }
+ break;
+ case BUTTONVALUE_DONTKNOW: //what to do?
+ default:
+ break;
+ }
+
+ HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ }
+ bOK = true;
+ }
+ break;
+
+ case CTRL_PROGRESS:
+ case CTRL_INTROPROGRESS:
+ {
+ long nProgressWidth = aValue.getNumericVal();
+ HIThemeTrackDrawInfo aTrackInfo;
+ aTrackInfo.version = 0;
+ aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
+ aTrackInfo.bounds = rc;
+ aTrackInfo.min = 0;
+ aTrackInfo.max = static_cast<SInt32>(rc.size.width);
+ aTrackInfo.value = nProgressWidth;
+ aTrackInfo.reserved = 0;
+ aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow
+ aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow
+ aTrackInfo.attributes = kThemeTrackHorizontal;
+ if( Application::GetSettings().GetLayoutRTL() )
+ aTrackInfo.attributes |= kThemeTrackRightToLeft;
+ aTrackInfo.enableState = getTrackState( nState );
+ // the intro bitmap never gets key anyway; we want to draw that enabled
+ if( nType == CTRL_INTROPROGRESS )
+ aTrackInfo.enableState = kThemeTrackActive;
+ aTrackInfo.filler1 = 0;
+ aTrackInfo.trackInfo.progress.phase = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0);
+
+ HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_SLIDER:
+ {
+ SliderValue* pSLVal = (SliderValue*)&aValue;
+
+ HIThemeTrackDrawInfo aTrackDraw;
+ aTrackDraw.kind = kThemeSliderMedium;
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ {
+ aTrackDraw.bounds = rc;
+ aTrackDraw.min = pSLVal->mnMin;
+ aTrackDraw.max = pSLVal->mnMax;;
+ aTrackDraw.value = pSLVal->mnCur;
+ aTrackDraw.reserved = 0;
+ aTrackDraw.attributes = kThemeTrackShowThumb;
+ if( nPart == PART_TRACK_HORZ_AREA )
+ aTrackDraw.attributes |= kThemeTrackHorizontal;
+ aTrackDraw.enableState = (nState & CTRL_STATE_ENABLED)
+ ? kThemeTrackActive : kThemeTrackInactive;
+
+ SliderTrackInfo aSlideInfo;
+ aSlideInfo.thumbDir = kThemeThumbUpward;
+ aSlideInfo.pressState = 0;
+ aTrackDraw.trackInfo.slider = aSlideInfo;
+
+ HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ }
+ break;
+
+ case CTRL_SCROLLBAR:
+ {
+ ScrollbarValue* pScrollbarVal = (ScrollbarValue *)&aValue;
+
+ if( nPart == PART_DRAW_BACKGROUND_VERT ||
+ nPart == PART_DRAW_BACKGROUND_HORZ )
+ {
+ HIThemeTrackDrawInfo aTrackDraw;
+ aTrackDraw.kind = kThemeMediumScrollBar;
+ // FIXME: the scrollbar length must be adjusted
+ if (nPart == PART_DRAW_BACKGROUND_VERT)
+ rc.size.height += 2;
+ else
+ rc.size.width += 2;
+
+ aTrackDraw.bounds = rc;
+ aTrackDraw.min = pScrollbarVal->mnMin;
+ aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
+ aTrackDraw.value = pScrollbarVal->mnCur;
+ aTrackDraw.reserved = 0;
+ aTrackDraw.attributes = kThemeTrackShowThumb;
+ if( nPart == PART_DRAW_BACKGROUND_HORZ )
+ aTrackDraw.attributes |= kThemeTrackHorizontal;
+ aTrackDraw.enableState = getTrackState( nState );
+
+ ScrollBarTrackInfo aScrollInfo;
+ aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
+ aScrollInfo.pressState = 0;
+
+ if ( pScrollbarVal->mnButton1State & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnButton1State & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
+ }
+
+ if ( pScrollbarVal->mnButton2State & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnButton2State & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
+ }
+
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeThumbPressed;
+ }
+
+ aTrackDraw.trackInfo.scrollbar = aScrollInfo;
+
+ HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ }
+ break;
+
+//#define OLD_TAB_STYLE
+#ifdef OLD_TAB_STYLE
+ case CTRL_TAB_PANE:
+ {
+ HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
+ aTabPaneDrawInfo.version = 0;
+ aTabPaneDrawInfo.state = kThemeStateActive;
+ aTabPaneDrawInfo.direction=kThemeTabNorth;
+ aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
+
+ //the border is outside the rect rc for Carbon
+ //but for VCL it should be inside
+ rc.origin.x+=1;
+ rc.size.width-=2;
+
+ HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+ {
+ HIThemeTabDrawInfo aTabItemDrawInfo;
+ aTabItemDrawInfo.version=0;
+ aTabItemDrawInfo.style=kThemeTabNonFront;
+ aTabItemDrawInfo.direction=kThemeTabNorth;
+ aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentNone;
+
+ if(nState & CTRL_STATE_SELECTED) {
+ aTabItemDrawInfo.style=kThemeTabFront;
+ }
+ if(nState & CTRL_STATE_FOCUSED) {
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentFocus;
+ }
+
+ /*if(rc.size.height>=TAB_HEIGHT_NORMAL) rc.size.height=TAB_HEIGHT_NORMAL;
+ else if(rc.size.height>=TAB_HEIGHT_SMALL) rc.size.height=TAB_HEIGHT_SMALL;
+ else rc.size.height=TAB_HEIGHT_MINI;*/
+ //now we only use the default size
+ rc.size.height=TAB_HEIGHT_NORMAL;
+
+ HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
+
+ bOK=true;
+ }
+ break;
+#else
+ case CTRL_TAB_PANE:
+ {
+ HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
+ aTabPaneDrawInfo.version = 1;
+ aTabPaneDrawInfo.state = kThemeStateActive;
+ aTabPaneDrawInfo.direction=kThemeTabNorth;
+ aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
+
+ //the border is outside the rect rc for Carbon
+ //but for VCL it should be inside
+ rc.origin.x+=1;
+ rc.origin.y-=TAB_HEIGHT_NORMAL/2;
+ rc.size.height+=TAB_HEIGHT_NORMAL/2;
+ rc.size.width-=2;
+
+ HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ bOK = true;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+ {
+ HIThemeTabDrawInfo aTabItemDrawInfo;
+ aTabItemDrawInfo.version=1;
+ aTabItemDrawInfo.style=kThemeTabNonFront;
+ aTabItemDrawInfo.direction=kThemeTabNorth;
+ aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
+ //State
+ if(nState & CTRL_STATE_SELECTED) {
+ aTabItemDrawInfo.style=kThemeTabFront;
+ }
+ if(nState & CTRL_STATE_FOCUSED) {
+ aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
+ }
+
+ //first, last or middle tab
+ aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
+
+ TabitemValue* pTabValue = (TabitemValue *) &aValue;
+ unsigned int nAlignment = pTabValue->mnAlignment;
+ //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab
+ //when there are several lines of tabs because there is only one first tab and one
+ //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the
+ //line width is different from window width, there may not be TABITEM_RIGHTALIGNED
+ if( ( (nAlignment & TABITEM_LEFTALIGNED)&&(nAlignment & TABITEM_RIGHTALIGNED) ) ||
+ ( (nAlignment & TABITEM_FIRST_IN_GROUP)&&(nAlignment & TABITEM_LAST_IN_GROUP) )
+ ) //tab alone
+ aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
+ else if((nAlignment & TABITEM_LEFTALIGNED)||(nAlignment & TABITEM_FIRST_IN_GROUP))
+ aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
+ else if((nAlignment & TABITEM_RIGHTALIGNED)||(nAlignment & TABITEM_LAST_IN_GROUP))
+ aTabItemDrawInfo.position=kHIThemeTabPositionLast;
+
+ //support for RTL
+ //see issue 79748
+ if( Application::GetSettings().GetLayoutRTL() ) {
+ if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
+ aTabItemDrawInfo.position = kHIThemeTabPositionLast;
+ else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
+ aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
+ }
+
+ rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
+ rc.origin.x-=1;
+
+ HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
+
+ bOK=true;
+ }
+ break;
+#endif
+
+ case CTRL_LISTBOX:
+ switch( nPart)
+ {
+ case PART_ENTIRE_CONTROL:
+ case PART_BUTTON_DOWN:
+ {
+ HIThemeButtonDrawInfo aListInfo;
+ aListInfo.version = 0;
+ aListInfo.kind = kThemePopupButton;
+ aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
+ aListInfo.value = kThemeButtonOn;
+
+ aListInfo.adornment = kThemeAdornmentDefault;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aListInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
+ bOK = true;
+ break;
+ }
+ case PART_WINDOW:
+ {
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ rc.size.width+=1;//else there's a white space because aqua theme hasn't a 3D border
+ rc.size.height+=1;
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ break;
+ }
+ }
+ break;
+
+ case CTRL_EDITBOX:
+ case CTRL_MULTILINE_EDITBOX:
+ {
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ rc.size.width += 1; // else there may be a white space because aqua theme hasn't a 3D border
+ // change rc so that the frame will encompass only the content region
+ // see counterpart in GetNativeControlRegion
+ rc.size.width += 2;
+ rc.size.height += 2;
+
+ //CGContextSetFillColorWithColor
+ CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ //fill a white background, because drawFrame only draws the border
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ }
+ break;
+
+ case CTRL_SPINBOX:
+ {
+ if(nPart == PART_ENTIRE_CONTROL)
+ {
+ //text field:
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ //rc.size.width contains the full size of the spinbox ie textfield + button
+ //so we remove the button width and the space between the button and the textfield
+ rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
+ rc.origin.x += FOCUS_RING_WIDTH;
+ rc.origin.y += FOCUS_RING_WIDTH;
+
+ //CGContextSetFillColorWithColor
+ CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ //fill a white background, because drawFrame only draws the border
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ //buttons:
+ SpinbuttonValue* pSpinButtonVal = (SpinbuttonValue *)&aValue;
+ ControlState nUpperState = CTRL_STATE_ENABLED;//state of the upper button
+ ControlState nLowerState = CTRL_STATE_ENABLED;//and of the lower button
+ if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
+ nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
+ nLowerState = (ControlState) pSpinButtonVal->mnLowerState;
+ }
+
+ if( pSpinButtonVal )
+ {
+ HIThemeButtonDrawInfo aSpinInfo;
+ aSpinInfo.kind = kThemeIncDecButton;
+ aSpinInfo.state = kThemeStateActive;
+ if(nUpperState & CTRL_STATE_PRESSED)
+ aSpinInfo.state = kThemeStatePressedUp;
+ else if(nLowerState & CTRL_STATE_PRESSED)
+ aSpinInfo.state = kThemeStatePressedDown;
+ else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED))
+ aSpinInfo.state = kThemeStateInactive;
+ else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER))
+ aSpinInfo.state = kThemeStateRollover;
+
+ Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
+ aSpinRect.Union( pSpinButtonVal->maLowerRect );
+ HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
+
+ // FIXME: without this fuzz factor there is some unwanted clipping
+ if( Application::GetSettings().GetLayoutRTL() )
+ buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
+ else
+ buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
+
+ switch( aValue.getTristateVal() )
+ {
+ case BUTTONVALUE_ON: aSpinInfo.value = kThemeButtonOn;
+ break;
+ case BUTTONVALUE_OFF: aSpinInfo.value = kThemeButtonOff;
+ break;
+ case BUTTONVALUE_MIXED:
+ case BUTTONVALUE_DONTKNOW:
+ default: aSpinInfo.value = kThemeButtonMixed;
+ break;
+ }
+
+ aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) ||
+ ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 ))
+ aSpinInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ }
+
+ bOK=true;
+ }
+
+ }
+ break;
+
+ case CTRL_FRAME:
+ {
+ USHORT nStyle = aValue.getNumericVal();
+ if( nPart == PART_BORDER ) {
+ if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) )
+ {
+ // #i84756# strange effects start to happen when HIThemeDrawFrame
+ // meets the border of the window. These can be avoided by clipping
+ // to the boundary of the frame
+ if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
+ {
+ CGMutablePathRef rPath = CGPathCreateMutable();
+ CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
+
+ CGContextBeginPath( mrContext );
+ CGContextAddPath( mrContext, rPath );
+ CGContextClip( mrContext );
+ CGPathRelease( rPath );
+ }
+
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameListBox;
+ aTextDrawInfo.state=kThemeStateActive;
+ aTextDrawInfo.isFocused=false;
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ }
+ }
+ }
+ break;
+
+ case CTRL_LISTNET:
+ {
+ //do nothing as there isn't net for listviews on macos
+ bOK=true;
+ }
+ break;
+
+ }
+
+ CGContextRestoreGState( mrContext );
+
+ /* #i90291# in most cases invalidating the whole control region instead
+ of just the unclipped part of it is sufficient (and probably faster).
+ However for the window background we should not unnecessarily enlarge
+ the really changed rectangle since the difference is usually quite high
+ (the background is always drawn as a whole since we don't know anything
+ about its possible contents)
+ */
+ if( nType == CTRL_WINDOW_BACKGROUND )
+ {
+ CGRect aRect = { { 0, 0 }, { 0, 0 } };
+ if( mxClipPath )
+ aRect = CGPathGetBoundingBox( mxClipPath );
+ if( aRect.size.width != 0 && aRect.size.height != 0 )
+ buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x),
+ static_cast<long int>(aRect.origin.y) ),
+ Size( static_cast<long int>(aRect.size.width),
+ static_cast<long int>(aRect.size.height) ) ) );
+ }
+
+ RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
+
+ return bOK;
+}
+
+/*
+ * DrawNativeControlText()
+ *
+ * OPTIONAL. Draws the requested text for the control described by nPart/nState.
+ * Used if text not drawn by DrawNativeControl().
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL AquaSalGraphics::drawNativeControlText( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption )
+{
+ return( FALSE );
+}
+
+
+/*
+ * GetNativeControlRegion()
+ *
+ * If the return value is TRUE, rNativeBoundingRegion
+ * contains the true bounding region covered by the control
+ * including any adornment, while rNativeContentRegion contains the area
+ * within the control that can be safely drawn into without drawing over
+ * the borders of the control.
+ *
+ * rControlRegion: The bounding region of the control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+BOOL AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& aCaption,
+ Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion )
+
+{
+ BOOL toReturn = FALSE;
+
+ Rectangle aCtrlBoundRect( rControlRegion );
+ short x = aCtrlBoundRect.Left();
+ short y = aCtrlBoundRect.Top();
+ short w, h;
+
+ sal_uInt8 nBorderCleanup = 0;
+
+ switch (nType)
+ {
+ case CTRL_SLIDER:
+ {
+ if( nPart == PART_THUMB_HORZ )
+ {
+ w = 19; // taken from HIG
+ h = aCtrlBoundRect.GetHeight();
+ rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ toReturn = true;
+ }
+ else if( nPart == PART_THUMB_VERT )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = 18; // taken from HIG
+ rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ toReturn = true;
+ }
+ }
+ break;
+
+ case CTRL_SCROLLBAR:
+ {
+ Rectangle aRect;
+ if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) )
+ {
+ toReturn = TRUE;
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ }
+ }
+ break;
+
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ {
+ if ( nType == CTRL_PUSHBUTTON )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = aCtrlBoundRect.GetHeight();
+ }
+ else
+ {
+ // checkbox and radio borders need cleanup after unchecking them
+ nBorderCleanup = 4;
+
+ // TEXT_SEPARATOR to respect Aqua HIG
+ w = BUTTON_WIDTH + TEXT_SEPARATOR;
+ h = BUTTON_HEIGHT;
+
+ }
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_PROGRESS:
+ {
+ Rectangle aRect( aCtrlBoundRect );
+ if( aRect.GetHeight() < 16 )
+ aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress
+ else
+ aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ toReturn = TRUE;
+ }
+ break;
+
+ case CTRL_INTROPROGRESS:
+ {
+ Rectangle aRect( aCtrlBoundRect );
+ aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ toReturn = TRUE;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+
+ w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
+
+#ifdef OLD_TAB_STYLE
+ h = TAB_HEIGHT_NORMAL;
+#else
+ h = TAB_HEIGHT_NORMAL+2;
+#endif
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+
+ break;
+
+ case CTRL_EDITBOX:
+ {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH-2, h-2 ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_LISTBOX:
+ case CTRL_COMBOBOX:
+ {
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_DOWN )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH;
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
+ y += FOCUS_RING_WIDTH;
+ w = DROPDOWN_BUTTON_WIDTH;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = true;
+ }
+ else if( nPart == PART_SUB_EDIT )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ x += FOCUS_RING_WIDTH;
+ x += 3; // add an offset for rounded borders
+ y += 2; // don't draw into upper border
+ y += FOCUS_RING_WIDTH;
+ w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
+ if( nType == CTRL_LISTBOX )
+ w -= 9; // HIG specifies 9 units distance between dropdown button area and content
+ h -= 4; // don't draw into lower border
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = true;
+ }
+ }
+ break;
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL ) {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_SUB_EDIT ) {
+ w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+ x += 4; // add an offset for rounded borders
+ y += 2; // don't draw into upper border
+ w -= 8; // offset for left and right rounded border
+ h -= 4; // don't draw into upper or ower border
+
+ rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_UP ) {
+ //aCtrlBoundRect.GetWidth() contains the width of the full control
+ //ie the width of the textfield + button
+ //x is the position of the left corner of the full control
+ x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
+ y += FOCUS_RING_WIDTH - CLIP_FUZZ;
+ w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
+ h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_DOWN ) {
+ x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
+ y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
+ w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
+ h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_FRAME:
+ {
+ USHORT nStyle = aValue.getNumericVal();
+ if( ( nPart == PART_BORDER ) &&
+ !( nStyle & (FRAME_DRAW_MENU | FRAME_DRAW_WINDOWBORDER | FRAME_DRAW_BORDERWINDOWBORDER) ) )
+ {
+ Rectangle aRect(aCtrlBoundRect);
+ if( nStyle & FRAME_DRAW_DOUBLEIN )
+ {
+ aRect.Left() += 1;
+ aRect.Top() += 1;
+ //rRect.Right() -= 1;
+ //rRect.Bottom() -= 1;
+ }
+ else
+ {
+ aRect.Left() += 1;
+ aRect.Top() += 1;
+ aRect.Right() -= 1;
+ aRect.Bottom() -= 1;
+ }
+
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = aRect;
+
+ toReturn = TRUE;
+ }
+ }
+ break;
+
+ case CTRL_MENUBAR:
+ case CTRL_MENU_POPUP:
+ {
+ if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
+
+ w=10;
+ h=10;//dimensions of the mark (10px font)
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ }
+ break;
+
+ }
+
+ return toReturn;
+}
diff --git a/vcl/aqua/source/gdi/salprn.cxx b/vcl/aqua/source/gdi/salprn.cxx
new file mode 100644
index 000000000000..1c0401f769b5
--- /dev/null
+++ b/vcl/aqua/source/gdi/salprn.cxx
@@ -0,0 +1,875 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "salprn.h"
+#include "aquaprintview.h"
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "vcl/jobset.h"
+#include "vcl/salptype.hxx"
+#include "vcl/print.hxx"
+#include "vcl/unohelp.hxx"
+
+#include <boost/bind.hpp>
+
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/container/XNameAccess.hpp"
+#include "com/sun/star/beans/PropertyValue.hpp"
+#include "com/sun/star/awt/Size.hpp"
+
+#include <algorithm>
+
+using namespace rtl;
+using namespace vcl;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+// =======================================================================
+
+AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo& i_rQueue ) :
+ mpGraphics( 0 ),
+ mbGraphics( false ),
+ mbJob( false ),
+ mpPrinter( nil ),
+ mpPrintInfo( nil ),
+ mePageOrientation( ORIENTATION_PORTRAIT ),
+ mnStartPageOffsetX( 0 ),
+ mnStartPageOffsetY( 0 ),
+ mnCurPageRangeStart( 0 ),
+ mnCurPageRangeCount( 0 )
+{
+ NSString* pStr = CreateNSString( i_rQueue.maPrinterName );
+ mpPrinter = [NSPrinter printerWithName: pStr];
+ [pStr release];
+
+ NSPrintInfo* pShared = [NSPrintInfo sharedPrintInfo];
+ if( pShared )
+ {
+ mpPrintInfo = [pShared copy];
+ [mpPrintInfo setPrinter: mpPrinter];
+ mePageOrientation = ([mpPrintInfo orientation] == NSLandscapeOrientation) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ [mpPrintInfo setOrientation: NSPortraitOrientation];
+ }
+
+ mpGraphics = new AquaSalGraphics();
+
+ const int nWidth = 100, nHeight = 100;
+ maContextMemory.reset( reinterpret_cast<sal_uInt8*>( rtl_allocateMemory( nWidth * 4 * nHeight ) ),
+ boost::bind( rtl_freeMemory, _1 ) );
+
+ if( maContextMemory )
+ {
+ mrContext = CGBitmapContextCreate( maContextMemory.get(), nWidth, nHeight, 8, nWidth * 4, GetSalData()->mxRGBSpace, kCGImageAlphaNoneSkipFirst );
+ if( mrContext )
+ SetupPrinterGraphics( mrContext );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalInfoPrinter::~AquaSalInfoPrinter()
+{
+ delete mpGraphics;
+ if( mpPrintInfo )
+ [mpPrintInfo release];
+ #if 0
+ // FIXME: verify that NSPrintInfo releases the printer
+ // else we have a leak here
+ if( mpPrinter )
+ [mpPrinter release];
+ #endif
+ if( mrContext )
+ CFRelease( mrContext );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::SetupPrinterGraphics( CGContextRef i_rContext ) const
+{
+ if( mpGraphics )
+ {
+ if( mpPrintInfo )
+ {
+ // FIXME: get printer resolution
+ long nDPIX = 720, nDPIY = 720;
+ NSSize aPaperSize = [mpPrintInfo paperSize];
+
+ NSRect aImageRect = [mpPrintInfo imageablePageBounds];
+ if( mePageOrientation == ORIENTATION_PORTRAIT )
+ {
+ // move mirrored CTM back into paper
+ double dX = 0, dY = aPaperSize.height;
+ // move CTM to reflect imageable area
+ dX += aImageRect.origin.x;
+ dY -= aPaperSize.height - aImageRect.size.height - aImageRect.origin.y;
+ CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetX, dY - mnStartPageOffsetY );
+ // scale to be top/down and reflect our "virtual" DPI
+ CGContextScaleCTM( i_rContext, 72.0/double(nDPIX), -(72.0/double(nDPIY)) );
+ }
+ else
+ {
+ // move CTM to reflect imageable area
+ double dX = aImageRect.origin.x, dY = aPaperSize.height - aImageRect.size.height - aImageRect.origin.y;
+ CGContextTranslateCTM( i_rContext, -dX, -dY );
+ // turn by 90 degree
+ CGContextRotateCTM( i_rContext, M_PI/2 );
+ // move turned CTM back into paper
+ dX = aPaperSize.height;
+ dY = -aPaperSize.width;
+ CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetY, dY - mnStartPageOffsetX );
+ // scale to be top/down and reflect our "virtual" DPI
+ CGContextScaleCTM( i_rContext, -(72.0/double(nDPIY)), (72.0/double(nDPIX)) );
+ }
+ mpGraphics->SetPrinterGraphics( i_rContext, nDPIX, nDPIY, 1.0 );
+ }
+ else
+ DBG_ERROR( "no print info in SetupPrinterGraphics" );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalInfoPrinter::GetGraphics()
+{
+ SalGraphics* pGraphics = mbGraphics ? NULL : mpGraphics;
+ mbGraphics = true;
+ return pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = false;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::Setup( SalFrame* i_pFrame, ImplJobSetup* i_pSetupData )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static struct PaperSizeEntry
+{
+ double fWidth;
+ double fHeight;
+ Paper nPaper;
+} aPaperSizes[] =
+{
+ { 842, 1191, PAPER_A3 },
+ { 595, 842, PAPER_A4 },
+ { 420, 595, PAPER_A5 },
+ { 612, 792, PAPER_LETTER },
+ { 612, 1008, PAPER_LEGAL },
+ { 728, 1032, PAPER_B4_JIS },
+ { 516, 729, PAPER_B5_JIS },
+ { 792, 1224, PAPER_TABLOID }
+};
+
+static bool getPaperSize( double& o_fWidth, double& o_fHeight, const Paper i_ePaper )
+{
+ for(unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ )
+ {
+ if( aPaperSizes[i].nPaper == i_ePaper )
+ {
+ o_fWidth = aPaperSizes[i].fWidth;
+ o_fHeight = aPaperSizes[i].fHeight;
+ return true;
+ }
+ }
+ return false;
+}
+
+static Paper recognizePaper( double i_fWidth, double i_fHeight )
+{
+ Paper aPaper = PAPER_USER;
+ sal_uInt64 nPaperDesc = 1000000*sal_uInt64(i_fWidth) + sal_uInt64(i_fHeight);
+ switch( nPaperDesc )
+ {
+ case 842001191: aPaper = PAPER_A3; break;
+ case 595000842: aPaper = PAPER_A4; break;
+ case 420000595: aPaper = PAPER_A5; break;
+ case 612000792: aPaper = PAPER_LETTER; break;
+ case 728001032: aPaper = PAPER_B4_JIS; break;
+ case 516000729: aPaper = PAPER_B5_JIS; break;
+ case 612001008: aPaper = PAPER_LEGAL; break;
+ case 792001224: aPaper = PAPER_TABLOID; break;
+ default:
+ aPaper = PAPER_USER;
+ break;
+ }
+
+ if( aPaper == PAPER_USER )
+ {
+ // search with fuzz factor
+ for( unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ )
+ {
+ double w = (i_fWidth > aPaperSizes[i].fWidth) ? i_fWidth - aPaperSizes[i].fWidth : aPaperSizes[i].fWidth - i_fWidth;
+ double h = (i_fHeight > aPaperSizes[i].fHeight) ? i_fHeight - aPaperSizes[i].fHeight : aPaperSizes[i].fHeight - i_fHeight;
+ if( w < 3 && h < 3 )
+ {
+ aPaper = aPaperSizes[i].nPaper;
+ break;
+ }
+ }
+ }
+
+ return aPaper;
+}
+
+BOOL AquaSalInfoPrinter::SetPrinterData( ImplJobSetup* io_pSetupData )
+{
+ // FIXME: implement driver data
+ if( io_pSetupData && io_pSetupData->mpDriverData )
+ return SetData( ~0, io_pSetupData );
+
+
+ BOOL bSuccess = TRUE;
+
+ // set system type
+ io_pSetupData->mnSystem = JOBSETUP_SYSTEM_MAC;
+
+ // get paper format
+ if( mpPrintInfo )
+ {
+ NSSize aPaperSize = [mpPrintInfo paperSize];
+ double width = aPaperSize.width, height = aPaperSize.height;
+ // set paper
+ io_pSetupData->mePaperFormat = recognizePaper( width, height );
+ if( io_pSetupData->mePaperFormat == PAPER_USER )
+ {
+ io_pSetupData->mnPaperWidth = PtTo10Mu( width );
+ io_pSetupData->mnPaperHeight = PtTo10Mu( height );
+ }
+ else
+ {
+ io_pSetupData->mnPaperWidth = 0;
+ io_pSetupData->mnPaperHeight = 0;
+ }
+
+ // set orientation
+ io_pSetupData->meOrientation = mePageOrientation;
+
+ io_pSetupData->mnPaperBin = 0;
+ io_pSetupData->mpDriverData = reinterpret_cast<BYTE*>(rtl_allocateMemory( 4 ));
+ io_pSetupData->mnDriverDataLen = 4;
+ }
+ else
+ bSuccess = FALSE;
+
+
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation )
+{
+
+ Orientation ePaperOrientation = ORIENTATION_PORTRAIT;
+ const PaperInfo* pPaper = matchPaper( i_nWidth, i_nHeight, ePaperOrientation );
+
+ if( pPaper )
+ {
+ NSString* pPaperName = [CreateNSString( rtl::OStringToOUString(PaperInfo::toPSName(pPaper->getPaper()), RTL_TEXTENCODING_ASCII_US) ) autorelease];
+ [mpPrintInfo setPaperName: pPaperName];
+ }
+ else if( i_nWidth > 0 && i_nHeight > 0 )
+ {
+ NSSize aPaperSize = { TenMuToPt(i_nWidth), TenMuToPt(i_nHeight) };
+ [mpPrintInfo setPaperSize: aPaperSize];
+ }
+ // this seems counterintuitive
+ mePageOrientation = i_eSetOrientation;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::SetData( ULONG i_nFlags, ImplJobSetup* io_pSetupData )
+{
+ if( ! io_pSetupData || io_pSetupData->mnSystem != JOBSETUP_SYSTEM_MAC )
+ return FALSE;
+
+
+ if( mpPrintInfo )
+ {
+ if( (i_nFlags & SAL_JOBSET_ORIENTATION) != 0 )
+ mePageOrientation = io_pSetupData->meOrientation;
+
+ if( (i_nFlags & SAL_JOBSET_PAPERSIZE) != 0)
+ {
+ // set paper format
+ long width = 21000, height = 29700;
+ if( io_pSetupData->mePaperFormat == PAPER_USER )
+ {
+ // #i101108# sanity check
+ if( io_pSetupData->mnPaperWidth && io_pSetupData->mnPaperHeight )
+ {
+ width = io_pSetupData->mnPaperWidth;
+ height = io_pSetupData->mnPaperHeight;
+ }
+ }
+ else
+ {
+ double w = 595, h = 842;
+ getPaperSize( w, h, io_pSetupData->mePaperFormat );
+ width = static_cast<long>(PtTo10Mu( w ));
+ height = static_cast<long>(PtTo10Mu( h ));
+ }
+
+ setPaperSize( width, height, mePageOrientation );
+ }
+ }
+
+ return mpPrintInfo != nil;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* i_pSetupData )
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalInfoPrinter::GetPaperBinName( const ImplJobSetup* i_pSetupData, ULONG i_nPaperBin )
+{
+ return XubString();
+}
+
+// -----------------------------------------------------------------------
+
+static bool getUseNativeDialog()
+{
+ bool bNative = true;
+ try
+ {
+ // get service provider
+ Reference< XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
+ // create configuration hierachical access name
+ if( xSMgr.is() )
+ {
+ try
+ {
+ Reference< XMultiServiceFactory > xConfigProvider(
+ Reference< XMultiServiceFactory >(
+ xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.configuration.ConfigurationProvider" ))),
+ UNO_QUERY )
+ );
+ if( xConfigProvider.is() )
+ {
+ Sequence< Any > aArgs(1);
+ PropertyValue aVal;
+ aVal.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
+ aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) );
+ aArgs.getArray()[0] <<= aVal;
+ Reference< XNameAccess > xConfigAccess(
+ Reference< XNameAccess >(
+ xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.configuration.ConfigurationAccess" )),
+ aArgs ),
+ UNO_QUERY )
+ );
+ if( xConfigAccess.is() )
+ {
+ try
+ {
+ sal_Bool bValue = sal_False;
+ Any aAny = xConfigAccess->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseSystemPrintDialog" ) ) );
+ if( aAny >>= bValue )
+ bNative = bValue;
+ }
+ catch( NoSuchElementException& )
+ {
+ }
+ catch( WrappedTargetException& )
+ {
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ }
+ catch( WrappedTargetException& )
+ {
+ }
+
+ return bNative;
+}
+
+ULONG AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup* i_pSetupData, USHORT i_nType )
+{
+ switch( i_nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return 0;
+ case PRINTER_CAPABILITIES_COPIES:
+ return 0xffff;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ return 0;
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ return 1;
+ case PRINTER_CAPABILITIES_SETDUPLEX:
+ return 0;
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ return 0;
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPER:
+ return 1;
+ case PRINTER_CAPABILITIES_EXTERNALDIALOG:
+ return getUseNativeDialog() ? 1 : 0;
+ case PRINTER_CAPABILITIES_PDF:
+ return 1;
+ default: break;
+ };
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
+ long& o_rOutWidth, long& o_rOutHeight,
+ long& o_rPageOffX, long& o_rPageOffY,
+ long& o_rPageWidth, long& o_rPageHeight )
+{
+ if( mpPrintInfo )
+ {
+ long nDPIX = 72, nDPIY = 72;
+ mpGraphics->GetResolution( nDPIX, nDPIY );
+ const double fXScaling = static_cast<double>(nDPIX)/72.0,
+ fYScaling = static_cast<double>(nDPIY)/72.0;
+
+ NSSize aPaperSize = [mpPrintInfo paperSize];
+ o_rPageWidth = static_cast<long>( double(aPaperSize.width) * fXScaling );
+ o_rPageHeight = static_cast<long>( double(aPaperSize.height) * fYScaling );
+
+ NSRect aImageRect = [mpPrintInfo imageablePageBounds];
+ o_rPageOffX = static_cast<long>( aImageRect.origin.x * fXScaling );
+ o_rPageOffY = static_cast<long>( (aPaperSize.height - aImageRect.size.height - aImageRect.origin.y) * fYScaling );
+ o_rOutWidth = static_cast<long>( aImageRect.size.width * fXScaling );
+ o_rOutHeight = static_cast<long>( aImageRect.size.height * fYScaling );
+
+ if( mePageOrientation == ORIENTATION_LANDSCAPE )
+ {
+ std::swap( o_rOutWidth, o_rOutHeight );
+ std::swap( o_rPageWidth, o_rPageHeight );
+ std::swap( o_rPageOffX, o_rPageOffY );
+ }
+ }
+}
+
+static Size getPageSize( vcl::PrinterController& i_rController, sal_Int32 i_nPage )
+{
+ Size aPageSize;
+ Sequence< PropertyValue > aPageParms( i_rController.getPageParameters( i_nPage ) );
+ for( sal_Int32 nProperty = 0, nPropertyCount = aPageParms.getLength(); nProperty < nPropertyCount; ++nProperty )
+ {
+ if( aPageParms[ nProperty ].Name.equalsAscii( "PageSize" ) )
+ {
+ awt::Size aSize;
+ aPageParms[ nProperty].Value >>= aSize;
+ aPageSize.Width() = aSize.Width;
+ aPageSize.Height() = aSize.Height;
+ break;
+ }
+ }
+ return aPageSize;
+}
+
+BOOL AquaSalInfoPrinter::StartJob( const String* i_pFileName,
+ const String& i_rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rController
+ )
+{
+ if( mbJob )
+ return FALSE;
+
+ BOOL bSuccess = FALSE;
+ bool bWasAborted = false;
+ AquaSalInstance* pInst = GetSalData()->mpFirstInstance;
+ PrintAccessoryViewState aAccViewState;
+ sal_Int32 nAllPages = 0;
+
+ // reset IsLastPage
+ i_rController.setLastPage( sal_False );
+
+ // update job data
+ if( i_pSetupData )
+ SetData( ~0, i_pSetupData );
+
+ // do we want a progress panel ?
+ sal_Bool bShowProgressPanel = sal_True;
+ beans::PropertyValue* pMonitor = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) );
+ if( pMonitor )
+ pMonitor->Value >>= bShowProgressPanel;
+ if( ! i_rController.isShowDialogs() )
+ bShowProgressPanel = sal_False;
+
+ // possibly create one job for collated output
+ sal_Bool bSinglePrintJobs = sal_False;
+ beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
+ if( pSingleValue )
+ {
+ pSingleValue->Value >>= bSinglePrintJobs;
+ }
+
+ // FIXME: jobStarted() should be done after the print dialog has ended (if there is one)
+ // how do I know when that might be ?
+ i_rController.jobStarted();
+
+
+ int nCopies = i_rController.getPrinter()->GetCopyCount();
+ int nJobs = 1;
+ if( bSinglePrintJobs )
+ {
+ nJobs = nCopies;
+ nCopies = 1;
+ }
+
+ for( int nCurJob = 0; nCurJob < nJobs; nCurJob++ )
+ {
+ aAccViewState.bNeedRestart = true;
+ do
+ {
+ if( aAccViewState.bNeedRestart )
+ {
+ mnCurPageRangeStart = 0;
+ mnCurPageRangeCount = 0;
+ nAllPages = i_rController.getFilteredPageCount();
+ }
+
+ aAccViewState.bNeedRestart = false;
+
+ Size aCurSize( 21000, 29700 );
+ if( nAllPages > 0 )
+ {
+ mnCurPageRangeCount = 1;
+ aCurSize = getPageSize( i_rController, mnCurPageRangeStart );
+ Size aNextSize( aCurSize );
+
+ // print pages up to a different size
+ while( mnCurPageRangeCount + mnCurPageRangeStart < nAllPages )
+ {
+ aNextSize = getPageSize( i_rController, mnCurPageRangeStart + mnCurPageRangeCount );
+ if( aCurSize == aNextSize // same page size
+ ||
+ (aCurSize.Width() == aNextSize.Height() && aCurSize.Height() == aNextSize.Width()) // same size, but different orientation
+ )
+ {
+ mnCurPageRangeCount++;
+ }
+ else
+ break;
+ }
+ }
+ else
+ mnCurPageRangeCount = 0;
+
+ // now for the current run
+ mnStartPageOffsetX = mnStartPageOffsetY = 0;
+ // setup the paper size and orientation
+ // do this on our associated Printer object, since that is
+ // out interface to the applications which occasionally rely on the paper
+ // information (e.g. brochure printing scales to the found paper size)
+ // also SetPaperSizeUser has the advantage that we can share a
+ // platform independent paper matching algorithm
+ boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
+ pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
+ pPrinter->SetPaperSizeUser( aCurSize, true );
+
+ // create view
+ NSView* pPrintView = [[AquaPrintView alloc] initWithController: &i_rController withInfoPrinter: this];
+
+ NSMutableDictionary* pPrintDict = [mpPrintInfo dictionary];
+
+ // set filename
+ if( i_pFileName )
+ {
+ [mpPrintInfo setJobDisposition: NSPrintSaveJob];
+ NSString* pPath = CreateNSString( *i_pFileName );
+ [pPrintDict setObject: pPath forKey: NSPrintSavePath];
+ [pPath release];
+ }
+
+ [pPrintDict setObject: [[NSNumber numberWithInt: nCopies] autorelease] forKey: NSPrintCopies];
+ [pPrintDict setObject: [[NSNumber numberWithBool: YES] autorelease] forKey: NSPrintDetailedErrorReporting];
+ [pPrintDict setObject: [[NSNumber numberWithInt: 1] autorelease] forKey: NSPrintFirstPage];
+ // #i103253# weird: for some reason, autoreleasing the value below like the others above
+ // leads do a double free malloc error. Why this value should behave differently from all the others
+ // is a mystery.
+ [pPrintDict setObject: [NSNumber numberWithInt: mnCurPageRangeCount] forKey: NSPrintLastPage];
+
+
+ // create print operation
+ NSPrintOperation* pPrintOperation = [NSPrintOperation printOperationWithView: pPrintView printInfo: mpPrintInfo];
+
+ if( pPrintOperation )
+ {
+ NSObject* pReleaseAfterUse = nil;
+ bool bShowPanel = (! i_rController.isDirectPrint() && getUseNativeDialog() && i_rController.isShowDialogs() );
+ [pPrintOperation setShowsPrintPanel: bShowPanel ? YES : NO ];
+ [pPrintOperation setShowsProgressPanel: bShowProgressPanel ? YES : NO];
+
+ // set job title (since MacOSX 10.5)
+ if( [pPrintOperation respondsToSelector: @selector(setJobTitle:)] )
+ [pPrintOperation performSelector: @selector(setJobTitle:) withObject: [CreateNSString( i_rJobName ) autorelease]];
+
+ if( bShowPanel && mnCurPageRangeStart == 0 && nCurJob == 0) // only the first range of pages (in the first job) gets the accesory view
+ pReleaseAfterUse = [AquaPrintAccessoryView setupPrinterPanel: pPrintOperation withController: &i_rController withState: &aAccViewState];
+
+ bSuccess = TRUE;
+ mbJob = true;
+ pInst->startedPrintJob();
+ [pPrintOperation runOperation];
+ pInst->endedPrintJob();
+ bWasAborted = [[[pPrintOperation printInfo] jobDisposition] compare: NSPrintCancelJob] == NSOrderedSame;
+ mbJob = false;
+ if( pReleaseAfterUse )
+ [pReleaseAfterUse release];
+ }
+
+ mnCurPageRangeStart += mnCurPageRangeCount;
+ mnCurPageRangeCount = 1;
+ } while( aAccViewState.bNeedRestart || mnCurPageRangeStart + mnCurPageRangeCount < nAllPages );
+ }
+
+ // inform application that it can release its data
+ // this is awkward, but the XRenderable interface has no method for this,
+ // so we need to call XRenderadble::render one last time with IsLastPage = TRUE
+ i_rController.setLastPage( sal_True );
+ GDIMetaFile aPageFile;
+ if( mrContext )
+ SetupPrinterGraphics( mrContext );
+ i_rController.getFilteredPageFile( 0, aPageFile );
+
+ i_rController.setJobState( bWasAborted
+ ? view::PrintableState_JOB_ABORTED
+ : view::PrintableState_JOB_SPOOLED );
+
+ mnCurPageRangeStart = mnCurPageRangeCount = 0;
+
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::EndJob()
+{
+ mnStartPageOffsetX = mnStartPageOffsetY = 0;
+ mbJob = false;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::AbortJob()
+{
+ mbJob = false;
+
+ // FIXME: implementation
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalInfoPrinter::StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData )
+{
+ if( i_bNewJobData && i_pSetupData )
+ SetPrinterData( i_pSetupData );
+
+ CGContextRef rContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
+
+ SetupPrinterGraphics( rContext );
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::EndPage()
+{
+ mpGraphics->InvalidateContext();
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalInfoPrinter::GetErrorCode() const
+{
+ return 0;
+}
+
+// =======================================================================
+
+AquaSalPrinter::AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter ) :
+ mpInfoPrinter( i_pInfoPrinter )
+{
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalPrinter::~AquaSalPrinter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::StartJob( const String* i_pFileName,
+ const String& i_rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rController )
+{
+ return mpInfoPrinter->StartJob( i_pFileName, i_rJobName, i_rAppName, i_pSetupData, i_rController );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::StartJob( const XubString* i_pFileName,
+ const XubString& i_rJobName,
+ const XubString& i_rAppName,
+ ULONG i_nCopies,
+ bool i_bCollate,
+ bool i_bDirect,
+ ImplJobSetup* i_pSetupData )
+{
+ DBG_ERROR( "should never be called" );
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::EndJob()
+{
+ return mpInfoPrinter->EndJob();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::AbortJob()
+{
+ return mpInfoPrinter->AbortJob();
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalPrinter::StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData )
+{
+ return mpInfoPrinter->StartPage( i_pSetupData, i_bNewJobData );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::EndPage()
+{
+ return mpInfoPrinter->EndPage();
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalPrinter::GetErrorCode()
+{
+ return mpInfoPrinter->GetErrorCode();
+}
+
+void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* i_pSetupData )
+{
+ m_aPaperFormats.clear();
+ m_bPapersInit = true;
+
+ if( mpPrinter )
+ {
+ if( [mpPrinter statusForTable: @"PPD"] == NSPrinterTableOK )
+ {
+ NSArray* pPaperNames = [mpPrinter stringListForKey: @"PageSize" inTable: @"PPD"];
+ if( pPaperNames )
+ {
+ unsigned int nPapers = [pPaperNames count];
+ for( unsigned int i = 0; i < nPapers; i++ )
+ {
+ NSString* pPaper = [pPaperNames objectAtIndex: i];
+ NSSize aPaperSize = [mpPrinter pageSizeForPaper: pPaper];
+ if( aPaperSize.width > 0 && aPaperSize.height > 0 )
+ {
+ PaperInfo aInfo( PtTo10Mu( aPaperSize.width ),
+ PtTo10Mu( aPaperSize.height ) );
+ m_aPaperFormats.push_back( aInfo );
+ }
+ }
+ }
+ }
+ }
+}
+
+const PaperInfo* AquaSalInfoPrinter::matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const
+{
+ if( ! m_bPapersInit )
+ const_cast<AquaSalInfoPrinter*>(this)->InitPaperFormats( NULL );
+
+ const PaperInfo* pMatch = NULL;
+ o_rOrientation = ORIENTATION_PORTRAIT;
+ for( int n = 0; n < 2 ; n++ )
+ {
+ for( size_t i = 0; i < m_aPaperFormats.size(); i++ )
+ {
+ if( abs( m_aPaperFormats[i].getWidth() - i_nWidth ) < 50 &&
+ abs( m_aPaperFormats[i].getHeight() - i_nHeight ) < 50 )
+ {
+ pMatch = &m_aPaperFormats[i];
+ return pMatch;
+ }
+ }
+ o_rOrientation = ORIENTATION_LANDSCAPE;
+ std::swap( i_nWidth, i_nHeight );
+ }
+ return pMatch;
+}
+
+int AquaSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* i_pSetupData )
+{
+ return 900;
+}
+
+
diff --git a/vcl/aqua/source/gdi/salvd.cxx b/vcl/aqua/source/gdi/salvd.cxx
new file mode 100644
index 000000000000..eb09a44f5edd
--- /dev/null
+++ b/vcl/aqua/source/gdi/salvd.cxx
@@ -0,0 +1,236 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salvd.h"
+#include "salinst.h"
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "salframe.h"
+
+#include "vcl/sysdata.hxx"
+
+// -----------------------------------------------------------------------
+
+SalVirtualDevice* AquaSalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData )
+{
+ // #i92075# can be called first in a thread
+ SalData::ensureThreadAutoreleasePool();
+
+ return new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >( pGraphics ), nDX, nDY, nBitCount, pData );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// =======================================================================
+
+AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData )
+: mbGraphicsUsed( false )
+, mxBitmapContext( NULL )
+, mnBitmapDepth( 0 )
+, mxLayer( NULL )
+{
+ if( pGraphic && pData && pData->rCGContext )
+ {
+ // Create virtual device based on existing SystemGraphicsData
+ // We ignore nDx and nDY, as the desired size comes from the SystemGraphicsData
+ mbForeignContext = true; // the mxContext is from pData
+ mpGraphics = new AquaSalGraphics( /*pGraphic*/ );
+ mpGraphics->SetVirDevGraphics( mxLayer, pData->rCGContext );
+ }
+ else
+ {
+ // create empty new virtual device
+ mbForeignContext = false; // the mxContext is created within VCL
+ mpGraphics = new AquaSalGraphics(); // never fails
+ mnBitmapDepth = nBitCount;
+
+ // inherit resolution from reference device
+ if( pGraphic )
+ {
+ AquaSalFrame* pFrame = pGraphic->getGraphicsFrame();
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) )
+ {
+ mpGraphics->setGraphicsFrame( pFrame );
+ mpGraphics->copyResolution( *pGraphic );
+ }
+ }
+
+ if( nDX && nDY )
+ SetSize( nDX, nDY );
+
+ // NOTE: if SetSize does not succeed, we just ignore the nDX and nDY
+ }
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalVirtualDevice::~AquaSalVirtualDevice()
+{
+ if( mpGraphics )
+ {
+ mpGraphics->SetVirDevGraphics( NULL, NULL );
+ delete mpGraphics;
+ mpGraphics = 0;
+ }
+ Destroy();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalVirtualDevice::Destroy()
+{
+ if( mbForeignContext ) {
+ // Do not delete mxContext that we have received from outside VCL
+ mxLayer = NULL;
+ return;
+ }
+
+ if( mxLayer )
+ {
+ if( mpGraphics )
+ mpGraphics->SetVirDevGraphics( NULL, NULL );
+ CGLayerRelease( mxLayer );
+ mxLayer = NULL;
+ }
+
+ if( mxBitmapContext )
+ {
+ void* pRawData = CGBitmapContextGetData( mxBitmapContext );
+ rtl_freeMemory( pRawData );
+ CGContextRelease( mxBitmapContext );
+ mxBitmapContext = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalVirtualDevice::GetGraphics()
+{
+ if( mbGraphicsUsed || !mpGraphics )
+ return 0;
+
+ mbGraphicsUsed = true;
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ mbGraphicsUsed = false;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ if( mbForeignContext )
+ {
+ // Do not delete/resize mxContext that we have received from outside VCL
+ return true;
+ }
+
+ if( mxLayer )
+ {
+ const CGSize aSize = CGLayerGetSize( mxLayer );
+ if( (nDX == aSize.width) && (nDY == aSize.height) )
+ {
+ // Yay, we do not have to do anything :)
+ return true;
+ }
+ }
+
+ Destroy();
+
+ // create a Quartz layer matching to the intended virdev usage
+ CGContextRef xCGContext = NULL;
+ if( mnBitmapDepth && (mnBitmapDepth < 16) )
+ {
+ mnBitmapDepth = 8; // TODO: are 1bit vdevs worth it?
+ const CGColorSpaceRef aCGColorSpace = GetSalData()->mxGraySpace;
+ const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNone;
+ const int nBytesPerRow = (mnBitmapDepth * nDX + 7) / 8;
+
+ void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY );
+ mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY,
+ mnBitmapDepth, nBytesPerRow, aCGColorSpace, aCGBmpInfo );
+ xCGContext = mxBitmapContext;
+ }
+ else
+ {
+ // default to a NSView target context
+ AquaSalFrame* pSalFrame = mpGraphics->getGraphicsFrame();
+ if( !pSalFrame && !GetSalData()->maFrames.empty() )
+ pSalFrame = *GetSalData()->maFrames.begin();
+ if( pSalFrame )
+ {
+ NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pSalFrame->getWindow()];
+ if( pNSContext )
+ xCGContext = reinterpret_cast<CGContextRef>([pNSContext graphicsPort]);
+ }
+ }
+
+ DBG_ASSERT( xCGContext, "no context" );
+
+ const CGSize aNewSize = { nDX, nDY };
+ mxLayer = CGLayerCreateWithContext( xCGContext, aNewSize, NULL );
+
+ if( mxLayer && mpGraphics )
+ {
+ // get the matching Quartz context
+ CGContextRef xDrawContext = CGLayerGetContext( mxLayer );
+ mpGraphics->SetVirDevGraphics( mxLayer, xDrawContext, mnBitmapDepth );
+ }
+
+ return (mxLayer != NULL);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ if( mxLayer )
+ {
+ const CGSize aSize = CGLayerGetSize( mxLayer );
+ rWidth = static_cast<long>(aSize.width);
+ rHeight = static_cast<long>(aSize.height);
+ }
+ else
+ {
+ rWidth = 0;
+ rHeight = 0;
+ }
+}
diff --git a/vcl/aqua/source/res/MainMenu.nib/classes.nib b/vcl/aqua/source/res/MainMenu.nib/classes.nib
new file mode 100644
index 000000000000..b9b4b09f6b0d
--- /dev/null
+++ b/vcl/aqua/source/res/MainMenu.nib/classes.nib
@@ -0,0 +1,4 @@
+{
+ IBClasses = ({CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; });
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/vcl/aqua/source/res/MainMenu.nib/info.nib b/vcl/aqua/source/res/MainMenu.nib/info.nib
new file mode 100644
index 000000000000..856429aee5bd
--- /dev/null
+++ b/vcl/aqua/source/res/MainMenu.nib/info.nib
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>135 107 356 240 0 0 1680 1028 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>29</key>
+ <string>132 352 141 44 0 0 1680 1028 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>446.1</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>29</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8R2218</string>
+</dict>
+</plist>
diff --git a/vcl/aqua/source/res/MainMenu.nib/keyedobjects.nib b/vcl/aqua/source/res/MainMenu.nib/keyedobjects.nib
new file mode 100644
index 000000000000..d39d10119c0c
--- /dev/null
+++ b/vcl/aqua/source/res/MainMenu.nib/keyedobjects.nib
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/airbrush.png b/vcl/aqua/source/res/cursors/airbrush.png
new file mode 100644
index 000000000000..7ec780c4f9f9
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/airbrush.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/ase.png b/vcl/aqua/source/res/cursors/ase.png
new file mode 100644
index 000000000000..a3a30e0bcdce
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/ase.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asn.png b/vcl/aqua/source/res/cursors/asn.png
new file mode 100644
index 000000000000..7a140b1ec926
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asn.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asne.png b/vcl/aqua/source/res/cursors/asne.png
new file mode 100644
index 000000000000..311506aeb349
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asne.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asns.png b/vcl/aqua/source/res/cursors/asns.png
new file mode 100644
index 000000000000..1c8950eb28bc
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asns.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asnswe.png b/vcl/aqua/source/res/cursors/asnswe.png
new file mode 100644
index 000000000000..aae5246fbbc0
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asnswe.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asnw.png b/vcl/aqua/source/res/cursors/asnw.png
new file mode 100644
index 000000000000..9fd0036df077
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asnw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/ass.png b/vcl/aqua/source/res/cursors/ass.png
new file mode 100644
index 000000000000..bee09e736ad1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/ass.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asse.png b/vcl/aqua/source/res/cursors/asse.png
new file mode 100644
index 000000000000..d7883211d44f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asse.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/assw.png b/vcl/aqua/source/res/cursors/assw.png
new file mode 100644
index 000000000000..0b0a496a52ec
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/assw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asw.png b/vcl/aqua/source/res/cursors/asw.png
new file mode 100644
index 000000000000..5a4b9519e075
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/aswe.png b/vcl/aqua/source/res/cursors/aswe.png
new file mode 100644
index 000000000000..b9c5afaac043
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/aswe.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/chain.png b/vcl/aqua/source/res/cursors/chain.png
new file mode 100644
index 000000000000..dbf069924d73
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/chain.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/chainnot.png b/vcl/aqua/source/res/cursors/chainnot.png
new file mode 100644
index 000000000000..547703edf12c
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/chainnot.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/chart.png b/vcl/aqua/source/res/cursors/chart.png
new file mode 100644
index 000000000000..de5514006e1f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/chart.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copydata.png b/vcl/aqua/source/res/cursors/copydata.png
new file mode 100644
index 000000000000..b6202fd9144f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copydata.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copydlnk.png b/vcl/aqua/source/res/cursors/copydlnk.png
new file mode 100644
index 000000000000..fab24c9f8f7c
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copydlnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copyf.png b/vcl/aqua/source/res/cursors/copyf.png
new file mode 100644
index 000000000000..70546d0c0c22
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copyf.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copyf2.png b/vcl/aqua/source/res/cursors/copyf2.png
new file mode 100644
index 000000000000..b6f76051f10f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copyf2.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copyflnk.png b/vcl/aqua/source/res/cursors/copyflnk.png
new file mode 100644
index 000000000000..23561e484e36
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copyflnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/crook.png b/vcl/aqua/source/res/cursors/crook.png
new file mode 100644
index 000000000000..4378f8df8351
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/crook.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/crop.png b/vcl/aqua/source/res/cursors/crop.png
new file mode 100644
index 000000000000..92a778ada31a
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/crop.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/darc.png b/vcl/aqua/source/res/cursors/darc.png
new file mode 100644
index 000000000000..9772a1c6b85a
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/darc.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dbezier.png b/vcl/aqua/source/res/cursors/dbezier.png
new file mode 100644
index 000000000000..988498137e9a
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dbezier.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dcapt.png b/vcl/aqua/source/res/cursors/dcapt.png
new file mode 100644
index 000000000000..d1ef82818735
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dcapt.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dcirccut.png b/vcl/aqua/source/res/cursors/dcirccut.png
new file mode 100644
index 000000000000..cb4ed0e85ecd
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dcirccut.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dconnect.png b/vcl/aqua/source/res/cursors/dconnect.png
new file mode 100644
index 000000000000..e4a43bdbe021
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dconnect.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dellipse.png b/vcl/aqua/source/res/cursors/dellipse.png
new file mode 100644
index 000000000000..319c4574c7c1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dellipse.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/detectiv.png b/vcl/aqua/source/res/cursors/detectiv.png
new file mode 100644
index 000000000000..abe93f263d4d
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/detectiv.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dfree.png b/vcl/aqua/source/res/cursors/dfree.png
new file mode 100644
index 000000000000..2de92942adde
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dfree.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dline.png b/vcl/aqua/source/res/cursors/dline.png
new file mode 100644
index 000000000000..6afb670ef8a8
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dline.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dpie.png b/vcl/aqua/source/res/cursors/dpie.png
new file mode 100644
index 000000000000..44a9474846b9
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dpie.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dpolygon.png b/vcl/aqua/source/res/cursors/dpolygon.png
new file mode 100644
index 000000000000..847e6ad9bea5
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dpolygon.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/drect.png b/vcl/aqua/source/res/cursors/drect.png
new file mode 100644
index 000000000000..ff3dcbba07b4
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/drect.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dtext.png b/vcl/aqua/source/res/cursors/dtext.png
new file mode 100644
index 000000000000..ee375f0e47a0
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dtext.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/fill.png b/vcl/aqua/source/res/cursors/fill.png
new file mode 100644
index 000000000000..220641b9beb4
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/fill.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/help.png b/vcl/aqua/source/res/cursors/help.png
new file mode 100644
index 000000000000..e29c19eccd22
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/help.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/hourglass.png b/vcl/aqua/source/res/cursors/hourglass.png
new file mode 100644
index 000000000000..07bb5af73e6e
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/hourglass.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/hshear.png b/vcl/aqua/source/res/cursors/hshear.png
new file mode 100644
index 000000000000..b45beded2d93
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/hshear.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/linkdata.png b/vcl/aqua/source/res/cursors/linkdata.png
new file mode 100644
index 000000000000..6432db0155b6
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/linkdata.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/linkf.png b/vcl/aqua/source/res/cursors/linkf.png
new file mode 100644
index 000000000000..e17107fec9ff
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/linkf.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/magnify.png b/vcl/aqua/source/res/cursors/magnify.png
new file mode 100644
index 000000000000..4e73146b91e4
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/magnify.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/mirror.png b/vcl/aqua/source/res/cursors/mirror.png
new file mode 100644
index 000000000000..8fac93f0b6df
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/mirror.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movebw.png b/vcl/aqua/source/res/cursors/movebw.png
new file mode 100644
index 000000000000..63bf76ad3942
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movebw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movedata.png b/vcl/aqua/source/res/cursors/movedata.png
new file mode 100644
index 000000000000..60ece8a53e59
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movedata.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movedlnk.png b/vcl/aqua/source/res/cursors/movedlnk.png
new file mode 100644
index 000000000000..6951cd718d97
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movedlnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movef.png b/vcl/aqua/source/res/cursors/movef.png
new file mode 100644
index 000000000000..97a01c88fa4d
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movef.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movef2.png b/vcl/aqua/source/res/cursors/movef2.png
new file mode 100644
index 000000000000..2cdddb410aae
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movef2.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/moveflnk.png b/vcl/aqua/source/res/cursors/moveflnk.png
new file mode 100644
index 000000000000..53301ba58c50
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/moveflnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movept.png b/vcl/aqua/source/res/cursors/movept.png
new file mode 100644
index 000000000000..41945deb1916
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movept.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/neswsize.png b/vcl/aqua/source/res/cursors/neswsize.png
new file mode 100644
index 000000000000..91b89b5803ec
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/neswsize.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/notallow.png b/vcl/aqua/source/res/cursors/notallow.png
new file mode 100644
index 000000000000..df770a495194
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/notallow.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/nullptr.png b/vcl/aqua/source/res/cursors/nullptr.png
new file mode 100644
index 000000000000..489636595bec
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/nullptr.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/nwsesize.png b/vcl/aqua/source/res/cursors/nwsesize.png
new file mode 100644
index 000000000000..fc6a33288ef2
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/nwsesize.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pen.png b/vcl/aqua/source/res/cursors/pen.png
new file mode 100644
index 000000000000..81b583086778
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pen.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotcol.png b/vcl/aqua/source/res/cursors/pivotcol.png
new file mode 100644
index 000000000000..1c38b915b886
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotcol.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotdel.png b/vcl/aqua/source/res/cursors/pivotdel.png
new file mode 100644
index 000000000000..fbd663ee36c1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotdel.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotfld.png b/vcl/aqua/source/res/cursors/pivotfld.png
new file mode 100644
index 000000000000..04375de1efe6
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotfld.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotrow.png b/vcl/aqua/source/res/cursors/pivotrow.png
new file mode 100644
index 000000000000..18ef0e8e59ba
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotrow.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pntbrsh.png b/vcl/aqua/source/res/cursors/pntbrsh.png
new file mode 100644
index 000000000000..ec8d799f66c2
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pntbrsh.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/rotate.png b/vcl/aqua/source/res/cursors/rotate.png
new file mode 100644
index 000000000000..a8137e077e56
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/rotate.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblsele.png b/vcl/aqua/source/res/cursors/tblsele.png
new file mode 100644
index 000000000000..a2da05e009d1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblsele.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblsels.png b/vcl/aqua/source/res/cursors/tblsels.png
new file mode 100644
index 000000000000..ba20589c794f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblsels.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblselse.png b/vcl/aqua/source/res/cursors/tblselse.png
new file mode 100644
index 000000000000..4ee7f62b304b
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblselse.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblselsw.png b/vcl/aqua/source/res/cursors/tblselsw.png
new file mode 100644
index 000000000000..11d7cb34d64d
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblselsw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblselw.png b/vcl/aqua/source/res/cursors/tblselw.png
new file mode 100644
index 000000000000..62813a975855
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblselw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/timemove.png b/vcl/aqua/source/res/cursors/timemove.png
new file mode 100644
index 000000000000..3dae038a2011
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/timemove.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/timesize.png b/vcl/aqua/source/res/cursors/timesize.png
new file mode 100644
index 000000000000..22178c9b8d0e
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/timesize.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/vshear.png b/vcl/aqua/source/res/cursors/vshear.png
new file mode 100644
index 000000000000..b01cb6c935e1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/vshear.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/vtext.png b/vcl/aqua/source/res/cursors/vtext.png
new file mode 100644
index 000000000000..2d6c847c9fc7
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/vtext.png
Binary files differ
diff --git a/vcl/aqua/source/res/delzip b/vcl/aqua/source/res/delzip
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/vcl/aqua/source/res/delzip
diff --git a/vcl/aqua/source/res/makefile.mk b/vcl/aqua/source/res/makefile.mk
new file mode 100644
index 000000000000..2043504450e7
--- /dev/null
+++ b/vcl/aqua/source/res/makefile.mk
@@ -0,0 +1,54 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+TARGET=aquares
+
+# --- Settings -------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files ----------------------------------------------------
+
+.IF "$(OS)"!="MACOSX"
+
+dummy:
+ @echo "Nothing to build for OS $(OS)"
+
+.ELSE # "$(OS)"!="MACOSX"
+
+ZIPFLAGS = -r
+ZIP1TARGET = osxres
+#ZIP1DIR =
+ZIP1LIST = MainMenu.nib/*.nib cursors/*.png
+
+# --- Targets --------------------------------------------------
+
+.INCLUDE : target.mk
+
+.ENDIF # "$(OS)"!="MACOSX"
+
diff --git a/vcl/aqua/source/window/makefile.mk b/vcl/aqua/source/window/makefile.mk
new file mode 100644
index 000000000000..7afbce885e4a
--- /dev/null
+++ b/vcl/aqua/source/window/makefile.mk
@@ -0,0 +1,63 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=salwin
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= \
+ $(SLO)/salframe.obj \
+ $(SLO)/salframeview.obj \
+ $(SLO)/salmenu.obj \
+ $(SLO)/salnsmenu.obj \
+ $(SLO)/salobj.obj
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/aqua/source/window/salframe.cxx b/vcl/aqua/source/window/salframe.cxx
new file mode 100644
index 000000000000..b14354e1b4bd
--- /dev/null
+++ b/vcl/aqua/source/window/salframe.cxx
@@ -0,0 +1,1636 @@
+/************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string>
+
+#include "saldata.hxx"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salmenu.h"
+#include "saltimer.h"
+#include "salinst.h"
+#include "salframeview.h"
+#include "aqua11yfactory.h"
+#include "vcl/salwtype.hxx"
+#include "vcl/window.hxx"
+#include "vcl/timer.hxx"
+
+#include "premac.h"
+// needed for theming
+// FIXME: move theming code to salnativewidgets.cxx
+#include <Carbon/Carbon.h>
+#include "postmac.h"
+
+#include "boost/assert.hpp"
+#include "vcl/svapp.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "osl/file.h"
+
+using namespace std;
+
+// =======================================================================
+
+AquaSalFrame* AquaSalFrame::s_pCaptureFrame = NULL;
+
+// =======================================================================
+
+AquaSalFrame::AquaSalFrame( SalFrame* pParent, ULONG salFrameStyle ) :
+ mpWindow(nil),
+ mpView(nil),
+ mpDockMenuEntry(nil),
+ mpGraphics(NULL),
+ mpParent(NULL),
+ mnMinWidth(0),
+ mnMinHeight(0),
+ mnMaxWidth(0),
+ mnMaxHeight(0),
+ mbGraphics(false),
+ mbFullScreen( false ),
+ mbShown(false),
+ mbInitShow(true),
+ mbPositioned(false),
+ mbSized(false),
+ mbPresentation( false ),
+ mnStyle( salFrameStyle ),
+ mnStyleMask( 0 ),
+ mnLastEventTime( 0 ),
+ mnLastModifierFlags( 0 ),
+ mpMenu( NULL ),
+ mnExtStyle( 0 ),
+ mePointerStyle( POINTER_ARROW ),
+ mnTrackingRectTag( 0 ),
+ mrClippingPath( 0 ),
+ mnICOptions( 0 )
+{
+ maSysData.nSize = sizeof( SystemEnvData );
+
+ mpParent = dynamic_cast<AquaSalFrame*>(pParent);
+
+ initWindowAndView();
+
+ SalData* pSalData = GetSalData();
+ pSalData->maFrames.push_front( this );
+ pSalData->maFrameCheck.insert( this );
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalFrame::~AquaSalFrame()
+{
+ // if the frame is destroyed and has the current menubar
+ // set the default menubar
+ if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
+ AquaSalMenu::setDefaultMenu();
+
+ // cleanup clipping stuff
+ ResetClipRegion();
+
+ [SalFrameView unsetMouseFrame: this];
+
+ SalData* pSalData = GetSalData();
+ pSalData->maFrames.remove( this );
+ pSalData->maFrameCheck.erase( this );
+
+ DBG_ASSERT( this != s_pCaptureFrame, "capture frame destroyed" );
+ if( this == s_pCaptureFrame )
+ s_pCaptureFrame = NULL;
+
+ if ( mpGraphics )
+ delete mpGraphics;
+
+ if( mpDockMenuEntry )
+ // life cycle comment: the menu has ownership of the item, so no release
+ [AquaSalInstance::GetDynamicDockMenu() removeItem: mpDockMenuEntry];
+ if ( mpView ) {
+ [AquaA11yFactory revokeView: mpView];
+ [mpView release];
+ }
+ if ( mpWindow )
+ [mpWindow release];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::initWindowAndView()
+{
+ // initialize mirroring parameters
+ // FIXME: screens changing
+ NSScreen * pScreen = [mpWindow screen];
+ if( pScreen == nil )
+ pScreen = [NSScreen mainScreen];
+ maScreenRect = [pScreen frame];
+
+ // calculate some default geometry
+ NSRect aVisibleRect = [pScreen visibleFrame];
+ CocoaToVCL( aVisibleRect );
+
+ maGeometry.nX = static_cast<int>(aVisibleRect.origin.x + aVisibleRect.size.width / 10);
+ maGeometry.nY = static_cast<int>(aVisibleRect.origin.y + aVisibleRect.size.height / 10);
+ maGeometry.nWidth = static_cast<unsigned int>(aVisibleRect.size.width * 0.8);
+ maGeometry.nHeight = static_cast<unsigned int>(aVisibleRect.size.height * 0.8);
+
+ // calculate style mask
+ if( (mnStyle & SAL_FRAME_STYLE_FLOAT) ||
+ (mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ mnStyleMask = NSBorderlessWindowMask;
+ else if( mnStyle & SAL_FRAME_STYLE_DEFAULT )
+ {
+ mnStyleMask = NSTitledWindowMask |
+ NSMiniaturizableWindowMask |
+ NSResizableWindowMask |
+ NSClosableWindowMask;
+ // make default window "maximized"
+ maGeometry.nX = static_cast<int>(aVisibleRect.origin.x);
+ maGeometry.nY = static_cast<int>(aVisibleRect.origin.y);
+ maGeometry.nWidth = static_cast<int>(aVisibleRect.size.width);
+ maGeometry.nHeight = static_cast<int>(aVisibleRect.size.height);
+ mbPositioned = mbSized = true;
+ }
+ else
+ {
+ if( (mnStyle & SAL_FRAME_STYLE_MOVEABLE) )
+ {
+ mnStyleMask |= NSTitledWindowMask;
+ if( mpParent == NULL )
+ mnStyleMask |= NSMiniaturizableWindowMask;
+ }
+ if( (mnStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ mnStyleMask |= NSResizableWindowMask;
+ if( (mnStyle & SAL_FRAME_STYLE_CLOSEABLE) )
+ mnStyleMask |= NSClosableWindowMask;
+ // documentation says anything other than NSBorderlessWindowMask (=0)
+ // should also include NSTitledWindowMask;
+ if( mnStyleMask != 0 )
+ mnStyleMask |= NSTitledWindowMask;
+ }
+
+ mpWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
+ mpView = [[SalFrameView alloc] initWithSalFrame: this];
+ if( (mnStyle & SAL_FRAME_STYLE_TOOLTIP) )
+ [mpWindow setIgnoresMouseEvents: YES];
+ else
+ [mpWindow setAcceptsMouseMovedEvents: YES];
+ [mpWindow setHasShadow: YES];
+ [mpWindow setDelegate: mpWindow];
+
+ NSRect aRect = { { 0,0 }, { maGeometry.nWidth, maGeometry.nHeight } };
+ mnTrackingRectTag = [mpView addTrackingRect: aRect owner: mpView userData: nil assumeInside: NO];
+
+ maSysData.pView = mpView;
+
+ UpdateFrameGeometry();
+
+ // setContentView causes a display; in multithreaded use this can deadlock
+ //YieldMutexReleaser aRel;
+ [mpWindow setContentView: mpView];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
+ else
+ io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
+}
+
+void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
+ else
+ io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
+}
+
+void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
+ else
+ io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
+}
+
+void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
+ else
+ io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::screenParametersChanged()
+{
+ UpdateFrameGeometry();
+
+ if( mpGraphics )
+ mpGraphics->updateResolution();
+ CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalFrame::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( !mpGraphics )
+ {
+ mpGraphics = new AquaSalGraphics;
+ mpGraphics->SetWindowGraphics( this );
+ }
+
+ mbGraphics = TRUE;
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ DBG_ASSERT( pGraphics == mpGraphics, "graphics released on wrong frame" );
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalFrame::PostEvent( void *pData )
+{
+ GetSalData()->mpFirstInstance->PostUserEvent( this, SALEVENT_USEREVENT, pData );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+void AquaSalFrame::SetTitle(const XubString& rTitle)
+{
+ NSString* pTitle = CreateNSString( rTitle );
+ [mpWindow setTitle: pTitle];
+
+ // create an entry in the dock menu
+ const ULONG nAppWindowStyle = (SAL_FRAME_STYLE_CLOSEABLE | SAL_FRAME_STYLE_MOVEABLE);
+ if( mpParent == NULL &&
+ (mnStyle & nAppWindowStyle) == nAppWindowStyle )
+ {
+ if( mpDockMenuEntry == NULL )
+ {
+ NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
+ mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
+ action: @selector(dockMenuItemTriggered:)
+ keyEquivalent: @""
+ atIndex: 0];
+ [mpDockMenuEntry setTarget: mpWindow];
+
+ // TODO: image (either the generic window image or an icon
+ // check mark (for "main" window ?)
+ }
+ else
+ [mpDockMenuEntry setTitle: pTitle];
+ }
+
+ if (pTitle)
+ [pTitle release];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetIcon( USHORT )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetRepresentedURL( const rtl::OUString& i_rDocURL )
+{
+ if( i_rDocURL.indexOfAsciiL( "file:", 5 ) == 0 )
+ {
+ rtl::OUString aSysPath;
+ osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
+ NSString* pStr = CreateNSString( aSysPath );
+ if( pStr )
+ {
+ [pStr autorelease];
+ [mpWindow setRepresentedFilename: pStr];
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::initShow()
+{
+ mbInitShow = false;
+ if( ! mbPositioned && ! mbFullScreen )
+ {
+ Rectangle aScreenRect;
+ GetWorkArea( aScreenRect );
+ if( mpParent ) // center relative to parent
+ {
+ // center on parent
+ long nNewX = mpParent->maGeometry.nX + (mpParent->maGeometry.nWidth - maGeometry.nWidth)/2;
+ if( nNewX < aScreenRect.Left() )
+ nNewX = aScreenRect.Left();
+ if( long(nNewX + maGeometry.nWidth) > aScreenRect.Right() )
+ nNewX = aScreenRect.Right() - maGeometry.nWidth-1;
+ long nNewY = mpParent->maGeometry.nY + (mpParent->maGeometry.nHeight - maGeometry.nHeight)/2;
+ if( nNewY < aScreenRect.Top() )
+ nNewY = aScreenRect.Top();
+ if( nNewY > aScreenRect.Bottom() )
+ nNewY = aScreenRect.Bottom() - maGeometry.nHeight-1;
+ SetPosSize( nNewX - mpParent->maGeometry.nX,
+ nNewY - mpParent->maGeometry.nY,
+ 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+ }
+ else if( ! (mnStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ {
+ // center on screen
+ long nNewX = (aScreenRect.GetWidth() - maGeometry.nWidth)/2;
+ long nNewY = (aScreenRect.GetHeight() - maGeometry.nHeight)/2;
+ SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+ }
+ }
+
+ // make sure the view is present in the wrapper list before any children receive focus
+ [AquaA11yFactory registerView: mpView];
+}
+
+void AquaSalFrame::SendPaintEvent( const Rectangle* pRect )
+{
+ SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true );
+ if( pRect )
+ {
+ aPaintEvt.mnBoundX = pRect->Left();
+ aPaintEvt.mnBoundY = pRect->Top();
+ aPaintEvt.mnBoundWidth = pRect->GetWidth();
+ aPaintEvt.mnBoundHeight = pRect->GetHeight();
+ }
+
+ CallCallback(SALEVENT_PAINT, &aPaintEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Show(BOOL bVisible, BOOL bNoActivate)
+{
+ mbShown = bVisible;
+ if(bVisible)
+ {
+ if( mbInitShow )
+ initShow();
+
+ CallCallback(SALEVENT_RESIZE, 0);
+ // trigger filling our backbuffer
+ SendPaintEvent();
+
+ //YieldMutexReleaser aRel;
+
+ if( bNoActivate || [mpWindow canBecomeKeyWindow] == NO )
+ [mpWindow orderFront: NSApp];
+ else
+ [mpWindow makeKeyAndOrderFront: NSApp];
+
+ if( mpParent )
+ {
+ /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
+ child implicitly does). However we also do not want a parentless toolbar.
+
+ HACK: try to decide when we should not insert a child to its parent
+ floaters and ownerdraw windows have not yet shown up in cases where
+ we don't want the parent to become visible
+ */
+ if( mpParent->mbShown || (mnStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_FLOAT) ) )
+ {
+ [mpParent->mpWindow addChildWindow: mpWindow ordered: NSWindowAbove];
+ }
+ }
+
+ if( mbPresentation )
+ [mpWindow makeMainWindow];
+ }
+ else
+ {
+ // if the frame holding the current menubar gets hidden
+ // show the default menubar
+ if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
+ AquaSalMenu::setDefaultMenu();
+
+ //YieldMutexReleaser aRel;
+
+ // #i90440# #i94443# work around the focus going back to some other window
+ // if a child gets hidden for a parent window
+ if( mpParent && mpParent->mbShown && [mpWindow isKeyWindow] )
+ [mpParent->mpWindow makeKeyAndOrderFront: NSApp];
+
+ [SalFrameView unsetMouseFrame: this];
+ if( mpParent && [mpWindow parentWindow] == mpParent->mpWindow )
+ [mpParent->mpWindow removeChildWindow: mpWindow];
+
+ [mpWindow orderOut: NSApp];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Enable( BOOL bEnable )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ mnMinWidth = nWidth;
+ mnMinHeight = nHeight;
+
+ if( mpWindow )
+ {
+ // Always add the decoration as the dimension concerns only
+ // the content rectangle
+ nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
+ nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
+
+ NSSize aSize = { nWidth, nHeight };
+
+ // Size of full window (content+structure) although we only
+ // have the client size in arguments
+ [mpWindow setMinSize: aSize];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ mnMaxWidth = nWidth;
+ mnMaxHeight = nHeight;
+
+ if( mpWindow )
+ {
+ // Always add the decoration as the dimension concerns only
+ // the content rectangle
+ nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
+ nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
+
+ // Carbon windows can't have a size greater than 32767x32767
+ if (nWidth>32767) nWidth=32767;
+ if (nHeight>32767) nHeight=32767;
+
+ NSSize aSize = { nWidth, nHeight };
+
+ // Size of full window (content+structure) although we only
+ // have the client size in arguments
+ [mpWindow setMaxSize: aSize];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetClientSize( long nWidth, long nHeight )
+{
+ if( mpWindow )
+ {
+ NSSize aSize = { nWidth, nHeight };
+
+ [mpWindow setContentSize: aSize];
+ UpdateFrameGeometry();
+ if( mbShown )
+ // trigger filling our backbuffer
+ SendPaintEvent();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ if( mbShown || mbInitShow )
+ {
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+ }
+ else
+ {
+ rWidth = 0;
+ rHeight = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetWindowState( const SalFrameState* pState )
+{
+ // set normal state
+ NSRect aStateRect = [mpWindow frame];
+ aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
+ CocoaToVCL( aStateRect );
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_X )
+ aStateRect.origin.x = float(pState->mnX);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
+ aStateRect.origin.y = float(pState->mnY);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
+ aStateRect.size.width = float(pState->mnWidth);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
+ aStateRect.size.height = float(pState->mnHeight);
+ VCLToCocoa( aStateRect );
+ aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
+
+ // relase and acquire mutex again since this call can block waiting for an internal lock
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: aStateRect display: NO];
+ }
+
+ // FIXME: HTH maximized state ?
+
+ // get new geometry
+ UpdateFrameGeometry();
+
+ USHORT nEvent = 0;
+ if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_X) )
+ {
+ mbPositioned = true;
+ nEvent = SALEVENT_MOVE;
+ }
+
+ if( pState->mnMask & (SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT) )
+ {
+ mbSized = true;
+ nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE;
+ }
+ // send event that we were moved/sized
+ if( nEvent )
+ CallCallback( nEvent, NULL );
+
+ if( mbShown )
+ {
+ // trigger filling our backbuffer
+ SendPaintEvent();
+
+ // tell the system the views need to be updated
+ //YieldMutexReleaser aRel;
+
+ [mpWindow display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalFrame::GetWindowState( SalFrameState* pState )
+{
+ pState->mnMask = SAL_FRAMESTATE_MASK_X |
+ SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH |
+ SAL_FRAMESTATE_MASK_HEIGHT |
+ #if 0
+ SAL_FRAMESTATE_MASK_MAXIMIZED_X |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT |
+ #endif
+ SAL_FRAMESTATE_MASK_STATE;
+
+ NSRect aStateRect = [mpWindow frame];
+ aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
+ CocoaToVCL( aStateRect );
+ pState->mnX = long(aStateRect.origin.x);
+ pState->mnY = long(aStateRect.origin.y);
+ pState->mnWidth = long(aStateRect.size.width);
+ pState->mnHeight = long(aStateRect.size.height);
+
+ // FIXME: HTH maximized state ?
+
+ if( [mpWindow isMiniaturized] )
+ pState->mnState = SAL_FRAMESTATE_MINIMIZED;
+ else if( ! [mpWindow isZoomed] )
+ pState->mnState = SAL_FRAMESTATE_NORMAL;
+ else
+ pState->mnState = SAL_FRAMESTATE_MAXIMIZED;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
+{
+ NSArray* pScreens = [NSScreen screens];
+ Rectangle aRet;
+ NSScreen* pScreen = nil;
+ if( pScreens && nScreen < [pScreens count] )
+ {
+ // get new screen frame
+ pScreen = [pScreens objectAtIndex: nScreen];
+ NSRect aNewScreen = [pScreen frame];
+
+ // get current screen frame
+ pScreen = [mpWindow screen];
+ if( pScreen )
+ {
+ NSRect aCurScreen = [pScreen frame];
+ if( aCurScreen.origin.x != aNewScreen.origin.x ||
+ aCurScreen.origin.y != aNewScreen.origin.y )
+ {
+ NSRect aFrameRect = [mpWindow frame];
+ aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
+ aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
+ [mpWindow setFrame: aFrameRect display: NO];
+ UpdateFrameGeometry();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay )
+{
+ if( mbFullScreen == bFullScreen )
+ return;
+
+ mbFullScreen = bFullScreen;
+ if( bFullScreen )
+ {
+ // hide the dock and the menubar if we are on the menu screen
+ // which is always on index 0 according to documentation
+ bool bHideMenu = (nDisplay == 0);
+
+ NSRect aNewContentRect = { { 0, 0 }, { 0, 0 } };
+ // get correct screen
+ NSScreen* pScreen = nil;
+ NSArray* pScreens = [NSScreen screens];
+ if( pScreens )
+ {
+ if( nDisplay >= 0 && (unsigned int)nDisplay < [pScreens count] )
+ pScreen = [pScreens objectAtIndex: nDisplay];
+ else
+ {
+ // this means span all screens
+ bHideMenu = true;
+ NSEnumerator* pEnum = [pScreens objectEnumerator];
+ while( (pScreen = [pEnum nextObject]) != nil )
+ {
+ NSRect aScreenRect = [pScreen frame];
+ if( aScreenRect.origin.x < aNewContentRect.origin.x )
+ {
+ aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
+ aNewContentRect.origin.x = aScreenRect.origin.x;
+ }
+ if( aScreenRect.origin.y < aNewContentRect.origin.y )
+ {
+ aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
+ aNewContentRect.origin.y = aScreenRect.origin.y;
+ }
+ if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
+ aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
+ if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
+ aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
+ }
+ }
+ }
+ if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
+ {
+ if( pScreen == nil )
+ pScreen = [mpWindow screen];
+ if( pScreen == nil )
+ pScreen = [NSScreen mainScreen];
+
+ aNewContentRect = [pScreen frame];
+ }
+
+ if( bHideMenu )
+ [NSMenu setMenuBarVisible:NO];
+
+ maFullScreenRect = [mpWindow frame];
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
+ }
+
+ UpdateFrameGeometry();
+
+ if( mbShown )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+ }
+ else
+ {
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
+ }
+ UpdateFrameGeometry();
+
+ if( mbShown )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+
+ // show the dock and the menubar
+ [NSMenu setMenuBarVisible:YES];
+ }
+ if( mbShown )
+ // trigger filling our backbuffer
+ SendPaintEvent();
+}
+
+// -----------------------------------------------------------------------
+
+class PreventSleepTimer : public AutoTimer
+{
+public:
+ PreventSleepTimer()
+ {
+ SetTimeout( 30000 );
+ Start();
+ }
+
+ virtual ~PreventSleepTimer()
+ {
+ }
+
+ virtual void Timeout()
+ {
+ UpdateSystemActivity(OverallAct);
+ }
+};
+
+void AquaSalFrame::StartPresentation( BOOL bStart )
+{
+ if( bStart )
+ {
+ mpActivityTimer.reset( new PreventSleepTimer() );
+ [mpWindow setLevel: NSScreenSaverWindowLevel];
+ if( mbShown )
+ [mpWindow makeMainWindow];
+ }
+ else
+ {
+ mpActivityTimer.reset();
+ [mpWindow setLevel: NSNormalWindowLevel];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetAlwaysOnTop( BOOL bOnTop )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::ToTop(USHORT nFlags)
+{
+ if( ! (nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN) )
+ {
+ if( ! [mpWindow isVisible] || [mpWindow isMiniaturized] )
+ return;
+ }
+ if( nFlags & SAL_FRAME_TOTOP_GRABFOCUS )
+ [mpWindow makeKeyAndOrderFront: NSApp];
+ else
+ [mpWindow orderFront: NSApp];
+}
+
+// -----------------------------------------------------------------------
+
+NSCursor* AquaSalFrame::getCurrentCursor() const
+{
+ NSCursor* pCursor = nil;
+ switch( mePointerStyle )
+ {
+ case POINTER_TEXT: pCursor = [NSCursor IBeamCursor]; break;
+ case POINTER_CROSS: pCursor = [NSCursor crosshairCursor]; break;
+ case POINTER_HAND:
+ case POINTER_MOVE: pCursor = [NSCursor openHandCursor]; break;
+ case POINTER_NSIZE: pCursor = [NSCursor resizeUpCursor]; break;
+ case POINTER_SSIZE: pCursor = [NSCursor resizeDownCursor]; break;
+ case POINTER_ESIZE: pCursor = [NSCursor resizeRightCursor]; break;
+ case POINTER_WSIZE: pCursor = [NSCursor resizeLeftCursor]; break;
+ case POINTER_ARROW: pCursor = [NSCursor arrowCursor]; break;
+ case POINTER_VSPLIT:
+ case POINTER_VSIZEBAR:
+ case POINTER_WINDOW_NSIZE:
+ case POINTER_WINDOW_SSIZE:
+ pCursor = [NSCursor resizeUpDownCursor]; break;
+ case POINTER_HSPLIT:
+ case POINTER_HSIZEBAR:
+ case POINTER_WINDOW_ESIZE:
+ case POINTER_WINDOW_WSIZE:
+ pCursor = [NSCursor resizeLeftRightCursor]; break;
+ case POINTER_REFHAND: pCursor = [NSCursor pointingHandCursor]; break;
+
+ default:
+ pCursor = GetSalData()->getCursor( mePointerStyle );
+ if( pCursor == nil )
+ {
+ DBG_ERROR( "unmapped cursor" );
+ pCursor = [NSCursor arrowCursor];
+ }
+ break;
+ }
+ return pCursor;
+}
+
+void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ if( ePointerStyle >= POINTER_COUNT || ePointerStyle == mePointerStyle )
+ return;
+ mePointerStyle = ePointerStyle;
+
+ [mpWindow invalidateCursorRectsForView: mpView];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetPointerPos( long nX, long nY )
+{
+ // FIXME: use Cocoa functions
+
+ // FIXME: multiscreen support
+ CGPoint aPoint = { nX + maGeometry.nX, nY + maGeometry.nY };
+ CGDirectDisplayID mainDisplayID = CGMainDisplayID();
+ CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Flush( void )
+{
+ if( !(mbGraphics && mpGraphics && mpView && mbShown) )
+ return;
+
+ [mpView setNeedsDisplay: YES];
+
+ // outside of the application's event loop (e.g. IntroWindow)
+ // nothing would trigger paint event handling
+ // => fall back to synchronous painting
+ if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
+ {
+ [mpView display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Flush( const Rectangle& rRect )
+{
+ if( !(mbGraphics && mpGraphics && mpView && mbShown) )
+ return;
+
+ NSRect aNSRect = { {rRect.Left(), rRect.Top()}, { rRect.GetWidth(), rRect.GetHeight() } };
+ VCLToCocoa( aNSRect, false );
+ [mpView setNeedsDisplayInRect: aNSRect];
+
+ // outside of the application's event loop (e.g. IntroWindow)
+ // nothing would trigger paint event handling
+ // => fall back to synchronous painting
+ if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
+ {
+ [mpView display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Sync()
+{
+ if( mbGraphics && mpGraphics && mpView && mbShown )
+ {
+ //YieldMutexReleaser aRel;
+
+ [mpView setNeedsDisplay: YES];
+ [mpView display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if (!pContext)
+ {
+ mnICOptions = 0;
+ return;
+ }
+
+ mnICOptions = pContext->mnOptions;
+
+ if(!(pContext->mnOptions & SAL_INPUTCONTEXT_TEXT))
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::EndExtTextInput( USHORT nFlags )
+{
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalFrame::GetKeyName( USHORT nKeyCode )
+{
+ static std::map< USHORT, rtl::OUString > aKeyMap;
+ if( aKeyMap.empty() )
+ {
+ USHORT i;
+ for( i = KEY_A; i <= KEY_Z; i++ )
+ aKeyMap[ i ] = rtl::OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
+ for( i = KEY_0; i <= KEY_9; i++ )
+ aKeyMap[ i ] = rtl::OUString( sal_Unicode( '0' + (i - KEY_0) ) );
+ for( i = KEY_F1; i <= KEY_F26; i++ )
+ {
+ rtl::OUStringBuffer aKey( 3 );
+ aKey.append( sal_Unicode( 'F' ) );
+ aKey.append( sal_Int32( i - KEY_F1 + 1 ) );
+ aKeyMap[ i ] = aKey.makeStringAndClear();
+ }
+
+ aKeyMap[ KEY_DOWN ] = rtl::OUString( sal_Unicode( 0x21e3 ) );
+ aKeyMap[ KEY_UP ] = rtl::OUString( sal_Unicode( 0x21e1 ) );
+ aKeyMap[ KEY_LEFT ] = rtl::OUString( sal_Unicode( 0x21e0 ) );
+ aKeyMap[ KEY_RIGHT ] = rtl::OUString( sal_Unicode( 0x21e2 ) );
+ aKeyMap[ KEY_HOME ] = rtl::OUString( sal_Unicode( 0x2196 ) );
+ aKeyMap[ KEY_END ] = rtl::OUString( sal_Unicode( 0x2198 ) );
+ aKeyMap[ KEY_PAGEUP ] = rtl::OUString( sal_Unicode( 0x21de ) );
+ aKeyMap[ KEY_PAGEDOWN ] = rtl::OUString( sal_Unicode( 0x21df ) );
+ aKeyMap[ KEY_RETURN ] = rtl::OUString( sal_Unicode( 0x21a9 ) );
+ aKeyMap[ KEY_ESCAPE ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "esc" ) );
+ aKeyMap[ KEY_TAB ] = rtl::OUString( sal_Unicode( 0x21e5 ) );
+ aKeyMap[ KEY_BACKSPACE ]= rtl::OUString( sal_Unicode( 0x232b ) );
+ aKeyMap[ KEY_SPACE ] = rtl::OUString( sal_Unicode( 0x2423 ) );
+ aKeyMap[ KEY_DELETE ] = rtl::OUString( sal_Unicode( 0x2326 ) );
+ aKeyMap[ KEY_ADD ] = rtl::OUString( sal_Unicode( '+' ) );
+ aKeyMap[ KEY_SUBTRACT ] = rtl::OUString( sal_Unicode( '-' ) );
+ aKeyMap[ KEY_DIVIDE ] = rtl::OUString( sal_Unicode( '/' ) );
+ aKeyMap[ KEY_MULTIPLY ] = rtl::OUString( sal_Unicode( '*' ) );
+ aKeyMap[ KEY_POINT ] = rtl::OUString( sal_Unicode( '.' ) );
+ aKeyMap[ KEY_COMMA ] = rtl::OUString( sal_Unicode( ',' ) );
+ aKeyMap[ KEY_LESS ] = rtl::OUString( sal_Unicode( '<' ) );
+ aKeyMap[ KEY_GREATER ] = rtl::OUString( sal_Unicode( '>' ) );
+ aKeyMap[ KEY_EQUAL ] = rtl::OUString( sal_Unicode( '=' ) );
+ aKeyMap[ KEY_OPEN ] = rtl::OUString( sal_Unicode( 0x23cf ) );
+
+ /* yet unmapped KEYCODES:
+ aKeyMap[ KEY_INSERT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_CUT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_COPY ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_PASTE ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_UNDO ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_REPEAT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_FIND ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_PROPERTIES ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_FRONT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_CONTEXTMENU ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_MENU ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_HELP ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_HANGUL_HANJA ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_DECIMAL ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_TILDE ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_QUOTELEFT ]= rtl::OUString( sal_Unicode( ) );
+ */
+
+ }
+
+ rtl::OUStringBuffer aResult( 16 );
+
+ USHORT nUnmodifiedCode = (nKeyCode & KEY_CODE);
+ std::map< USHORT, rtl::OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
+ if( it != aKeyMap.end() )
+ {
+ if( (nKeyCode & KEY_SHIFT) != 0 )
+ aResult.append( sal_Unicode( 0x21e7 ) );
+ if( (nKeyCode & KEY_MOD1) != 0 )
+ aResult.append( sal_Unicode( 0x2318 ) );
+ // we do not really handle Alt (see below)
+ // we map it to MOD3, whichis actually Command
+ if( (nKeyCode & (KEY_MOD2|KEY_MOD3)) != 0 )
+ aResult.append( sal_Unicode( 0x2303 ) );
+
+ aResult.append( it->second );
+ }
+
+ return aResult.makeStringAndClear();
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode )
+{
+ return GetKeyName( nKeyCode );
+}
+
+// -----------------------------------------------------------------------
+
+static void getAppleScrollBarVariant(void)
+{
+ bool bIsScrollbarDoubleMax = true; // default is DoubleMax
+
+ CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
+ if( AppleScrollBarType )
+ {
+ CFStringRef ScrollBarVariant = ((CFStringRef)CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
+ if( ScrollBarVariant )
+ {
+ if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
+ {
+ // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
+ CFStringRef DoubleMax = CFSTR("DoubleMax");
+ if (DoubleMax)
+ {
+ if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
+ bIsScrollbarDoubleMax = true;
+ else
+ bIsScrollbarDoubleMax = false;
+ CFRelease(DoubleMax);
+ }
+ }
+ CFRelease( ScrollBarVariant );
+ }
+ CFRelease(AppleScrollBarType);
+ }
+
+ GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
+
+ CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
+ if( jumpScroll )
+ {
+ CFBooleanRef jumpStr = ((CFBooleanRef)CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
+ if( jumpStr )
+ {
+ if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
+ ImplGetSVData()->maNWFData.mbScrollbarJumpPage = (jumpStr == kCFBooleanTrue);
+ CFRelease( jumpStr );
+ }
+ CFRelease( jumpScroll );
+ }
+}
+
+static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
+{
+ Color aRet( rDefault );
+ if( pSysColor )
+ {
+ // transform to RGB
+ NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
+ if( pRBGColor )
+ {
+ float r = 0, g = 0, b = 0, a = 0;
+ [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
+ aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
+ /*
+ do not release here; leads to duplicate free in yield
+ it seems the converted color comes out autoreleased, although this
+ is not documented
+ [pRBGColor release];
+ */
+ }
+ }
+ return aRet;
+}
+
+static Font getFont( NSFont* pFont, long nDPIY, const Font& rDefault )
+{
+ Font aResult( rDefault );
+ if( pFont )
+ {
+ aResult.SetName( GetOUString( [pFont familyName] ) );
+ aResult.SetHeight( static_cast<int>(([pFont pointSize] * 72.0 / (float)nDPIY)+0.5) );
+ aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
+ // FIMXE: bold ?
+ }
+
+ return aResult;
+}
+
+void AquaSalFrame::getResolution( long& o_rDPIX, long& o_rDPIY )
+{
+ if( ! mpGraphics )
+ {
+ GetGraphics();
+ ReleaseGraphics( mpGraphics );
+ }
+ mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
+}
+
+// on OSX-Aqua the style settings are independent of the frame, so it does
+// not really belong here. Since the connection to the Appearance_Manager
+// is currently done in salnativewidgets.cxx this would be a good place.
+// On the other hand VCL's platform independent code currently only asks
+// SalFrames for system settings anyway, so moving the code somewhere else
+// doesn't make the anything cleaner for now
+void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ [mpView lockFocus];
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+
+ // Background Color
+ Color aBackgroundColor = Color( 0xEC, 0xEC, 0xEC );
+ aStyleSettings.Set3DColors( aBackgroundColor );
+ aStyleSettings.SetFaceColor( aBackgroundColor );
+ Color aInactiveTabColor( aBackgroundColor );
+ aInactiveTabColor.DecreaseLuminance( 32 );
+ aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
+
+ aStyleSettings.SetDialogColor( aBackgroundColor );
+ aStyleSettings.SetLightBorderColor( aBackgroundColor );
+ Color aShadowColor( aStyleSettings.GetShadowColor() );
+ aStyleSettings.SetDarkShadowColor( aShadowColor );
+ aShadowColor.IncreaseLuminance( 32 );
+ aStyleSettings.SetShadowColor( aShadowColor );
+
+ // get the system font settings
+ Font aAppFont = aStyleSettings.GetAppFont();
+ long nDPIX = 72, nDPIY = 72;
+ getResolution( nDPIX, nDPIY );
+ aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
+
+ // TODO: better mapping of aqua<->ooo font settings
+ aStyleSettings.SetAppFont( aAppFont );
+ aStyleSettings.SetHelpFont( aAppFont );
+ aStyleSettings.SetPushButtonFont( aAppFont );
+
+ Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
+ aStyleSettings.SetTitleFont( aTitleFont );
+ aStyleSettings.SetFloatTitleFont( aTitleFont );
+
+ Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
+ aStyleSettings.SetMenuFont( aMenuFont );
+
+ aStyleSettings.SetToolFont( aAppFont );
+
+ Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
+ aStyleSettings.SetLabelFont( aLabelFont );
+ aStyleSettings.SetInfoFont( aLabelFont );
+ aStyleSettings.SetRadioCheckFont( aLabelFont );
+ aStyleSettings.SetFieldFont( aLabelFont );
+ aStyleSettings.SetGroupFont( aLabelFont );
+ aStyleSettings.SetIconFont( aLabelFont );
+
+ Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
+ aStyleSettings.GetHighlightColor(), mpWindow ) );
+ aStyleSettings.SetHighlightColor( aHighlightColor );
+ Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
+ aStyleSettings.GetHighlightTextColor(), mpWindow ) );
+ aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
+
+ Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
+ aStyleSettings.GetMenuHighlightColor(), mpWindow ) );
+ aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
+ Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
+ aStyleSettings.GetMenuHighlightTextColor(), mpWindow ) );
+ aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
+
+ aStyleSettings.SetMenuColor( aBackgroundColor );
+ Color aMenuTextColor( getColor( [NSColor textColor],
+ aStyleSettings.GetMenuTextColor(), mpWindow ) );
+ aStyleSettings.SetMenuTextColor( aMenuTextColor );
+ aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
+
+ aStyleSettings.SetCursorBlinkTime( 500 );
+
+ // no mnemonics on aqua
+ aStyleSettings.SetOptions( aStyleSettings.GetOptions() | STYLE_OPTION_NOMNEMONICS );
+
+ getAppleScrollBarVariant();
+
+ // set scrollbar size
+ aStyleSettings.SetScrollBarSize( static_cast<long int>([NSScroller scrollerWidth]) );
+
+ // images in menus false for MacOSX
+ aStyleSettings.SetUseImagesInMenus( false );
+
+ rSettings.SetStyleSettings( aStyleSettings );
+
+ [mpView unlockFocus];
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* AquaSalFrame::GetSystemData() const
+{
+ return &maSysData;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Beep( SoundType eSoundType )
+{
+ switch( eSoundType )
+ {
+ case SOUND_DISABLE:
+ // don't beep
+ break;
+ default:
+ NSBeep();
+ break;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, USHORT nFlags)
+{
+ USHORT nEvent = 0;
+
+ if( [mpWindow isMiniaturized] )
+ [mpWindow deminiaturize: NSApp]; // expand the window
+
+ if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
+ {
+ mbPositioned = true;
+ nEvent = SALEVENT_MOVE;
+ }
+
+ if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
+ {
+ mbSized = true;
+ nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE;
+ }
+
+ NSRect aFrameRect = [mpWindow frame];
+ NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
+
+ // position is always relative to parent frame
+ NSRect aParentContentRect;
+
+ if( mpParent )
+ {
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
+ nX = mpParent->maGeometry.nWidth - nWidth-1 - nX;
+ else
+ nX = mpParent->maGeometry.nWidth - static_cast<long int>( aContentRect.size.width-1) - nX;
+ }
+ NSRect aParentFrameRect = [mpParent->mpWindow frame];
+ aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
+ }
+ else
+ aParentContentRect = maScreenRect; // use screen if no parent
+
+ CocoaToVCL( aContentRect );
+ CocoaToVCL( aParentContentRect );
+
+ bool bPaint = false;
+ if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
+ {
+ if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
+ bPaint = true;
+ }
+
+ // use old window pos if no new pos requested
+ if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
+ aContentRect.origin.x = nX + aParentContentRect.origin.x;
+ if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
+ aContentRect.origin.y = nY + aParentContentRect.origin.y;
+
+ // use old size if no new size requested
+ if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
+ aContentRect.size.width = nWidth;
+ if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
+ aContentRect.size.height = nHeight;
+
+ VCLToCocoa( aContentRect );
+
+ // do not display yet, we need to update our backbuffer
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
+ }
+
+ UpdateFrameGeometry();
+
+ if (nEvent)
+ CallCallback(nEvent, NULL);
+
+ if( mbShown && bPaint )
+ {
+ // trigger filling our backbuffer
+ SendPaintEvent();
+
+ // now inform the system that the views need to be drawn
+ //YieldMutexReleaser aRel;
+ [mpWindow display];
+ }
+}
+
+void AquaSalFrame::GetWorkArea( Rectangle& rRect )
+{
+ NSScreen* pScreen = [mpWindow screen];
+ if( pScreen == nil )
+ pScreen = [NSScreen mainScreen];
+ NSRect aRect = [pScreen visibleFrame];
+ CocoaToVCL( aRect );
+ rRect.nLeft = static_cast<long>(aRect.origin.x);
+ rRect.nTop = static_cast<long>(aRect.origin.y);
+ rRect.nRight = static_cast<long>(aRect.origin.x + aRect.size.width - 1);
+ rRect.nBottom = static_cast<long>(aRect.origin.y + aRect.size.height - 1);
+}
+
+SalPointerState AquaSalFrame::GetPointerState()
+{
+ SalPointerState state;
+ state.mnState = 0;
+
+ // get position
+ NSPoint aPt = [mpWindow mouseLocationOutsideOfEventStream];
+ CocoaToVCL( aPt, false );
+ state.maPos = Point(static_cast<long>(aPt.x), static_cast<long>(aPt.y));
+
+ NSEvent* pCur = [NSApp currentEvent];
+ bool bMouseEvent = false;
+ if( pCur )
+ {
+ bMouseEvent = true;
+ switch( [pCur type] )
+ {
+ case NSLeftMouseDown: state.mnState |= MOUSE_LEFT; break;
+ case NSLeftMouseUp: break;
+ case NSRightMouseDown: state.mnState |= MOUSE_RIGHT; break;
+ case NSRightMouseUp: break;
+ case NSOtherMouseDown: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
+ case NSOtherMouseUp: break;
+ case NSMouseMoved: break;
+ case NSLeftMouseDragged: state.mnState |= MOUSE_LEFT; break;
+ case NSRightMouseDragged: state.mnState |= MOUSE_RIGHT; break;
+ case NSOtherMouseDragged: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
+ break;
+ default:
+ bMouseEvent = false;
+ break;
+ }
+ }
+ if( bMouseEvent )
+ {
+ unsigned int nMask = (unsigned int)[pCur modifierFlags];
+ if( (nMask & NSShiftKeyMask) != 0 )
+ state.mnState |= KEY_SHIFT;
+ if( (nMask & NSControlKeyMask) != 0 )
+ state.mnState |= KEY_MOD3;
+ if( (nMask & NSAlternateKeyMask) != 0 )
+ state.mnState |= KEY_MOD2;
+ if( (nMask & NSCommandKeyMask) != 0 )
+ state.mnState |= KEY_MOD1;
+
+ }
+ else
+ {
+ // FIXME: replace Carbon by Cocoa
+ // Cocoa does not have an equivalent for GetCurrentEventButtonState
+ // and GetCurrentEventKeyModifiers.
+ // we could try to get away with tracking all events for modifierKeys
+ // and all mouse events for button state in VCL_NSApllication::sendEvent,
+ // but it is unclear whether this will get us the same result.
+ // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
+
+ // fill in button state
+ UInt32 nState = GetCurrentEventButtonState();
+ state.mnState = 0;
+ if( nState & 1 )
+ state.mnState |= MOUSE_LEFT; // primary button
+ if( nState & 2 )
+ state.mnState |= MOUSE_RIGHT; // secondary button
+ if( nState & 4 )
+ state.mnState |= MOUSE_MIDDLE; // tertiary button
+
+ // fill in modifier state
+ nState = GetCurrentEventKeyModifiers();
+ if( nState & shiftKey )
+ state.mnState |= KEY_SHIFT;
+ if( nState & controlKey )
+ state.mnState |= KEY_MOD3;
+ if( nState & optionKey )
+ state.mnState |= KEY_MOD2;
+ if( nState & cmdKey )
+ state.mnState |= KEY_MOD1;
+ }
+
+
+ return state;
+}
+
+bool AquaSalFrame::SetPluginParent( SystemParentData* pNewParent )
+{
+ // plugin parent may be killed unexpectedly by
+ // plugging process;
+
+ //TODO: implement
+ return sal_False;
+}
+
+BOOL AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
+{
+ // not supported yet
+ return FALSE;
+}
+
+LanguageType AquaSalFrame::GetInputLanguage()
+{
+ //TODO: implement
+ return LANGUAGE_DONTKNOW;
+}
+
+void AquaSalFrame::DrawMenuBar()
+{
+}
+
+void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
+{
+ AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
+ DBG_ASSERT( ! pMenu || pMenu->mbMenuBar, "setting non menubar on frame" );
+ mpMenu = pMenu;
+ if( mpMenu )
+ mpMenu->setMainMenu();
+}
+
+void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+ if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
+ [mpWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
+ mnExtStyle = nStyle;
+}
+
+void AquaSalFrame::SetBackgroundBitmap( SalBitmap* )
+{
+ //TODO: implement
+}
+
+SalBitmap* AquaSalFrame::SnapShot()
+{
+ return mpGraphics ? mpGraphics->getBitmap( 0, 0, maGeometry.nWidth, maGeometry.nHeight ) : NULL;
+}
+
+SalFrame* AquaSalFrame::GetParent() const
+{
+ return mpParent;
+}
+
+void AquaSalFrame::SetParent( SalFrame* pNewParent )
+{
+ bool bShown = mbShown;
+ // remove from child list
+ Show( FALSE );
+ mpParent = (AquaSalFrame*)pNewParent;
+ // insert to correct parent and paint
+ Show( bShown );
+}
+
+void AquaSalFrame::UpdateFrameGeometry()
+{
+ // keep in mind that view and window coordinates are lower left
+ // whereas vcl's are upper left
+
+ // update screen rect
+ NSScreen * pScreen = [mpWindow screen];
+ if( pScreen )
+ {
+ maScreenRect = [pScreen frame];
+ NSArray* pScreens = [NSScreen screens];
+ if( pScreens )
+ maGeometry.nScreenNumber = [pScreens indexOfObject: pScreen];
+ }
+
+ NSRect aFrameRect = [mpWindow frame];
+ NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
+
+ // release old track rect
+ [mpView removeTrackingRect: mnTrackingRectTag];
+ // install the new track rect
+ NSRect aTrackRect = { { 0, 0 }, aContentRect.size };
+ mnTrackingRectTag = [mpView addTrackingRect: aTrackRect owner: mpView userData: nil assumeInside: NO];
+
+ // convert to vcl convention
+ CocoaToVCL( aFrameRect );
+ CocoaToVCL( aContentRect );
+
+ maGeometry.nX = static_cast<int>(aContentRect.origin.x);
+ maGeometry.nY = static_cast<int>(aContentRect.origin.y);
+
+ maGeometry.nLeftDecoration = static_cast<unsigned int>(aContentRect.origin.x - aFrameRect.origin.x);
+ maGeometry.nRightDecoration = static_cast<unsigned int>((aFrameRect.origin.x + aFrameRect.size.width) -
+ (aContentRect.origin.x + aContentRect.size.width));
+
+ maGeometry.nTopDecoration = static_cast<unsigned int>(aContentRect.origin.y - aFrameRect.origin.y);
+ maGeometry.nBottomDecoration = static_cast<unsigned int>((aFrameRect.origin.y + aFrameRect.size.height) -
+ (aContentRect.origin.y + aContentRect.size.height));
+
+ maGeometry.nWidth = static_cast<unsigned int>(aContentRect.size.width);
+ maGeometry.nHeight = static_cast<unsigned int>(aContentRect.size.height);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::CaptureMouse( BOOL bCapture )
+{
+ /* Remark:
+ we'll try to use a pidgin version of capture mouse
+ on MacOSX (neither carbon nor cocoa) there is a
+ CaptureMouse equivalent (in Carbon there is TrackMouseLocation
+ but this is useless to use since it is blocking)
+
+ However on cocoa the active frame seems to get mouse events
+ also outside the window, so we'll try to forward mouse events
+ to the capture frame in the hope that one of our frames
+ gets a mouse event.
+
+ This will break as soon as the user activates another app, but
+ a mouse click will normally lead to a release of the mouse anyway.
+
+ Let's see how far we get this way. Alternatively we could use one
+ large overlay window like we did for the carbon implementation,
+ however that is resource intensive.
+ */
+
+ if( bCapture )
+ s_pCaptureFrame = this;
+ else if( ! bCapture && s_pCaptureFrame == this )
+ s_pCaptureFrame = NULL;
+}
+
+void AquaSalFrame::ResetClipRegion()
+{
+ // release old path and indicate no clipping
+ CGPathRelease( mrClippingPath );
+ mrClippingPath = NULL;
+
+ if( mpView && mbShown )
+ [mpView setNeedsDisplay: YES];
+ if( mpWindow )
+ {
+ [mpWindow setOpaque: YES];
+ [mpWindow invalidateShadow];
+ }
+}
+
+void AquaSalFrame::BeginSetClipRegion( ULONG nRects )
+{
+ // release old path
+ if( mrClippingPath )
+ {
+ CGPathRelease( mrClippingPath );
+ mrClippingPath = NULL;
+ }
+
+ if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
+ {
+ std::vector<CGRect> aEmptyVec;
+ maClippingRects.swap( aEmptyVec );
+ }
+ maClippingRects.clear();
+ maClippingRects.reserve( nRects );
+}
+
+void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( nWidth && nHeight )
+ {
+ NSRect aRect = { { nX, nY }, { nWidth, nHeight } };
+ VCLToCocoa( aRect, false );
+ maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
+ }
+}
+
+void AquaSalFrame::EndSetClipRegion()
+{
+ if( ! maClippingRects.empty() )
+ {
+ mrClippingPath = CGPathCreateMutable();
+ CGPathAddRects( mrClippingPath, NULL, &maClippingRects[0], maClippingRects.size() );
+ }
+ if( mpView && mbShown )
+ [mpView setNeedsDisplay: YES];
+ if( mpWindow )
+ {
+ [mpWindow setOpaque: (mrClippingPath != NULL) ? NO : YES];
+ [mpWindow setBackgroundColor: [NSColor clearColor]];
+ // shadow is invalidated when view gets drawn again
+ }
+}
+
diff --git a/vcl/aqua/source/window/salframeview.mm b/vcl/aqua/source/window/salframeview.mm
new file mode 100755
index 000000000000..25dadf0e592b
--- /dev/null
+++ b/vcl/aqua/source/window/salframeview.mm
@@ -0,0 +1,1609 @@
+/*n***********************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salframeview.h"
+#include "aqua11yfactory.h"
+#include <sal/alloca.h>
+#include "vcl/window.hxx"
+
+#include "vcl/svapp.hxx"
+
+#define WHEEL_EVENT_FACTOR 1.5
+
+static USHORT ImplGetModifierMask( unsigned int nMask )
+{
+ USHORT nRet = 0;
+ if( (nMask & NSShiftKeyMask) != 0 )
+ nRet |= KEY_SHIFT;
+ if( (nMask & NSControlKeyMask) != 0 )
+ nRet |= KEY_MOD3;
+ if( (nMask & NSAlternateKeyMask) != 0 )
+ nRet |= KEY_MOD2;
+ if( (nMask & NSCommandKeyMask) != 0 )
+ nRet |= KEY_MOD1;
+ return nRet;
+}
+
+static USHORT ImplMapCharCode( sal_Unicode aCode )
+{
+ static USHORT aKeyCodeMap[ 128 ] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ KEY_BACKSPACE, KEY_TAB, KEY_RETURN, 0, 0, KEY_RETURN, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, KEY_TAB, 0, KEY_ESCAPE, 0, 0, 0, 0,
+ KEY_SPACE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, KEY_MULTIPLY, KEY_ADD, KEY_COMMA, KEY_SUBTRACT, KEY_POINT, KEY_DIVIDE,
+ KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
+ KEY_8, KEY_9, 0, 0, KEY_LESS, KEY_EQUAL, KEY_GREATER, 0,
+ 0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
+ KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
+ KEY_X, KEY_Y, KEY_Z, 0, 0, 0, 0, 0,
+ KEY_QUOTELEFT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
+ KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
+ KEY_X, KEY_Y, KEY_Z, 0, 0, 0, KEY_TILDE, KEY_BACKSPACE
+ };
+
+ // Note: the mapping 0x7f should by rights be KEY_DELETE
+ // however if you press "backspace" 0x7f is reported
+ // whereas for "delete" 0xf728 gets reported
+
+ // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons
+ // tab alone is reported as 0x09 (as expected) but shift-tab is
+ // reported as 0x19 (end of medium)
+
+ static USHORT aFunctionKeyCodeMap[ 128 ] =
+ {
+ KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
+ KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
+ KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
+ KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_F25, KEY_F26, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, KEY_INSERT,
+ KEY_DELETE, KEY_HOME, 0, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, 0, 0,
+ 0, 0, 0, 0, 0, KEY_MENU, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, KEY_UNDO, KEY_REPEAT, KEY_FIND, KEY_HELP, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ USHORT nKeyCode = 0;
+ if( aCode < sizeof( aKeyCodeMap) / sizeof( aKeyCodeMap[0] ) )
+ nKeyCode = aKeyCodeMap[ aCode ];
+ else if( aCode >= 0xf700 && aCode < 0xf780 )
+ nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ];
+ return nKeyCode;
+}
+
+// store the frame the mouse last entered
+static AquaSalFrame* s_pMouseFrame = NULL;
+// store the last pressed button for enter/exit events
+// which lack that information
+static USHORT s_nLastButton = 0;
+
+// combinations of keys we need to handle ourselves
+static const struct ExceptionalKey
+{
+ const USHORT nKeyCode;
+ const unsigned int nModifierMask;
+} aExceptionalKeys[] =
+{
+ { KEY_D, NSControlKeyMask | NSShiftKeyMask | NSAlternateKeyMask },
+ { KEY_D, NSCommandKeyMask | NSShiftKeyMask | NSAlternateKeyMask }
+};
+
+static AquaSalFrame* getMouseContainerFrame()
+{
+ int nWindows = 0;
+ NSCountWindows( &nWindows );
+ int* pWindows = (int*)alloca( nWindows * sizeof(int) );
+ // note: NSWindowList is supposed to be in z-order front to back
+ NSWindowList( nWindows, pWindows );
+ AquaSalFrame* pDispatchFrame = NULL;
+ for(int i = 0; i < nWindows && ! pDispatchFrame; i++ )
+ {
+ NSWindow* pWin = [NSApp windowWithWindowNumber: pWindows[i]];
+ if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [(SalFrameWindow*)pWin containsMouse] )
+ pDispatchFrame = [(SalFrameWindow*)pWin getSalFrame];
+ }
+ return pDispatchFrame;
+}
+
+@implementation SalFrameWindow
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame
+{
+ mDraggingDestinationHandler = nil;
+ mpFrame = pFrame;
+ NSRect aRect = { { pFrame->maGeometry.nX, pFrame->maGeometry.nY },
+ { pFrame->maGeometry.nWidth, pFrame->maGeometry.nHeight } };
+ pFrame->VCLToCocoa( aRect );
+ return [super initWithContentRect: aRect styleMask: mpFrame->getStyleMask() backing: NSBackingStoreBuffered defer: NO ];
+}
+
+-(AquaSalFrame*)getSalFrame
+{
+ return mpFrame;
+}
+
+-(MacOSBOOL)containsMouse
+{
+ // is this event actually inside that NSWindow ?
+ NSPoint aPt = [NSEvent mouseLocation];
+ NSRect aFrameRect = [self frame];
+ MacOSBOOL bInRect = NSPointInRect( aPt, aFrameRect );
+ return bInRect;
+}
+
+-(MacOSBOOL)canBecomeKeyWindow
+{
+ if( (mpFrame->mnStyle &
+ ( SAL_FRAME_STYLE_FLOAT |
+ SAL_FRAME_STYLE_TOOLTIP |
+ SAL_FRAME_STYLE_INTRO
+ )) == 0 )
+ return YES;
+ if( (mpFrame->mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) != 0 )
+ return YES;
+ if( mpFrame->mbFullScreen )
+ return YES;
+ if( (mpFrame->mnStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ return YES;
+ return [super canBecomeKeyWindow];
+}
+
+-(void)windowDidBecomeKey: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ static const ULONG nGuessDocument = SAL_FRAME_STYLE_MOVEABLE|
+ SAL_FRAME_STYLE_SIZEABLE|
+ SAL_FRAME_STYLE_CLOSEABLE;
+
+ if( mpFrame->mpMenu )
+ mpFrame->mpMenu->setMainMenu();
+ else if( ! mpFrame->mpParent &&
+ ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
+ mpFrame->mbFullScreen ) ) // ser default menu for e.g. presentation
+ {
+ AquaSalMenu::setDefaultMenu();
+ }
+ #if 0
+ // FIXME: we should disable menus while in modal mode
+ // however from down here there is currently no reliable way to
+ // find out when to do this
+ if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
+ AquaSalMenu::enableMainMenu( false );
+ #endif
+ mpFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
+ mpFrame->SendPaintEvent(); // repaint controls as active
+ }
+}
+
+-(void)windowDidResignKey: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->CallCallback(SALEVENT_LOSEFOCUS, 0);
+ mpFrame->SendPaintEvent(); // repaint controls as inactive
+ }
+}
+
+-(void)windowDidChangeScreen: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->screenParametersChanged();
+}
+
+-(void)windowDidMove: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_MOVE, 0 );
+ }
+}
+
+-(void)windowDidResize: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ mpFrame->SendPaintEvent();
+ }
+}
+
+-(void)windowDidMiniaturize: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mbShown = false;
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ }
+}
+
+-(void)windowDidDeminiaturize: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mbShown = true;
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ }
+}
+
+-(MacOSBOOL)windowShouldClose: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ MacOSBOOL bRet = YES;
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ // #i84461# end possible input
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->CallCallback( SALEVENT_CLOSE, 0 );
+ bRet = NO; // application will close the window or not, AppKit shouldn't
+ }
+ }
+
+ return bRet;
+}
+
+-(void)dockMenuItemTriggered: (id)sender
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->ToTop( SAL_FRAME_TOTOP_RESTOREWHENMIN | SAL_FRAME_TOTOP_GRABFOCUS );
+}
+
+-(::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >)accessibleContext
+{
+ return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
+}
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingEntered: sender];
+}
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingUpdated: sender];
+}
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler draggingExited: sender];
+}
+
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler prepareForDragOperation: sender];
+}
+
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler performDragOperation: sender];
+}
+
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler concludeDragOperation: sender];
+}
+
+-(void)registerDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = theHandler;
+}
+
+-(void)unregisterDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = nil;
+}
+
+@end
+
+@implementation SalFrameView
++(void)unsetMouseFrame: (AquaSalFrame*)pFrame
+{
+ if( pFrame == s_pMouseFrame )
+ s_pMouseFrame = NULL;
+}
+
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame
+{
+ if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
+ {
+ mDraggingDestinationHandler = nil;
+ mpFrame = pFrame;
+ mMarkedRange = NSMakeRange(NSNotFound, 0);
+ mSelectedRange = NSMakeRange(NSNotFound, 0);
+ mpReferenceWrapper = nil;
+ mpMouseEventListener = nil;
+ mpLastSuperEvent = nil;
+ }
+
+ return self;
+}
+
+-(void)resetCursorRects
+{
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
+ NSRect aRect = { { 0, 0 }, { mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight } };
+ [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
+ }
+}
+
+-(MacOSBOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+-(MacOSBOOL)acceptsFirstMouse: (NSEvent*)pEvent
+{
+ return YES;
+}
+
+-(MacOSBOOL)isOpaque
+{
+ return mpFrame ? (mpFrame->getClipPath() != 0 ? NO : YES) : YES;
+}
+
+// helper class similar to a vos::OGuard for the SalYieldMutex
+// the difference is that it only does tryToAcquire instead of aquire
+// so dreaded deadlocks like #i93512# are prevented
+class TryGuard
+{
+public:
+ TryGuard() { mbGuarded = ImplSalYieldMutexTryToAcquire(); }
+ ~TryGuard() { if( mbGuarded ) ImplSalYieldMutexRelease(); }
+ bool IsGuarded() { return mbGuarded; }
+private:
+ bool mbGuarded;
+};
+
+-(void)drawRect: (NSRect)aRect
+{
+ // HOTFIX: #i93512# prevent deadlocks if any other thread already has the SalYieldMutex
+ TryGuard aTryGuard;
+ if( !aTryGuard.IsGuarded() )
+ {
+ // NOTE: the mpFrame access below is not guarded yet!
+ // TODO: mpFrame et al need to be guarded by an independent mutex
+ AquaSalGraphics* pGraphics = (mpFrame && AquaSalFrame::isAlive(mpFrame)) ? mpFrame->mpGraphics : NULL;
+ if( pGraphics )
+ {
+ // we did not get the mutex so we cannot draw now => request to redraw later
+ // convert the NSRect to a CGRect for Refreshrect()
+ const CGRect aCGRect = {{aRect.origin.x,aRect.origin.y},{aRect.size.width,aRect.size.height}};
+ pGraphics->RefreshRect( aCGRect );
+ }
+ return;
+ }
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ if( mpFrame->mpGraphics )
+ {
+ mpFrame->mpGraphics->UpdateWindow( aRect );
+ if( mpFrame->getClipPath() )
+ [mpFrame->getWindow() invalidateShadow];
+ }
+ }
+}
+
+-(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(USHORT)nButton eventtype:(USHORT)nEvent
+{
+ YIELD_GUARD;
+
+ AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
+ bool bIsCaptured = false;
+ if( pDispatchFrame )
+ {
+ bIsCaptured = true;
+ if( nEvent == SALEVENT_MOUSELEAVE ) // no leave events if mouse is captured
+ nEvent = SALEVENT_MOUSEMOVE;
+ }
+ else if( s_pMouseFrame )
+ pDispatchFrame = s_pMouseFrame;
+ else
+ pDispatchFrame = mpFrame;
+
+ /* #i81645# Cocoa reports mouse events while a button is pressed
+ to the window in which it was first pressed. This is reasonable and fine and
+ gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
+ however vcl expects mouse events to occur in the window the mouse is over, unless the
+ mouse is explicitly captured. So we need to find the window the mouse is actually
+ over for conformance with other platforms.
+ */
+ if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
+ {
+ // is this event actually inside that NSWindow ?
+ NSPoint aPt = [NSEvent mouseLocation];
+ NSRect aFrameRect = [pDispatchFrame->getWindow() frame];
+
+ if ( ! NSPointInRect( aPt, aFrameRect ) )
+ {
+ // no, it is not
+ // now we need to find the one it may be in
+ /* #i93756# we ant to get enumerate the application windows in z-order
+ to check if any contains the mouse. This could be elegantly done with this
+ code:
+
+ // use NSApp to check windows in ZOrder whether they contain the mouse pointer
+ NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
+ if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
+ pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
+
+ However if a non SalFrameWindow is on screen (like e.g. the file dialog)
+ it can be hit with the containsMouse selector, which it doesn't support.
+ Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
+ I assume) whether a window supports a selector before sending it.
+ */
+ AquaSalFrame* pMouseFrame = getMouseContainerFrame();
+ if( pMouseFrame )
+ pDispatchFrame = pMouseFrame;
+ }
+ }
+
+ if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
+ {
+ pDispatchFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ pDispatchFrame->CocoaToVCL( aPt );
+
+ USHORT nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
+ // #i82284# emulate ctrl left
+ if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
+ {
+ nModMask = 0;
+ nButton = MOUSE_RIGHT;
+ }
+
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pDispatchFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY;
+ aEvent.mnButton = nButton;
+ aEvent.mnCode = aEvent.mnButton | nModMask;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ pDispatchFrame->CallCallback( nEvent, &aEvent );
+ }
+}
+
+-(void)mouseDown: (NSEvent*)pEvent
+{
+ if ( mpMouseEventListener != nil &&
+ [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
+ {
+ [mpMouseEventListener mouseDown: [pEvent copyWithZone: NULL]];
+ }
+
+ s_nLastButton = MOUSE_LEFT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONDOWN];
+}
+
+-(void)mouseDragged: (NSEvent*)pEvent
+{
+ if ( mpMouseEventListener != nil &&
+ [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
+ {
+ [mpMouseEventListener mouseDragged: [pEvent copyWithZone: NULL]];
+ }
+ s_nLastButton = MOUSE_LEFT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)mouseUp: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONUP];
+}
+
+-(void)mouseMoved: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ [self sendMouseEventToFrame:pEvent button:0 eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)mouseEntered: (NSEvent*)pEvent
+{
+ s_pMouseFrame = mpFrame;
+
+ [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)mouseExited: (NSEvent*)pEvent
+{
+ if( s_pMouseFrame == mpFrame )
+ s_pMouseFrame = NULL;
+
+ [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSELEAVE];
+}
+
+-(void)rightMouseDown: (NSEvent*)pEvent
+{
+ s_nLastButton = MOUSE_RIGHT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONDOWN];
+}
+
+-(void)rightMouseDragged: (NSEvent*)pEvent
+{
+ s_nLastButton = MOUSE_RIGHT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)rightMouseUp: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONUP];
+}
+
+-(void)otherMouseDown: (NSEvent*)pEvent
+{
+ if( [pEvent buttonNumber] == 2 )
+ {
+ s_nLastButton = MOUSE_MIDDLE;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONDOWN];
+ }
+ else
+ s_nLastButton = 0;
+}
+
+-(void)otherMouseDragged: (NSEvent*)pEvent
+{
+ if( [pEvent buttonNumber] == 2 )
+ {
+ s_nLastButton = MOUSE_MIDDLE;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEMOVE];
+ }
+ else
+ s_nLastButton = 0;
+}
+
+-(void)otherMouseUp: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ if( [pEvent buttonNumber] == 2 )
+ [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONUP];
+}
+
+- (void)magnifyWithEvent: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ // TODO: ?? -(float)magnification;
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ float dZ = 0.0;
+ for(;;)
+ {
+ dZ += [pEvent deltaZ];
+ NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
+ untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
+ if( !pNextEvent )
+ break;
+ pEvent = pNextEvent;
+ }
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ mpFrame->CocoaToVCL( aPt );
+
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
+ aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
+ aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling
+ aEvent.mbDeltaIsPixel = TRUE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ if( dZ != 0.0 )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dZ));
+ aEvent.mnNotchDelta = dZ < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = FALSE;
+ aEvent.mnScrollLines = dZ > 0 ? dZ/WHEEL_EVENT_FACTOR : -dZ/WHEEL_EVENT_FACTOR;
+ if( aEvent.mnScrollLines == 0 )
+ aEvent.mnScrollLines = 1;
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ }
+}
+
+- (void)rotateWithEvent: (NSEvent*)pEvent
+{
+ //Rotation : -(float)rotation;
+ // TODO: create new CommandType so rotation is available to the applications
+}
+
+- (void)swipeWithEvent: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ // merge pending scroll wheel events
+ float dX = 0.0;
+ float dY = 0.0;
+ for(;;)
+ {
+ dX += [pEvent deltaX];
+ dY += [pEvent deltaY];
+ NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
+ untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
+ if( !pNextEvent )
+ break;
+ pEvent = pNextEvent;
+ }
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ mpFrame->CocoaToVCL( aPt );
+
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
+ aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
+ aEvent.mbDeltaIsPixel = TRUE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ if( dX != 0.0 )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dX));
+ aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = TRUE;
+ aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dY));
+ aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = FALSE;
+ aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ }
+}
+
+-(void)scrollWheel: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ // merge pending scroll wheel events
+ float dX = 0.0;
+ float dY = 0.0;
+ for(;;)
+ {
+ dX += [pEvent deltaX];
+ dY += [pEvent deltaY];
+ NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
+ untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
+ if( !pNextEvent )
+ break;
+ pEvent = pNextEvent;
+ }
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ mpFrame->CocoaToVCL( aPt );
+
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
+ aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
+ aEvent.mbDeltaIsPixel = TRUE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ if( dX != 0.0 )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dX));
+ aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = TRUE;
+ aEvent.mnScrollLines = dY > 0 ? dX/WHEEL_EVENT_FACTOR : -dX/WHEEL_EVENT_FACTOR;
+ if( aEvent.mnScrollLines == 0 )
+ aEvent.mnScrollLines = 1;
+
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dY));
+ aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = FALSE;
+ aEvent.mnScrollLines = dY > 0 ? dY/WHEEL_EVENT_FACTOR : -dY/WHEEL_EVENT_FACTOR;
+ if( aEvent.mnScrollLines < 1 )
+ aEvent.mnScrollLines = 1;
+
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ }
+}
+
+
+-(void)keyDown: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpLastEvent = pEvent;
+ mbInKeyInput = true;
+ mbNeedSpecialKeyHandle = false;
+ mbKeyHandled = false;
+
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ if( ! [self handleKeyDownException: pEvent] )
+ {
+ NSArray* pArray = [NSArray arrayWithObject: pEvent];
+ [self interpretKeyEvents: pArray];
+ }
+
+ mbInKeyInput = false;
+ }
+}
+
+-(MacOSBOOL)handleKeyDownException:(NSEvent*)pEvent
+{
+ // check for a very special set of modified characters
+ NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
+
+ if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
+ {
+ /* #i103102# key events with command and alternate don't make it through
+ interpretKeyEvents (why ?). Try to dispatch them here first,
+ if not successful continue normally
+ */
+ if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
+ == (NSAlternateKeyMask | NSCommandKeyMask) )
+ {
+ if( [self sendSingleCharacter: mpLastEvent] )
+ return YES;
+ }
+ unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
+ USHORT nKeyCode = ImplMapCharCode( keyChar );
+
+ // Caution: should the table grow to more than 5 or 6 entries,
+ // we must consider moving it to a kind of hash map
+ const unsigned int nExceptions = sizeof( aExceptionalKeys ) / sizeof( aExceptionalKeys[0] );
+ for( unsigned int i = 0; i < nExceptions; i++ )
+ {
+ if( nKeyCode == aExceptionalKeys[i].nKeyCode &&
+ (mpFrame->mnLastModifierFlags & aExceptionalKeys[i].nModifierMask)
+ == aExceptionalKeys[i].nModifierMask )
+ {
+ [self sendKeyInputAndReleaseToFrame: nKeyCode character: 0];
+
+ return YES;
+ }
+ }
+ }
+ return NO;
+}
+
+-(void)flagsChanged: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+ }
+}
+
+-(void)insertText:(id)aString
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ NSString* pInsert = nil;
+ if( [aString isMemberOfClass: [NSAttributedString class]] )
+ pInsert = [aString string];
+ else
+ pInsert = aString;
+
+ int nLen = 0;
+ if( pInsert && ( nLen = [pInsert length] ) > 0 )
+ {
+ OUString aInsertString( GetOUString( pInsert ) );
+ // aCharCode initializer is safe since aInsertString will at least contain '\0'
+ sal_Unicode aCharCode = *aInsertString.getStr();
+
+ if( nLen == 1 &&
+ aCharCode < 0x80 &&
+ aCharCode > 0x1f &&
+ ! [self hasMarkedText ]
+ )
+ {
+ USHORT nKeyCode = ImplMapCharCode( aCharCode );
+ unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
+
+ // #i99567#
+ // find out the unmodified key code
+
+ // sanity check
+ if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
+ {
+ // get unmodified string
+ NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
+ if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
+ {
+ // map the unmodified key code
+ unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
+ nKeyCode = ImplMapCharCode( keyChar );
+ }
+ nLastModifiers = [mpLastEvent modifierFlags];
+
+ }
+ // #i99567#
+ // applications and vcl's edit fields ignore key events with ALT
+ // however we're at a place where we know text should be inserted
+ // so it seems we need to strip the Alt modifier here
+ if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
+ == NSAlternateKeyMask )
+ {
+ nLastModifiers = 0;
+ }
+ [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
+ }
+ else
+ {
+ SalExtTextInputEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.maText = aInsertString;
+ aEvent.mpTextAttr = NULL;
+ aEvent.mnCursorPos = aInsertString.getLength();
+ aEvent.mnDeltaStart = 0;
+ aEvent.mnCursorFlags = 0;
+ aEvent.mbOnlyCursor = FALSE;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+ }
+ }
+ else
+ {
+ SalExtTextInputEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.maText = String();
+ aEvent.mpTextAttr = NULL;
+ aEvent.mnCursorPos = 0;
+ aEvent.mnDeltaStart = 0;
+ aEvent.mnCursorFlags = 0;
+ aEvent.mbOnlyCursor = FALSE;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+
+ }
+ mbKeyHandled = true;
+ [self unmarkText];
+ }
+}
+
+-(void)insertTab: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
+}
+
+-(void)insertBacktab: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
+}
+
+-(void)moveLeft: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
+}
+
+-(void)moveLeftAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
+}
+
+-(void)moveBackwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveRight: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
+}
+
+-(void)moveRightAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
+}
+
+-(void)moveForwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordLeft: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordBackwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordLeftAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordRight: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordForwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordRightAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToRightEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToRightEndOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToLeftEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfParagraphAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphForwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphBackwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfDocument: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)scrollToEndOfDocument: (id)aSender
+{
+ // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfDocumentAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfDocument: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)scrollToBeginningOfDocument: (id)aSender
+{
+ // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveUp: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
+}
+
+-(void)moveDown: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
+}
+
+-(void)insertNewline: (id)aSender
+{
+ // #i91267# make enter and shift-enter work by evaluating the modifiers
+ [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
+}
+
+-(void)deleteBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
+}
+
+-(void)deleteForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
+}
+
+-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
+}
+
+-(void)deleteWordBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)deleteWordForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)deleteToBeginningOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)deleteToEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)deleteToBeginningOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)deleteToEndOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)insertLineBreak: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0];
+}
+
+-(void)insertParagraphSeparator: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)selectWord: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD character: 0 modifiers: 0];
+}
+
+-(void)selectLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_LINE character: 0 modifiers: 0];
+}
+
+-(void)selectParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)selectAll: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_ALL character: 0 modifiers: 0];
+}
+
+-(void)cancelOperation: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
+}
+
+-(void)noop: (id)aSender
+{
+ if( ! mbKeyHandled )
+ {
+ if( ! [self sendSingleCharacter:mpLastEvent] )
+ {
+ /* prevent recursion */
+ if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
+ {
+ id pLastSuperEvent = mpLastSuperEvent;
+ mpLastSuperEvent = mpLastEvent;
+ [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
+ mpLastSuperEvent = pLastSuperEvent;
+
+ std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
+ if( it != GetSalData()->maKeyEventAnswer.end() )
+ it->second = true;
+ }
+ }
+ }
+}
+
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar
+{
+ return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
+}
+
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
+{
+ return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
+ [self sendSingleCharacter: mpLastEvent];
+}
+
+-(MacOSBOOL)sendKeyToFrameDirect: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
+{
+ YIELD_GUARD;
+
+ long nRet = 0;
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ SalKeyEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnCode = nKeyCode | ImplGetModifierMask( nMod );
+ aEvent.mnCharCode = aChar;
+ aEvent.mnRepeat = FALSE;
+ nRet = mpFrame->CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
+ if( it != GetSalData()->maKeyEventAnswer.end() )
+ it->second = nRet ? true : false;
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->CallCallback( SALEVENT_KEYUP, &aEvent );
+ }
+ return nRet ? YES : NO;
+}
+
+
+-(MacOSBOOL)sendSingleCharacter: (NSEvent *)pEvent
+{
+ NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
+
+ if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
+ {
+ unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
+ USHORT nKeyCode = ImplMapCharCode( keyChar );
+ if( nKeyCode != 0 )
+ {
+ // don't send unicodes in the private use area
+ if( keyChar >= 0xf700 && keyChar < 0xf780 )
+ keyChar = 0;
+ MacOSBOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
+ mbInKeyInput = false;
+
+ return bRet;
+ }
+ }
+ return NO;
+}
+
+
+// NSTextInput protocol
+- (NSArray *)validAttributesForMarkedText
+{
+ return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
+}
+
+- (MacOSBOOL)hasMarkedText
+{
+ MacOSBOOL bHasMarkedText;
+
+ bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
+ ( mMarkedRange.length != 0 );
+ // hack to check keys like "Control-j"
+ if( mbInKeyInput )
+ {
+ mbNeedSpecialKeyHandle = true;
+ }
+
+ // FIXME:
+ // #i106901#
+ // if we come here outside of mbInKeyInput, this is likely to be because
+ // of the keyboard viewer. For unknown reasons having no marked range
+ // in this case causes a crash. So we say we have a marked range anyway
+ // This is a hack, since it is not understood what a) causes that crash
+ // and b) why we should have a marked range at this point.
+ if( ! mbInKeyInput )
+ bHasMarkedText = YES;
+
+ return bHasMarkedText;
+}
+
+- (NSRange)markedRange
+{
+ // FIXME:
+ // #i106901#
+ // if we come here outside of mbInKeyInput, this is likely to be because
+ // of the keyboard viewer. For unknown reasons having no marked range
+ // in this case causes a crash. So we say we have a marked range anyway
+ // This is a hack, since it is not understood what a) causes that crash
+ // and b) why we should have a marked range at this point.
+ if( ! mbInKeyInput )
+ return NSMakeRange( 0, 0 );
+
+ return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
+}
+
+- (NSRange)selectedRange
+{
+ return mSelectedRange;
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
+{
+ if( ![aString isKindOfClass:[NSAttributedString class]] )
+ aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
+ NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
+ if( rangeToReplace.location == NSNotFound )
+ {
+ mMarkedRange = NSMakeRange( selRange.location, [aString length] );
+ mSelectedRange = NSMakeRange( selRange.location, selRange.length );
+ }
+ else
+ {
+ mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
+ mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
+ }
+
+ int len = [aString length];
+ SalExtTextInputEvent aInputEvent;
+ aInputEvent.mnTime = mpFrame->mnLastEventTime;
+ aInputEvent.mnDeltaStart = 0;
+ aInputEvent.mbOnlyCursor = FALSE;
+ if( len > 0 ) {
+ NSString *pString = [aString string];
+ OUString aInsertString( GetOUString( pString ) );
+ std::vector<USHORT> aInputFlags = std::vector<USHORT>( std::max( 1, len ), 0 );
+ for ( int i = 0; i < len; i++ )
+ {
+ unsigned int nUnderlineValue;
+ NSRange effectiveRange;
+
+ effectiveRange = NSMakeRange(i, 1);
+ nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
+
+ switch (nUnderlineValue & 0xff) {
+ case NSUnderlineStyleSingle:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ break;
+ case NSUnderlineStyleThick:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_UNDERLINE | SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ break;
+ case NSUnderlineStyleDouble:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_BOLDUNDERLINE;
+ break;
+ default:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ break;
+ }
+ }
+
+ aInputEvent.maText = aInsertString;
+ aInputEvent.mnCursorPos = selRange.location;
+ aInputEvent.mpTextAttr = &aInputFlags[0];
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
+ } else {
+ aInputEvent.maText = String();
+ aInputEvent.mnCursorPos = 0;
+ aInputEvent.mnCursorFlags = 0;
+ aInputEvent.mpTextAttr = 0;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+ }
+ mbKeyHandled= true;
+}
+
+- (void)unmarkText
+{
+ mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
+}
+
+- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
+{
+ // FIXME
+ return nil;
+}
+
+- (unsigned int)characterIndexForPoint:(NSPoint)thePoint
+{
+ // FIXME
+ return 0;
+}
+
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+/* build target 10.5 or greater */
+- (NSInteger)conversationIdentifier
+#else
+/* build target 10.4 */
+- (long)conversationIdentifier
+#endif
+{
+ return (long)self;
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ // fprintf( stderr, "SalFrameView: doCommandBySelector %s\n", (char*)aSelector );
+ #endif
+ if( (mpFrame->mnICOptions & SAL_INPUTCONTEXT_TEXT) != 0 &&
+ aSelector != NULL && [self respondsToSelector: aSelector] )
+ {
+ [self performSelector: aSelector];
+ }
+ else
+ {
+ [self sendSingleCharacter:mpLastEvent];
+ }
+ }
+
+ mbKeyHandled = true;
+}
+
+-(void)clearLastEvent
+{
+ mpLastEvent = nil;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)theRange
+{
+ SalExtTextInputPosEvent aPosEvent;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void *)&aPosEvent );
+
+ NSRect rect;
+
+ rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
+ rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
+ rect.size.width = aPosEvent.mnWidth;
+ rect.size.height = aPosEvent.mnHeight;
+
+ mpFrame->VCLToCocoa( rect );
+ return rect;
+}
+
+-(id)parentAttribute {
+ return (NSView *) mpFrame -> mpWindow;
+}
+
+-(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext
+{
+ if ( mpReferenceWrapper == nil ) {
+ // some frames never become visible ..
+ Window *pWindow = mpFrame -> GetWindow();
+ if ( ! pWindow )
+ return nil;
+
+ mpReferenceWrapper = new ReferenceWrapper;
+ mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
+ [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
+ }
+ return [ super accessibleContext ];
+}
+
+-(NSView *)viewElementForParent
+{
+ return (NSView *) mpFrame -> mpWindow;
+}
+
+-(void)registerMouseEventListener: (id)theListener
+{
+ mpMouseEventListener = theListener;
+}
+
+-(void)unregisterMouseEventListener: (id)theListener
+{
+ mpMouseEventListener = nil;
+}
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingEntered: sender];
+}
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingUpdated: sender];
+}
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler draggingExited: sender];
+}
+
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler prepareForDragOperation: sender];
+}
+
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler performDragOperation: sender];
+}
+
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler concludeDragOperation: sender];
+}
+
+-(void)registerDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = theHandler;
+}
+
+-(void)unregisterDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = nil;
+}
+
+@end
+
diff --git a/vcl/aqua/source/window/salmenu.cxx b/vcl/aqua/source/window/salmenu.cxx
new file mode 100644
index 000000000000..ed3086d8506f
--- /dev/null
+++ b/vcl/aqua/source/window/salmenu.cxx
@@ -0,0 +1,958 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "saldata.hxx"
+#include "salinst.h"
+#include "salmenu.h"
+#include "salnsmenu.h"
+#include "salframe.h"
+#include "salbmp.h"
+#include "vcl/svids.hrc"
+#include "vcl/cmdevt.hxx"
+#include "vcl/floatwin.hxx"
+#include "vcl/window.h"
+#include "vcl/window.hxx"
+#include "vcl/svapp.hxx"
+
+#include "rtl/ustrbuf.hxx"
+#include "aqua11ywrapper.h"
+
+const AquaSalMenu* AquaSalMenu::pCurrentMenuBar = NULL;
+
+@interface MainMenuSelector : NSObject
+{
+}
+-(void)showDialog: (int)nDialog;
+-(void)showPreferences: (id)sender;
+-(void)showAbout: (id)sender;
+@end
+
+@implementation MainMenuSelector
+-(void)showDialog: (int)nDialog
+{
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const AquaSalFrame* pFrame = AquaSalMenu::pCurrentMenuBar->mpFrame;
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) )
+ {
+ pFrame->CallCallback( SALEVENT_SHOWDIALOG, reinterpret_cast<void*>(nDialog) );
+ }
+ }
+ else
+ {
+ String aDialog;
+ if( nDialog == SHOWDIALOG_ID_ABOUT )
+ aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "ABOUT" ) );
+ else if( nDialog == SHOWDIALOG_ID_PREFERENCES )
+ aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "PREFERENCES" ) );
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(),
+ ApplicationAddress(),
+ ByteString( "SHOWDIALOG" ),
+ aDialog );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ }
+}
+
+-(void)showPreferences: (id) sender
+{
+ [self showDialog: SHOWDIALOG_ID_PREFERENCES];
+}
+-(void)showAbout: (id) sender
+{
+ [self showDialog: SHOWDIALOG_ID_ABOUT];
+}
+@end
+
+
+// FIXME: currently this is leaked
+static MainMenuSelector* pMainMenuSelector = nil;
+
+static void initAppMenu()
+{
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+
+ ResMgr* pMgr = ImplGetResMgr();
+ if( pMgr )
+ {
+ // get the main menu
+ NSMenu* pMainMenu = [NSApp mainMenu];
+ if( pMainMenu != nil )
+ {
+ // create the action selector
+ pMainMenuSelector = [[MainMenuSelector alloc] init];
+
+ // get the proper submenu
+ NSMenu* pAppMenu = [[pMainMenu itemAtIndex: 0] submenu];
+ if( pAppMenu )
+ {
+ // insert about entry
+ String aAbout( ResId( SV_STDTEXT_ABOUT, *pMgr ) );
+ NSString* pString = CreateNSString( aAbout );
+ NSMenuItem* pNewItem = [pAppMenu insertItemWithTitle: pString
+ action: @selector(showAbout:)
+ keyEquivalent: @""
+ atIndex: 0];
+ if (pString)
+ [pString release];
+ if( pNewItem )
+ {
+ [pNewItem setTarget: pMainMenuSelector];
+ [pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
+ }
+
+ // insert preferences entry
+ String aPref( ResId( SV_STDTEXT_PREFERENCES, *pMgr ) );
+ pString = CreateNSString( aPref );
+ pNewItem = [pAppMenu insertItemWithTitle: pString
+ action: @selector(showPreferences:)
+ keyEquivalent: @","
+ atIndex: 2];
+ if (pString)
+ [pString release];
+ if( pNewItem )
+ {
+ [pNewItem setKeyEquivalentModifierMask: NSCommandKeyMask];
+ [pNewItem setTarget: pMainMenuSelector];
+ [pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
+ }
+
+ // WARNING: ultra ugly code ahead
+
+ // rename standard entries
+ // rename "Services"
+ pNewItem = [pAppMenu itemAtIndex: 4];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_SERVICES, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Hide NewApplication"
+ pNewItem = [pAppMenu itemAtIndex: 6];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEAPP, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Hide Others"
+ pNewItem = [pAppMenu itemAtIndex: 7];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEALL, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Show all"
+ pNewItem = [pAppMenu itemAtIndex: 8];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_SHOWALL, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Quit NewApplication"
+ pNewItem = [pAppMenu itemAtIndex: 10];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_QUITAPP, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+ }
+ }
+ }
+ }
+}
+
+// =======================================================================
+
+SalMenu* AquaSalInstance::CreateMenu( BOOL bMenuBar )
+{
+ initAppMenu();
+
+ AquaSalMenu *pAquaSalMenu = new AquaSalMenu( bMenuBar );
+
+ return pAquaSalMenu;
+}
+
+void AquaSalInstance::DestroyMenu( SalMenu* pSalMenu )
+{
+ delete pSalMenu;
+}
+
+SalMenuItem* AquaSalInstance::CreateMenuItem( const SalItemParams* pItemData )
+{
+ if( !pItemData )
+ return NULL;
+
+ AquaSalMenuItem *pSalMenuItem = new AquaSalMenuItem( pItemData );
+
+ return pSalMenuItem;
+}
+
+void AquaSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
+{
+ delete pSalMenuItem;
+}
+
+
+// =======================================================================
+
+
+/*
+ * AquaSalMenu
+ */
+
+AquaSalMenu::AquaSalMenu( bool bMenuBar ) :
+ mbMenuBar( bMenuBar ),
+ mpMenu( nil ),
+ mpVCLMenu( NULL ),
+ mpFrame( NULL ),
+ mpParentSalMenu( NULL )
+{
+ if( ! mbMenuBar )
+ {
+ mpMenu = [[SalNSMenu alloc] initWithMenu: this];
+ [mpMenu setDelegate: mpMenu];
+ }
+ else
+ {
+ mpMenu = [NSApp mainMenu];
+ }
+ [mpMenu setAutoenablesItems: NO];
+}
+
+AquaSalMenu::~AquaSalMenu()
+{
+ // actually someone should have done AquaSalFrame::SetMenu( NULL )
+ // on our frame, alas it is not so
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) && mpFrame->mpMenu == this )
+ const_cast<AquaSalFrame*>(mpFrame)->mpMenu = NULL;
+
+ // this should normally be empty already, but be careful...
+ for( size_t i = 0; i < maButtons.size(); i++ )
+ releaseButtonEntry( maButtons[i] );
+ maButtons.clear();
+
+ // is this leaking in some cases ? the release often leads to a duplicate release
+ // it seems the parent item gets ownership of the menu
+ if( mpMenu )
+ {
+ if( mbMenuBar )
+ {
+ if( pCurrentMenuBar == this )
+ {
+ // if the current menubar gets destroyed, set the default menubar
+ setDefaultMenu();
+ }
+ }
+ else
+ // the system may still hold a reference on mpMenu
+ {
+ // so set the pointer to this AquaSalMenu to NULL
+ // to protect from calling a dead object
+
+ // in ! mbMenuBar case our mpMenu is actually a SalNSMenu*
+ // so we can safely cast here
+ [static_cast<SalNSMenu*>(mpMenu) setSalMenu: NULL];
+ /* #i89860# FIXME:
+ using [autorelease] here (and in AquaSalMenuItem::~AquaSalMenuItem)
+ instead of [release] fixes an occasional crash. That should
+ indicate that we release menus / menu items in the wrong order
+ somewhere, but I could not find that case.
+ */
+ [mpMenu autorelease];
+ }
+ }
+}
+
+sal_Int32 removeUnusedItemsRunner(NSMenu * pMenu)
+{
+ NSArray * elements = [pMenu itemArray];
+ NSEnumerator * it = [elements objectEnumerator];
+ id elem;
+ NSMenuItem * lastDisplayedMenuItem = nil;
+ sal_Int32 drawnItems = 0;
+ bool firstEnabledItemIsNoSeparator = false;
+ while((elem=[it nextObject]) != nil) {
+ NSMenuItem * item = static_cast<NSMenuItem *>(elem);
+ if( (![item isEnabled] && ![item isSeparatorItem]) || ([item isSeparatorItem] && (lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem])) ) {
+ [[item menu]removeItem:item];
+ } else {
+ if( ! firstEnabledItemIsNoSeparator && [item isSeparatorItem] ) {
+ [[item menu]removeItem:item];
+ } else {
+ firstEnabledItemIsNoSeparator = true;
+ lastDisplayedMenuItem = item;
+ drawnItems++;
+ if( [item hasSubmenu] ) {
+ removeUnusedItemsRunner( [item submenu] );
+ }
+ }
+ }
+ }
+ if( lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem]) {
+ [[lastDisplayedMenuItem menu]removeItem:lastDisplayedMenuItem];
+ }
+ return drawnItems;
+}
+
+bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, ULONG nFlags)
+{
+ // do not use native popup menu when AQUA_NATIVE_MENUS is set to FALSE
+ if( ! VisibleMenuBar() ) {
+ return false;
+ }
+
+ // set offsets for positioning
+ const float offset = 9.0;
+
+ // get the pointers
+ AquaSalFrame * pParentAquaSalFrame = (AquaSalFrame *) pWin->ImplGetWindowImpl()->mpRealParent->ImplGetFrame();
+ NSWindow * pParentNSWindow = pParentAquaSalFrame->mpWindow;
+ NSView * pParentNSView = [pParentNSWindow contentView];
+ NSView * pPopupNSView = ((AquaSalFrame *) pWin->ImplGetWindow()->ImplGetFrame())->mpView;
+ NSRect popupFrame = [pPopupNSView frame];
+
+ // since we manipulate the menu below (removing entries)
+ // let's rather make a copy here and work with that
+ NSMenu* pCopyMenu = [mpMenu copy];
+
+ // filter disabled elements
+ removeUnusedItemsRunner( pCopyMenu );
+
+ // create frame rect
+ NSRect displayPopupFrame = NSMakeRect( rRect.nLeft+(offset-1), rRect.nTop+(offset+1), popupFrame.size.width, 0 );
+ pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false);
+
+ // do the same strange semantics as vcl popup windows to arrive at a frame geometry
+ // in mirrored UI case; best done by actually executing the same code
+ USHORT nArrangeIndex;
+ pWin->SetPosPixel( pWin->ImplCalcPos( pWin, rRect, nFlags, nArrangeIndex ) );
+ displayPopupFrame.origin.x = pWin->ImplGetFrame()->maGeometry.nX - pParentAquaSalFrame->maGeometry.nX + offset;
+ displayPopupFrame.origin.y = pWin->ImplGetFrame()->maGeometry.nY - pParentAquaSalFrame->maGeometry.nY + offset;
+ pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false);
+
+ // #i111992# if this menu was opened due to a key event, prevent dispatching that yet again
+ if( [pParentNSView respondsToSelector: @selector(clearLastEvent)] )
+ [pParentNSView performSelector:@selector(clearLastEvent)];
+
+ // open popup menu
+ NSPopUpButtonCell * pPopUpButtonCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
+ [pPopUpButtonCell setMenu: pCopyMenu];
+ [pPopUpButtonCell selectItem:nil];
+ [AquaA11yWrapper setPopupMenuOpen: YES];
+ [pPopUpButtonCell performClickWithFrame:displayPopupFrame inView:pParentNSView];
+ [pPopUpButtonCell release];
+ [AquaA11yWrapper setPopupMenuOpen: NO];
+
+ // clean up the copy
+ [pCopyMenu release];
+ return true;
+}
+
+int AquaSalMenu::getItemIndexByPos( USHORT nPos ) const
+{
+ int nIndex = 0;
+ if( nPos == MENU_APPEND )
+ nIndex = [mpMenu numberOfItems];
+ else
+ nIndex = sal::static_int_cast<int>( mbMenuBar ? nPos+1 : nPos );
+ return nIndex;
+}
+
+const AquaSalFrame* AquaSalMenu::getFrame() const
+{
+ const AquaSalMenu* pMenu = this;
+ while( pMenu && ! pMenu->mpFrame )
+ pMenu = pMenu->mpParentSalMenu;
+ return pMenu ? pMenu->mpFrame : NULL;
+}
+
+void AquaSalMenu::unsetMainMenu()
+{
+ pCurrentMenuBar = NULL;
+
+ // remove items from main menu
+ NSMenu* pMenu = [NSApp mainMenu];
+ for( int nItems = [pMenu numberOfItems]; nItems > 1; nItems-- )
+ [pMenu removeItemAtIndex: 1];
+}
+
+void AquaSalMenu::setMainMenu()
+{
+ DBG_ASSERT( mbMenuBar, "setMainMenu on non menubar" );
+ if( mbMenuBar )
+ {
+ if( pCurrentMenuBar != this )
+ {
+ unsetMainMenu();
+ // insert our items
+ for( unsigned int i = 0; i < maItems.size(); i++ )
+ {
+ NSMenuItem* pItem = maItems[i]->mpMenuItem;
+ [mpMenu insertItem: pItem atIndex: i+1];
+ }
+ pCurrentMenuBar = this;
+
+ // change status item
+ statusLayout();
+ }
+ enableMainMenu( true );
+ }
+}
+
+void AquaSalMenu::setDefaultMenu()
+{
+ NSMenu* pMenu = [NSApp mainMenu];
+
+ unsetMainMenu();
+
+ // insert default items
+ std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
+ for( unsigned int i = 0, nAddItems = rFallbackMenu.size(); i < nAddItems; i++ )
+ {
+ NSMenuItem* pItem = rFallbackMenu[i];
+ if( [pItem menu] == nil )
+ [pMenu insertItem: pItem atIndex: i+1];
+ }
+}
+
+void AquaSalMenu::enableMainMenu( bool bEnable )
+{
+ NSMenu* pMainMenu = [NSApp mainMenu];
+ if( pMainMenu )
+ {
+ // enable/disable items from main menu
+ int nItems = [pMainMenu numberOfItems];
+ for( int n = 1; n < nItems; n++ )
+ {
+ NSMenuItem* pItem = [pMainMenu itemAtIndex: n];
+ [pItem setEnabled: bEnable ? YES : NO];
+ }
+ }
+}
+
+void AquaSalMenu::addFallbackMenuItem( NSMenuItem* pNewItem )
+{
+ initAppMenu();
+
+ std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
+
+ // prevent duplicate insertion
+ int nItems = rFallbackMenu.size();
+ for( int i = 0; i < nItems; i++ )
+ {
+ if( rFallbackMenu[i] == pNewItem )
+ return;
+ }
+
+ // push the item to the back and retain it
+ [pNewItem retain];
+ rFallbackMenu.push_back( pNewItem );
+
+ if( pCurrentMenuBar == NULL )
+ setDefaultMenu();
+}
+
+void AquaSalMenu::removeFallbackMenuItem( NSMenuItem* pOldItem )
+{
+ std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
+
+ // find item
+ unsigned int nItems = rFallbackMenu.size();
+ for( unsigned int i = 0; i < nItems; i++ )
+ {
+ if( rFallbackMenu[i] == pOldItem )
+ {
+ // remove item and release
+ rFallbackMenu.erase( rFallbackMenu.begin() + i );
+ [pOldItem release];
+
+ if( pCurrentMenuBar == NULL )
+ setDefaultMenu();
+
+ return;
+ }
+ }
+}
+
+BOOL AquaSalMenu::VisibleMenuBar()
+{
+ // Enable/disable experimental native menus code?
+ //
+ // To disable native menus, set the environment variable AQUA_NATIVE_MENUS to FALSE
+
+ static const char *pExperimental = getenv ("AQUA_NATIVE_MENUS");
+
+ if ( ImplGetSVData()->mbIsTestTool || (pExperimental && !strcasecmp(pExperimental, "FALSE")) )
+ return FALSE;
+
+ // End of experimental code enable/disable part
+
+ return TRUE;
+}
+
+void AquaSalMenu::SetFrame( const SalFrame *pFrame )
+{
+ mpFrame = static_cast<const AquaSalFrame*>(pFrame);
+}
+
+void AquaSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
+{
+ AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem);
+
+ pAquaSalMenuItem->mpParentMenu = this;
+ DBG_ASSERT( pAquaSalMenuItem->mpVCLMenu == NULL ||
+ pAquaSalMenuItem->mpVCLMenu == mpVCLMenu ||
+ mpVCLMenu == NULL,
+ "resetting menu ?" );
+ if( pAquaSalMenuItem->mpVCLMenu )
+ mpVCLMenu = pAquaSalMenuItem->mpVCLMenu;
+
+ if( nPos == MENU_APPEND || nPos == maItems.size() )
+ maItems.push_back( pAquaSalMenuItem );
+ else if( nPos < maItems.size() )
+ maItems.insert( maItems.begin() + nPos, pAquaSalMenuItem );
+ else
+ {
+ DBG_ERROR( "invalid item index in insert" );
+ return;
+ }
+
+ if( ! mbMenuBar || pCurrentMenuBar == this )
+ [mpMenu insertItem: pAquaSalMenuItem->mpMenuItem atIndex: getItemIndexByPos(nPos)];
+}
+
+void AquaSalMenu::RemoveItem( unsigned nPos )
+{
+ AquaSalMenuItem* pRemoveItem = NULL;
+ if( nPos == MENU_APPEND || nPos == (maItems.size()-1) )
+ {
+ pRemoveItem = maItems.back();
+ maItems.pop_back();
+ }
+ else if( nPos < maItems.size() )
+ {
+ pRemoveItem = maItems[ nPos ];
+ maItems.erase( maItems.begin()+nPos );
+ }
+ else
+ {
+ DBG_ERROR( "invalid item index in remove" );
+ return;
+ }
+
+ pRemoveItem->mpParentMenu = NULL;
+
+ if( ! mbMenuBar || pCurrentMenuBar == this )
+ [mpMenu removeItemAtIndex: getItemIndexByPos(nPos)];
+}
+
+void AquaSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
+{
+ AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem);
+ AquaSalMenu *subAquaSalMenu = static_cast<AquaSalMenu*>(pSubMenu);
+
+ if (subAquaSalMenu)
+ {
+ pAquaSalMenuItem->mpSubMenu = subAquaSalMenu;
+ if( subAquaSalMenu->mpParentSalMenu == NULL )
+ {
+ subAquaSalMenu->mpParentSalMenu = this;
+ [pAquaSalMenuItem->mpMenuItem setSubmenu: subAquaSalMenu->mpMenu];
+
+ // set title of submenu
+ [subAquaSalMenu->mpMenu setTitle: [pAquaSalMenuItem->mpMenuItem title]];
+ }
+ else if( subAquaSalMenu->mpParentSalMenu != this )
+ {
+ // cocoa doesn't allow menus to be submenus of multiple
+ // menu items, so place a copy in the menu item instead ?
+ // let's hope that NSMenu copy does the right thing
+ NSMenu* pCopy = [subAquaSalMenu->mpMenu copy];
+ [pAquaSalMenuItem->mpMenuItem setSubmenu: pCopy];
+
+ // set title of submenu
+ [pCopy setTitle: [pAquaSalMenuItem->mpMenuItem title]];
+ }
+ }
+ else
+ {
+ if( pAquaSalMenuItem->mpSubMenu )
+ {
+ if( pAquaSalMenuItem->mpSubMenu->mpParentSalMenu == this )
+ pAquaSalMenuItem->mpSubMenu->mpParentSalMenu = NULL;
+ }
+ pAquaSalMenuItem->mpSubMenu = NULL;
+ [pAquaSalMenuItem->mpMenuItem setSubmenu: nil];
+ }
+}
+
+void AquaSalMenu::CheckItem( unsigned nPos, BOOL bCheck )
+{
+ if( nPos < maItems.size() )
+ {
+ NSMenuItem* pItem = maItems[nPos]->mpMenuItem;
+ [pItem setState: bCheck ? NSOnState : NSOffState];
+ }
+}
+
+void AquaSalMenu::EnableItem( unsigned nPos, BOOL bEnable )
+{
+ if( nPos < maItems.size() )
+ {
+ NSMenuItem* pItem = maItems[nPos]->mpMenuItem;
+ [pItem setEnabled: bEnable ? YES : NO];
+ }
+}
+
+void AquaSalMenu::SetItemImage( unsigned nPos, SalMenuItem* pSMI, const Image& rImage )
+{
+ AquaSalMenuItem* pSalMenuItem = static_cast<AquaSalMenuItem*>( pSMI );
+ if( ! pSalMenuItem || ! pSalMenuItem->mpMenuItem )
+ return;
+
+ NSImage* pImage = CreateNSImage( rImage );
+
+ [pSalMenuItem->mpMenuItem setImage: pImage];
+ if( pImage )
+ [pImage release];
+}
+
+void AquaSalMenu::SetItemText( unsigned i_nPos, SalMenuItem* i_pSalMenuItem, const XubString& i_rText )
+{
+ if (!i_pSalMenuItem)
+ return;
+
+ AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) i_pSalMenuItem;
+
+ String aText( i_rText );
+
+ // Delete mnemonics
+ aText.EraseAllChars( '~' );
+
+ /* #i90015# until there is a correct solution
+ strip out any appended (.*) in menubar entries
+ */
+ if( mbMenuBar )
+ {
+ xub_StrLen nPos = aText.SearchBackward( sal_Unicode( '(' ) );
+ if( nPos != STRING_NOTFOUND )
+ {
+ xub_StrLen nPos2 = aText.Search( sal_Unicode( ')' ) );
+ if( nPos2 != STRING_NOTFOUND )
+ aText.Erase( nPos, nPos2-nPos+1 );
+ }
+ }
+
+ NSString* pString = CreateNSString( aText );
+ if (pString)
+ {
+ [pAquaSalMenuItem->mpMenuItem setTitle: pString];
+ // if the menu item has a submenu, change its title as well
+ if (pAquaSalMenuItem->mpSubMenu)
+ [pAquaSalMenuItem->mpSubMenu->mpMenu setTitle: pString];
+ [pString release];
+ }
+}
+
+void AquaSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName )
+{
+ USHORT nModifier;
+ sal_Unicode nCommandKey = 0;
+
+ USHORT nKeyCode=rKeyCode.GetCode();
+ if( nKeyCode )
+ {
+ if ((nKeyCode>=KEY_A) && (nKeyCode<=KEY_Z)) // letter A..Z
+ nCommandKey = nKeyCode-KEY_A + 'a';
+ else if ((nKeyCode>=KEY_0) && (nKeyCode<=KEY_9)) // numbers 0..9
+ nCommandKey = nKeyCode-KEY_0 + '0';
+ else if ((nKeyCode>=KEY_F1) && (nKeyCode<=KEY_F26)) // function keys F1..F26
+ nCommandKey = nKeyCode-KEY_F1 + NSF1FunctionKey;
+ else if( nKeyCode == KEY_REPEAT )
+ nCommandKey = NSRedoFunctionKey;
+ else if( nKeyCode == KEY_SPACE )
+ nCommandKey = ' ';
+ else
+ {
+ switch (nKeyCode)
+ {
+ case KEY_ADD:
+ nCommandKey='+';
+ break;
+ case KEY_SUBTRACT:
+ nCommandKey='-';
+ break;
+ case KEY_MULTIPLY:
+ nCommandKey='*';
+ break;
+ case KEY_DIVIDE:
+ nCommandKey='/';
+ break;
+ case KEY_POINT:
+ nCommandKey='.';
+ break;
+ case KEY_LESS:
+ nCommandKey='<';
+ break;
+ case KEY_GREATER:
+ nCommandKey='>';
+ break;
+ case KEY_EQUAL:
+ nCommandKey='=';
+ break;
+ }
+ }
+ }
+ else // not even a code ? nonsense -> ignore
+ return;
+
+ DBG_ASSERT( nCommandKey, "unmapped accelerator key" );
+
+ nModifier=rKeyCode.GetAllModifier();
+
+ // should always use the command key
+ int nItemModifier = 0;
+
+ if (nModifier & KEY_SHIFT)
+ {
+ nItemModifier |= NSShiftKeyMask; // actually useful only for function keys
+ if( nKeyCode >= KEY_A && nKeyCode <= KEY_Z )
+ nCommandKey = nKeyCode - KEY_A + 'A';
+ }
+
+ if (nModifier & KEY_MOD1)
+ nItemModifier |= NSCommandKeyMask;
+
+ if(nModifier & KEY_MOD2)
+ nItemModifier |= NSAlternateKeyMask;
+
+ if(nModifier & KEY_MOD3)
+ nItemModifier |= NSControlKeyMask;
+
+ AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) pSalMenuItem;
+ NSString* pString = CreateNSString( rtl::OUString( &nCommandKey, 1 ) );
+ [pAquaSalMenuItem->mpMenuItem setKeyEquivalent: pString];
+ [pAquaSalMenuItem->mpMenuItem setKeyEquivalentModifierMask: nItemModifier];
+ if (pString)
+ [pString release];
+}
+
+void AquaSalMenu::GetSystemMenuData( SystemMenuData* pData )
+{
+}
+
+AquaSalMenu::MenuBarButtonEntry* AquaSalMenu::findButtonItem( USHORT i_nItemId )
+{
+ for( size_t i = 0; i < maButtons.size(); ++i )
+ {
+ if( maButtons[i].maButton.mnId == i_nItemId )
+ return &maButtons[i];
+ }
+ return NULL;
+}
+
+void AquaSalMenu::statusLayout()
+{
+ if( GetSalData()->mpStatusItem )
+ {
+ NSView* pView = [GetSalData()->mpStatusItem view];
+ if( [pView isMemberOfClass: [OOStatusItemView class]] ) // well of course it is
+ [(OOStatusItemView*)pView layout];
+ else
+ DBG_ERROR( "someone stole our status view" );
+ }
+}
+
+void AquaSalMenu::releaseButtonEntry( MenuBarButtonEntry& i_rEntry )
+{
+ if( i_rEntry.mpNSImage )
+ {
+ [i_rEntry.mpNSImage release];
+ i_rEntry.mpNSImage = nil;
+ }
+ if( i_rEntry.mpToolTipString )
+ {
+ [i_rEntry.mpToolTipString release];
+ i_rEntry.mpToolTipString = nil;
+ }
+}
+
+bool AquaSalMenu::AddMenuBarButton( const SalMenuButtonItem& i_rNewItem )
+{
+ if( ! mbMenuBar || ! VisibleMenuBar() )
+ return false;
+
+ MenuBarButtonEntry* pEntry = findButtonItem( i_rNewItem.mnId );
+ if( pEntry )
+ {
+ releaseButtonEntry( *pEntry );
+ pEntry->maButton = i_rNewItem;
+ pEntry->mpNSImage = CreateNSImage( i_rNewItem.maImage );
+ if( i_rNewItem.maToolTipText.getLength() )
+ pEntry->mpToolTipString = CreateNSString( i_rNewItem.maToolTipText );
+ }
+ else
+ {
+ maButtons.push_back( MenuBarButtonEntry( i_rNewItem ) );
+ maButtons.back().mpNSImage = CreateNSImage( i_rNewItem.maImage );
+ maButtons.back().mpToolTipString = CreateNSString( i_rNewItem.maToolTipText );
+ }
+
+ // lazy create status item
+ SalData::getStatusItem();
+
+ if( pCurrentMenuBar == this )
+ statusLayout();
+
+ return true;
+}
+
+void AquaSalMenu::RemoveMenuBarButton( USHORT i_nId )
+{
+ MenuBarButtonEntry* pEntry = findButtonItem( i_nId );
+ if( pEntry )
+ {
+ releaseButtonEntry( *pEntry );
+ // note: vector guarantees that its contents are in a plain array
+ maButtons.erase( maButtons.begin() + (pEntry - &maButtons[0]) );
+ }
+
+ if( pCurrentMenuBar == this )
+ statusLayout();
+}
+
+Rectangle AquaSalMenu::GetMenuBarButtonRectPixel( USHORT i_nItemId, SalFrame* i_pReferenceFrame )
+{
+ if( GetSalData()->mnSystemVersion < VER_LEOPARD )
+ return Rectangle( Point( -1, -1 ), Size( 1, 1 ) );
+
+ if( ! i_pReferenceFrame || ! AquaSalFrame::isAlive( static_cast<AquaSalFrame*>(i_pReferenceFrame) ) )
+ return Rectangle();
+
+ MenuBarButtonEntry* pEntry = findButtonItem( i_nItemId );
+
+ if( ! pEntry )
+ return Rectangle();
+
+ NSStatusItem* pItem = SalData::getStatusItem();
+ if( ! pItem )
+ return Rectangle();
+
+ NSView* pView = [pItem view];
+ if( ! pView )
+ return Rectangle();
+ NSWindow* pWin = [pView window];
+ if( ! pWin )
+ return Rectangle();
+
+ NSRect aRect = [pWin frame];
+ aRect.origin = [pWin convertBaseToScreen: NSMakePoint( 0, 0 )];
+
+ // make coordinates relative to reference frame
+ static_cast<AquaSalFrame*>(i_pReferenceFrame)->CocoaToVCL( aRect.origin );
+ aRect.origin.x -= i_pReferenceFrame->maGeometry.nX;
+ aRect.origin.y -= i_pReferenceFrame->maGeometry.nY + aRect.size.height;
+
+ return Rectangle( Point(static_cast<long int>(aRect.origin.x),
+ static_cast<long int>(aRect.origin.y)
+ ),
+ Size( static_cast<long int>(aRect.size.width),
+ static_cast<long int>(aRect.size.height)
+ )
+ );
+}
+
+// =======================================================================
+
+/*
+ * SalMenuItem
+ */
+
+AquaSalMenuItem::AquaSalMenuItem( const SalItemParams* pItemData ) :
+ mnId( pItemData->nId ),
+ mpVCLMenu( pItemData->pMenu ),
+ mpParentMenu( NULL ),
+ mpSubMenu( NULL ),
+ mpMenuItem( nil )
+{
+ String aText( pItemData->aText );
+
+ // Delete mnemonics
+ aText.EraseAllChars( '~' );
+
+ if (pItemData->eType == MENUITEM_SEPARATOR)
+ {
+ mpMenuItem = [NSMenuItem separatorItem];
+ // these can go occasionally go in and out of a menu, ensure their lifecycle
+ // also for the release in AquaSalMenuItem destructor
+ [mpMenuItem retain];
+ }
+ else
+ {
+ mpMenuItem = [[SalNSMenuItem alloc] initWithMenuItem: this];
+ [mpMenuItem setEnabled: YES];
+ NSString* pString = CreateNSString( aText );
+ if (pString)
+ {
+ [mpMenuItem setTitle: pString];
+ [pString release];
+ }
+ // anything but a separator should set a menu to dispatch to
+ DBG_ASSERT( mpVCLMenu, "no menu" );
+ }
+}
+
+AquaSalMenuItem::~AquaSalMenuItem()
+{
+ /* #i89860# FIXME:
+ using [autorelease] here (and in AquaSalMenu:::~AquaSalMenu) instead of
+ [release] fixes an occasional crash. That should indicate that we release
+ menus / menu items in the wrong order somewhere, but I
+ could not find that case.
+ */
+ if( mpMenuItem )
+ [mpMenuItem autorelease];
+}
+
+// -------------------------------------------------------------------
+
diff --git a/vcl/aqua/source/window/salnsmenu.mm b/vcl/aqua/source/window/salnsmenu.mm
new file mode 100755
index 000000000000..015c43aed70f
--- /dev/null
+++ b/vcl/aqua/source/window/salnsmenu.mm
@@ -0,0 +1,213 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "saldata.hxx"
+#include "salframe.h"
+#include "salmenu.h"
+#include "salnsmenu.h"
+
+#include "vcl/window.hxx"
+
+@implementation SalNSMenu
+-(id)initWithMenu: (AquaSalMenu*)pMenu
+{
+ mpMenu = pMenu;
+ return [super initWithTitle: [NSString string]];
+}
+
+-(void)menuNeedsUpdate: (NSMenu*)pMenu
+{
+ YIELD_GUARD;
+
+ if( mpMenu )
+ {
+ const AquaSalFrame* pFrame = mpMenu->getFrame();
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) )
+ {
+ SalMenuEvent aMenuEvt;
+ aMenuEvt.mnId = 0;
+ aMenuEvt.mpMenu = mpMenu->mpVCLMenu;
+ if( aMenuEvt.mpMenu )
+ {
+ pFrame->CallCallback(SALEVENT_MENUACTIVATE, &aMenuEvt);
+ pFrame->CallCallback(SALEVENT_MENUDEACTIVATE, &aMenuEvt);
+ }
+ else
+ DBG_ERROR( "unconnected menu" );
+ }
+ }
+}
+
+-(void)setSalMenu: (AquaSalMenu*)pMenu
+{
+ mpMenu = pMenu;
+}
+@end
+
+@implementation SalNSMenuItem
+-(id)initWithMenuItem: (AquaSalMenuItem*)pMenuItem
+{
+ mpMenuItem = pMenuItem;
+ id ret = [super initWithTitle: [NSString string]
+ action: @selector(menuItemTriggered:)
+ keyEquivalent: [NSString string]];
+ [ret setTarget: self];
+ return ret;
+}
+-(void)menuItemTriggered: (id)aSender
+{
+ YIELD_GUARD;
+
+ const AquaSalFrame* pFrame = mpMenuItem->mpParentMenu ? mpMenuItem->mpParentMenu->getFrame() : NULL;
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) && ! pFrame->GetWindow()->IsInModalMode() )
+ {
+ SalMenuEvent aMenuEvt( mpMenuItem->mnId, mpMenuItem->mpVCLMenu );
+ pFrame->CallCallback(SALEVENT_MENUCOMMAND, &aMenuEvt);
+ }
+ else if( mpMenuItem->mpVCLMenu )
+ {
+ // if an item from submenu was selected. the corresponding Window does not exist because
+ // we use native popup menus, so we have to set the selected menuitem directly
+ // incidentally this of course works for top level popup menus, too
+ PopupMenu * pPopupMenu = dynamic_cast<PopupMenu *>(mpMenuItem->mpVCLMenu);
+ if( pPopupMenu )
+ {
+ // FIXME: revise this ugly code
+
+ // select handlers in vcl are dispatch on the original menu
+ // if not consumed by the select handler of the current menu
+ // however since only the starting menu ever came into Execute
+ // the hierarchy is not build up. Workaround this by getting
+ // the menu it should have been
+
+ // get started from hierarchy in vcl menus
+ AquaSalMenu* pParentMenu = mpMenuItem->mpParentMenu;
+ Menu* pCurMenu = mpMenuItem->mpVCLMenu;
+ while( pParentMenu && pParentMenu->mpVCLMenu )
+ {
+ pCurMenu = pParentMenu->mpVCLMenu;
+ pParentMenu = pParentMenu->mpParentSalMenu;
+ }
+
+ pPopupMenu->SetSelectedEntry( mpMenuItem->mnId );
+ pPopupMenu->ImplSelectWithStart( pCurMenu );
+ }
+ else
+ DBG_ERROR( "menubar item without frame !" );
+ }
+}
+@end
+
+@implementation OOStatusItemView
+-(void)drawRect: (NSRect)aRect
+{
+ NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
+ [pContext saveGraphicsState];
+ [SalData::getStatusItem() drawStatusBarBackgroundInRect: aRect withHighlight: NO];
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
+ NSRect aFrame = [self frame];
+ NSRect aImgRect = { { 2, 0 }, { 0, 0 } };
+ for( size_t i = 0; i < rButtons.size(); ++i )
+ {
+ NSRect aFromRect = { { 0, 0 },
+ { rButtons[i].maButton.maImage.GetSizePixel().Width(),
+ rButtons[i].maButton.maImage.GetSizePixel().Height() } };
+ aImgRect.origin.y = floor((aFrame.size.height - aFromRect.size.height)/2);
+ aImgRect.size = aFromRect.size;
+ if( rButtons[i].mpNSImage )
+ [rButtons[i].mpNSImage drawInRect: aImgRect fromRect: aFromRect operation: NSCompositeSourceOver fraction: 1.0];
+ aImgRect.origin.x += aFromRect.size.width + 2;
+ }
+ }
+ [pContext restoreGraphicsState];
+}
+
+-(void)mouseUp: (NSEvent *)pEvent
+{
+ /* check if button goes up inside one of our status buttons */
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
+ NSRect aFrame = [self frame];
+ NSRect aImgRect = { { 2, 0 }, { 0, 0 } };
+ NSPoint aMousePt = [pEvent locationInWindow];
+ for( size_t i = 0; i < rButtons.size(); ++i )
+ {
+ NSRect aFromRect = { { 0, 0 },
+ { rButtons[i].maButton.maImage.GetSizePixel().Width(),
+ rButtons[i].maButton.maImage.GetSizePixel().Height() } };
+ aImgRect.origin.y = (aFrame.size.height - aFromRect.size.height)/2;
+ aImgRect.size = aFromRect.size;
+ if( aMousePt.x >= aImgRect.origin.x && aMousePt.x <= (aImgRect.origin.x+aImgRect.size.width) &&
+ aMousePt.y >= aImgRect.origin.y && aMousePt.y <= (aImgRect.origin.y+aImgRect.size.height) )
+ {
+ if( AquaSalMenu::pCurrentMenuBar->mpFrame && AquaSalFrame::isAlive( AquaSalMenu::pCurrentMenuBar->mpFrame ) )
+ {
+ SalMenuEvent aMenuEvt( rButtons[i].maButton.mnId, AquaSalMenu::pCurrentMenuBar->mpVCLMenu );
+ AquaSalMenu::pCurrentMenuBar->mpFrame->CallCallback(SALEVENT_MENUBUTTONCOMMAND, &aMenuEvt);
+ }
+ return;
+ }
+
+ aImgRect.origin.x += aFromRect.size.width + 2;
+ }
+ }
+}
+
+-(void)layout
+{
+ NSStatusBar* pStatBar = [NSStatusBar systemStatusBar];
+ NSSize aSize = { 0, [pStatBar thickness] };
+ [self removeAllToolTips];
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
+ if( ! rButtons.empty() )
+ {
+ aSize.width = 2;
+ for( size_t i = 0; i < rButtons.size(); ++i )
+ {
+ NSRect aImgRect = { { aSize.width, floor((aSize.height-rButtons[i].maButton.maImage.GetSizePixel().Height())/2) },
+ { rButtons[i].maButton.maImage.GetSizePixel().Width(),
+ rButtons[i].maButton.maImage.GetSizePixel().Height() } };
+ if( rButtons[i].mpToolTipString )
+ [self addToolTipRect: aImgRect owner: rButtons[i].mpToolTipString userData: NULL];
+ aSize.width += 2 + aImgRect.size.width;
+ }
+ }
+ }
+ [self setFrameSize: aSize];
+}
+@end
+
+
diff --git a/vcl/aqua/source/window/salobj.cxx b/vcl/aqua/source/window/salobj.cxx
new file mode 100644
index 000000000000..07d337dcc81a
--- /dev/null
+++ b/vcl/aqua/source/window/salobj.cxx
@@ -0,0 +1,239 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+
+#include "saldata.hxx"
+#include "salobj.h"
+#include "salframe.h"
+
+// =======================================================================
+
+AquaSalObject::AquaSalObject( AquaSalFrame* pFrame ) :
+ mpFrame( pFrame ),
+ mnClipX( -1 ),
+ mnClipY( -1 ),
+ mnClipWidth( -1 ),
+ mnClipHeight( -1 ),
+ mbClip( false ),
+ mnX( 0 ),
+ mnY( 0 ),
+ mnWidth( 20 ),
+ mnHeight( 20 )
+{
+ maSysData.nSize = sizeof( maSysData );
+ maSysData.pView = NULL;
+
+ NSRect aInitFrame = { { 0, 0 }, { 20, 20 } };
+ mpClipView = [[NSClipView alloc] initWithFrame: aInitFrame ];
+ if( mpClipView )
+ {
+ [mpFrame->getView() addSubview: mpClipView];
+ [mpClipView setHidden: YES];
+ }
+ maSysData.pView = [[NSView alloc] initWithFrame: aInitFrame];
+ if( maSysData.pView )
+ {
+ if( mpClipView )
+ [mpClipView setDocumentView: maSysData.pView];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalObject::~AquaSalObject()
+{
+ if( maSysData.pView )
+ {
+ NSView *pView = maSysData.pView;
+ [pView removeFromSuperview];
+ [pView release];
+ }
+ if( mpClipView )
+ {
+ [mpClipView removeFromSuperview];
+ [mpClipView release];
+ }
+}
+
+/*
+ sadly there seems to be no way to impose clipping on a child view,
+ especially a QTMovieView which seems to ignore the current context
+ completely. Also there is no real way to shape a window; on Aqua a
+ similar effect to non-rectangular windows is achieved by using a
+ non-opaque window and not painting where one wants the background
+ to shine through.
+
+ With respect to SalObject this leaves us to having an NSClipView
+ containing the child view. Even a QTMovieView respects the boundaries of
+ that, which gives us a clip "region" consisting of one rectangle.
+ This is gives us an 80% solution only, though.
+*/
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::ResetClipRegion()
+{
+ mbClip = false;
+ setClippedPosSize();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT AquaSalObject::GetClipRegionType()
+{
+ return SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::BeginSetClipRegion( ULONG nRectCount )
+{
+ mbClip = false;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( mbClip )
+ {
+ if( nX < mnClipX )
+ {
+ mnClipWidth += mnClipX - nX;
+ mnClipX = nX;
+ }
+ if( nX + nWidth > mnClipX + mnClipWidth )
+ mnClipWidth = nX + nWidth - mnClipX;
+ if( nY < mnClipY )
+ {
+ mnClipHeight += mnClipY - nY;
+ mnClipY = nY;
+ }
+ if( nY + nHeight > mnClipY + mnClipHeight )
+ mnClipHeight = nY + nHeight - mnClipY;
+ }
+ else
+ {
+ mnClipX = nX;
+ mnClipY = nY;
+ mnClipWidth = nWidth;
+ mnClipHeight = nHeight;
+ mbClip = true;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::EndSetClipRegion()
+{
+ setClippedPosSize();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ mnX = nX;
+ mnY = nY;
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ setClippedPosSize();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::setClippedPosSize()
+{
+ NSRect aViewRect = { { 0, 0 }, { mnWidth, mnHeight } };
+ if( maSysData.pView )
+ {
+ NSView *pView = maSysData.pView;
+ [pView setFrame: aViewRect];
+ }
+
+ NSRect aClipViewRect = { { mnX, mnY }, { mnWidth, mnHeight } };
+ NSPoint aClipPt = { 0, 0 };
+ if( mbClip )
+ {
+ aClipViewRect.origin.x += mnClipX;
+ aClipViewRect.origin.y += mnClipY;
+ aClipViewRect.size.width = mnClipWidth;
+ aClipViewRect.size.height = mnClipHeight;
+ aClipPt.x = mnClipX;
+ if( mnClipY == 0 )
+ aClipPt.y = mnHeight - mnClipHeight;;
+ }
+
+ mpFrame->VCLToCocoa( aClipViewRect, false );
+ [mpClipView setFrame: aClipViewRect];
+
+ [mpClipView scrollToPoint: aClipPt];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::Show( BOOL bVisible )
+{
+ if( mpClipView )
+ [mpClipView setHidden: (bVisible ? NO : YES)];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::Enable( BOOL bEnable )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::GrabFocus()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::SetBackground()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::SetBackground( SalColor nSalColor )
+{
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* AquaSalObject::GetSystemData() const
+{
+ return &maSysData;
+}
+