commit 669a4955e985692ff33dc11a06c0cbc10152a5ad Author: Adam Fedor Date: Wed Mar 27 23:44:41 2002 +0000 Initial revision git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@13249 72102866-910b-0410-8b05-ffd578937521 diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..223ede7 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..6f264cd --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4 @@ +2002-03-27 Adam Fedor + + * Version: Initial version (most code extracted from xgps). + diff --git a/Documentation/GNUmakefile b/Documentation/GNUmakefile new file mode 100644 index 0000000..b9f93f6 --- /dev/null +++ b/Documentation/GNUmakefile @@ -0,0 +1,91 @@ +# +# Documentation makefile for the GNUstep Backend Library +# Copyright (C) 1995 Free Software Foundation, Inc. +# +# Written by: Adam Fedor +# +# This file is part of the GNUstep Backend Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +# Install into the system root by default +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../back.make +include $(GNUSTEP_MAKEFILES)/common.make + +include ../Version + +# The documents to be generated +DOCUMENT_NAME = + +# The text documents to be generated +DOCUMENT_TEXT_NAME = \ +INSTALL NEWS README ANNOUNCE + +TOP_DOC_FILES = INSTALL NEWS README ANNOUNCE + +INSTALL_TEXI_FILES = version.texi +INSTALL_TEXT_MAIN = install.texi +INSTALL_DOC_INSTALL_DIR = Developer/Back/ReleaseNotes/$(VERSION) + +NEWS_TEXI_FILES = version.texi +NEWS_TEXT_MAIN = news.texi +NEWS_DOC_INSTALL_DIR = Developer/Back/ReleaseNotes/$(VERSION) + +README_TEXI_FILES = version.texi +README_TEXT_MAIN = readme.texi +README_DOC_INSTALL_DIR = Developer/Back/ReleaseNotes/$(VERSION) + +ANNOUNCE_TEXI_FILES = version.texi +ANNOUNCE_TEXT_MAIN = announce.texi +ANNOUNCE_DOC_INSTALL_DIR = Developer/Back/ReleaseNotes/$(VERSION) + +-include Makefile.preamble + +-include GNUmakefile.local + +include $(GNUSTEP_MAKEFILES)/documentation.make + +-include Makefile.postamble + +regenerate: $(DOCUMENT_TEXT_NAME) + mv $(TOP_DOC_FILES) .. + +version.texi: ../Version + rm -f version.texi + echo '@set GNUSTEP-BACK-VERSION' $(GNUSTEP_BACK_VERSION) \ + > version.texi + echo '@set GNUSTEP-BACK-GCC $(GNUSTEP_BACK_GCC)' \ + >> version.texi + echo '@set GNUSTEP-BACK-DGS $(GNUSTEP_BACK_DGS)' \ + >> version.texi + if [ $(GNUSTEP_BACK_FTP_MACHINE) ]; then \ + echo '@set GNUSTEP-BACK-FTP-MACHINE $(GNUSTEP_BACK_FTP_MACHINE)' \ + >> version.texi; fi + if [ $(GNUSTEP_BACK_FTP_DIRECTORY) ]; then \ + echo '@set GNUSTEP-BACK-FTP-DIRECTORY \ + $(GNUSTEP_BACK_FTP_DIRECTORY)' \ + >> version.texi; fi + if [ $(GNUSTEP_BACK_SNAP_FTP_MACHINE) ]; then \ + echo '@set GNUSTEP-BACK-SNAP-FTP-MACHINE \ + $(GNUSTEP_BACK_SNAP_FTP_MACHINE)' \ + >> version.texi; fi + if [ $(GNUSTEP_BACK_SNAP_FTP_DIRECTORY) ]; then \ + echo '@set GNUSTEP-BACK-SNAP-FTP-DIRECTORY \ + $(GNUSTEP_BACK_SNAP_FTP_DIRECTORY)' \ + >> version.texi; fi diff --git a/Documentation/announce.texi b/Documentation/announce.texi new file mode 100644 index 0000000..57031b0 --- /dev/null +++ b/Documentation/announce.texi @@ -0,0 +1,48 @@ +@c -*- texinfo -*- +@chapter ANNOUNCE +@ifset TEXT-ONLY +@include version.texi +@end ifset + +This is version @value{GNUSTEP-BACK-VERSION} of the GNUstep GUI Backend +(@samp{gnustep-back}). + +@section What is the GNUstep GUI Backend? + +It is a back-end component for the GNUstep GUI Library. The +implementation of the GNUstep GUI Library is designed in two parts. The +first part is the front-end component which is independent of platform +and display system. This front-end is combined with a back-end +component which handles all of the display system dependent such as +specific calls to the X Window System. This design allows the GNUstep +applications to have the "look and feel" of the underlying display +system without any changes to the application, and the library can be +easily ported to other display systems. + +The GNUstep GUI Backend is for platforms using the X-Window System and +in the future, Window's Systems. It works via a DPS emulation engine to +emulate the DPS functions required by the front-end system. + +@set ANNOUNCE-ONLY +@include news.texi +@clear ANNOUNCE-ONLY + +@section Where can you get it? How can you compile it? + +@ifset GNUSTEP-BACK-FTP-MACHINE +The gstep-back-@value{GNUSTEP-BACK-VERSION}.tar.gz distribution +file has been placed on @samp{@value{GNUSTEP-BACK-FTP-MACHINE}} in +@samp{@value{GNUSTEP-BACK-FTP-DIRECTORY}}. +@end ifset + +@section Where do I send bug reports? + +Bug reports can be sent to the GNUstep bug list +@email{bug-gnustep@@gnu.org} + +@section Obtaining GNU Software + +Check out the GNUstep web site. (@url{http://www.gnustep.org/}) and the +GNU web site. (@url{http://www.gnu.org/}) + + diff --git a/Documentation/install.texi b/Documentation/install.texi new file mode 100644 index 0000000..2d2a9bb --- /dev/null +++ b/Documentation/install.texi @@ -0,0 +1,54 @@ +@c -*- texinfo -*- +@chapter Installation + +@node Top, Introduction, (dir), (dir) +@include version.texi + +@menu +* Introduction:: +* Configuration:: +* Compilation:: +* Installing:: +@end menu + + +@node Introduction, Configuration, Top, Top +@section Introduction + +This file documents the installation of the GNUstep Backend Library, +@samp{gnustep-back}. If you are installing this package as part of the +GNUstep core package, read the file GNUstep-HOWTO for more complete +instructions on how to install the entire GNUstep package (including +this library). GNUstep-HOWTO is located at @url{http://www.gnustep.org} + +You must have installed gnustep-gui before installing this library. + +@node Configuration, Compilation, Introduction, Top +@section Configuration + +Configuration is performed by running the @file{configure} program at a +shell prompt. You may want to use some of the optional arguments to the +@file{configure} program. Type @code{configure --help} for a list. GNUstep +specific options are at the end of this list (if any). + +@node Compilation, Installing, Configuration, Top +@section Compilation + +To compile this library, type make. After this is complete, type make +install (make sure you are the root user). Some additional options you +can use with make are @samp{debug=yes} to make a debugging version of +the library and @samp{shared=no} to make a static version of the +library. See the gstep-make package for more information on these options. + +@node Installing, , Compilation, Top +@section Installing + +To install, type + +@example +make install +@end example + +@bye + + diff --git a/Documentation/news.texi b/Documentation/news.texi new file mode 100644 index 0000000..e7bf07c --- /dev/null +++ b/Documentation/news.texi @@ -0,0 +1,19 @@ +@c -*-texinfo-*- +@ifclear ANNOUNCE-ONLY +@chapter NEWS +@end ifclear + +@ifset TEXT-ONLY +@include version.texi +@end ifset + +@section Noteworthy changes in version @samp{0.7.7} +First release. Most components extracted from xgps. +@end itemize + +@c ==================================================================== +@c Keep the next line just below the list of changes in most recent version. +@ifclear ANNOUNCE-ONLY + + +@end ifclear diff --git a/Documentation/readme.texi b/Documentation/readme.texi new file mode 100644 index 0000000..afff089 --- /dev/null +++ b/Documentation/readme.texi @@ -0,0 +1,35 @@ +@c -*-texinfo-*- +@chapter README + +@ifset TEXT-ONLY +@include version.texi +@end ifset + +This is version @value{GNUSTEP-BACK-VERSION} of the GNUstep GUI Backend +(@samp{gnustep-back}). + +Here is some introductory info to get you started: + +@section Initial reading + +@itemize @bullet +@item +The file @file{ANNOUNCE} contains a very brief overview of the library. +It also tells you where to get the most recent version. + +@item +The file @file{NEWS} has the library's feature history. + +@item +The file @file{INSTALL} gives instructions for installing the library. +@end itemize + +@section How can you help? + +@itemize @bullet + +@item +Give us feedback! Tell us what you like; tell us what you think +could be better. Send us bug reports at @email{bug-gnustep@@gnu.org}. + +@end itemize diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..01ecc0c --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,51 @@ +# +# Top level makefile for GNUstep Backend +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Install into the system root by default +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +RPM_DISABLE_RELOCATABLE=YES +PACKAGE_NEEDS_CONFIGURE = YES + +CVS_MODULE_NAME = back + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=back.make +include $(GNUSTEP_MAKEFILES)/common.make + +PACKAGE_NAME = gnustep-back + +include ./Version + +# +# The list of subproject directories +# +SUBPROJECTS = Source Tools + +-include GNUmakefile.preamble + +include $(GNUSTEP_MAKEFILES)/aggregate.make + +-include GNUmakefile.postamble diff --git a/GNUmakefile.postamble b/GNUmakefile.postamble new file mode 100644 index 0000000..2fc2ef7 --- /dev/null +++ b/GNUmakefile.postamble @@ -0,0 +1,71 @@ +# -*-makefile-*- +# GNUmakefile.postamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Things to do before compiling +# before-all:: + +# Things to do after compiling +# after-all:: + +$(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional: + $(MKDIRS) $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional + +# Things to do before installing +before-install:: $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional + $(INSTALL_DATA) back.make \ + $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/back.make + +# Things to do after installing +# after-install:: + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +# after-uninstall:: + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +# after-clean:: + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +after-distclean:: + rm -f config.status config.log config.cache TAGS config.make back.make + +back.make: back.make.in + ./configure + +confige.mak: confige.mak.in + ./configure + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check:: diff --git a/Headers/gsc/GSContext.h b/Headers/gsc/GSContext.h new file mode 100644 index 0000000..15c8630 --- /dev/null +++ b/Headers/gsc/GSContext.h @@ -0,0 +1,86 @@ +/* GSContext + + Generic backend drawing context. + + Copyright (C) 2002 Free Software Foundation, Inc. + + Written By: Adam Fedor + Date: Mar 2002 + + This file is part of the GNU Objective C User Interface library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _GSContext_h_INCLUDE +#define _GSContext_h_INCLUDE + +#include +#include + +@class GSGState; +@class GSDisplayServer; + +@interface GSContext : NSGraphicsContext +{ +@public + GSDisplayServer *server; + void *opstack; + void *gstack; + GSGState *gstate; + NSMapTable *gtable; +} + +- (GSGState *) currentGState; + +@end + +/* Error Macros */ +#define DPS_WARN(type, resp) \ + NSDebugLLog(@"GSContext", type, resp) +#define DPS_ERROR(type, resp) \ + NSLog(type, resp) + +/* Current keys used for the info dictionary: + Key: Value: + DisplayName -- (NSString)name of X server + ScreenNumber -- (NSNumber)screen number + DebugContext -- (NSNumber)YES or NO +*/ + +extern NSString *DPSconfigurationerror; +extern NSString *DPSinvalidaccess; +extern NSString *DPSinvalidcontext; +extern NSString *DPSinvalidexit; +extern NSString *DPSinvalidfileaccess; +extern NSString *DPSinvalidfont; +extern NSString *DPSinvalidid; +extern NSString *DPSinvalidrestore; +extern NSString *DPSinvalidparam; +extern NSString *DPSioerror; +extern NSString *DPSlimitcheck; +extern NSString *DPSnocurrentpoint; +extern NSString *DPSnulloutput; +extern NSString *DPSrangecheck; +extern NSString *DPSstackoverflow; +extern NSString *DPSstackunderflow; +extern NSString *DPStypecheck; +extern NSString *DPSundefined; +extern NSString *DPSundefinedfilename; +extern NSString *DPSundefinedresult; +extern NSString *DPSVMerror; + +#endif /* _GSContext_h_INCLUDE */ + diff --git a/Headers/gsc/GSGState.h b/Headers/gsc/GSGState.h new file mode 100644 index 0000000..dd456c8 --- /dev/null +++ b/Headers/gsc/GSGState.h @@ -0,0 +1,86 @@ +/* GSGState - Implements generic graphic state drawing for non-PS backends + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1995 + Extracted from XGPS: Fred Kiefer + Date: March 2002 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _GSGState_h_INCLUDE +#define _GSGState_h_INCLUDE + +#include // needed for NSCompositingOperation +#include +#include + +@class NSAffineTransform; +@class NSBezierPath; +@class NSFont; +@class GSContext; + +typedef enum { + path_stroke, path_fill, path_eofill, path_clip, path_eoclip +} ctxt_object_t; + +@interface GSGState : NSObject +{ +@public + GSContext *drawcontext; + NSAffineTransform *ctm; + NSPoint offset; /* Offset from Drawable origin */ + NSBezierPath *path; /* current path */ + NSFont *font; + + BOOL viewIsFlipped; +} + +- initWithDrawContext: (GSContext *)context; +- deepen; + +- (void) setOffset: (NSPoint)theOffset; +- (NSPoint) offset; + +- (void) setFont: (NSFont*)font; +- (NSFont*) currentFont; + +- (void) compositeGState: (GSGState *)source + fromRect: (NSRect)aRect + toPoint: (NSPoint)aPoint + op: (NSCompositingOperation)op; + +- (void) dissolveGState: (GSGState *)source + fromRect: (NSRect)aRect + toPoint: (NSPoint)aPoint + delta: (float)delta; + +- (void) compositerect: (NSRect)aRect + op: (NSCompositingOperation)op; + +- (NSPoint) pointInMatrixSpace: (NSPoint)point; +- (NSPoint) deltaPointInMatrixSpace: (NSPoint)point; +- (NSRect) rectInMatrixSpace: (NSRect)rect; + +@end + +#include "GSGStateOps.h" + +#endif /* _GSGState_h_INCLUDE */ + diff --git a/Headers/gsc/GSGStateOps.h b/Headers/gsc/GSGStateOps.h new file mode 100644 index 0000000..86d7efc --- /dev/null +++ b/Headers/gsc/GSGStateOps.h @@ -0,0 +1,137 @@ +/* GSGStateOPS - Ops for GSGState + + Copyright (C) 1998 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1998 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _GSGStateOps_h_INCLUDE +#define _GSGStateOps_h_INCLUDE + +@interface GSGState (Ops) +/* ----------------------------------------------------------------------- */ +/* Color operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentalpha: (float*)a; +- (void) DPScurrentcmykcolor: (float*)c : (float*)m : (float*)y : (float*)k; +- (void) DPScurrentgray: (float*)gray; +- (void) DPScurrenthsbcolor: (float*)h : (float*)s : (float*)b; +- (void) DPScurrentrgbcolor: (float*)r : (float*)g : (float*)b; +- (void) DPSsetalpha: (float)a; +- (void) DPSsetcmykcolor: (float)c : (float)m : (float)y : (float)k; +- (void) DPSsetgray: (float)gray; +- (void) DPSsethsbcolor: (float)h : (float)s : (float)b; +- (void) DPSsetrgbcolor: (float)r : (float)g : (float)b; + +- (void) GSSetFillColorspace: (NSDictionary *)dict; +- (void) GSSetStrokeColorspace: (NSDictionary *)dict; +- (void) GSSetFillColor: (float *)values; +- (void) GSSetStrokeColor: (float *)values; + +/* ----------------------------------------------------------------------- */ +/* Text operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSashow: (float)x : (float)y : (const char*)s; +- (void) DPSawidthshow: (float)cx : (float)cy : (int)c : (float)ax : (float)ay + : (const char*)s; +- (void) DPScharpath: (const char*)s : (int)b; +- (void) DPSshow: (const char*)s; +- (void) DPSwidthshow: (float)x : (float)y : (int)c : (const char*)s; +- (void) DPSxshow: (const char*)s : (const float*)numarray : (int)size; +- (void) DPSxyshow: (const char*)s : (const float*)numarray : (int)size; +- (void) DPSyshow: (const char*)s : (const float*)numarray : (int)size; + +/* ----------------------------------------------------------------------- */ +/* Gstate operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSinitgraphics; + +- (void) DPScurrentflat: (float*)flatness; +- (void) DPScurrentlinecap: (int*)linecap; +- (void) DPScurrentlinejoin: (int*)linejoin; +- (void) DPScurrentlinewidth: (float*)width; +- (void) DPScurrentmiterlimit: (float*)limit; +- (void) DPScurrentpoint: (float*)x : (float*)y; +- (void) DPScurrentstrokeadjust: (int*)b; +- (void) DPSsetdash: (const float*)pat : (int)size : (float)offset; +- (void) DPSsetflat: (float)flatness; +- (void) DPSsetlinecap: (int)linecap; +- (void) DPSsetlinejoin: (int)linejoin; +- (void) DPSsetlinewidth: (float)width; +- (void) DPSsetmiterlimit: (float)limit; +- (void) DPSsetstrokeadjust: (int)b; + +/* ----------------------------------------------------------------------- */ +/* Matrix operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSconcat: (const float*)m; +- (void) DPSinitmatrix; +- (void) DPSrotate: (float)angle; +- (void) DPSscale: (float)x : (float)y; +- (void) DPStranslate: (float)x : (float)y; + +- (NSAffineTransform *) GSCurrentCTM; +- (void) GSSetCTM: (NSAffineTransform *)ctm; +- (void) GSConcatCTM: (NSAffineTransform *)ctm; + +/* ----------------------------------------------------------------------- */ +/* Paint operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSarc: (float)x : (float)y : (float)r : (float)angle1 + : (float)angle2; +- (void) DPSarcn: (float)x : (float)y : (float)r : (float)angle1 + : (float)angle2; +- (void) DPSarct: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r; +- (void) DPSclip; +- (void) DPSclosepath; +- (void) DPScurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 + : (float)x3 : (float)y3; +- (void) DPSeoclip; +- (void) DPSeofill; +- (void) DPSfill; +- (void) DPSflattenpath; +- (void) DPSinitclip; +- (void) DPSlineto: (float)x : (float)y; +- (void) DPSmoveto: (float)x : (float)y; +- (void) DPSnewpath; +- (void) DPSpathbbox: (float*)llx : (float*)lly : (float*)urx : (float*)ury; +- (void) DPSrcurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 + : (float)x3 : (float)y3; +- (void) DPSrectclip: (float)x : (float)y : (float)w : (float)h; +- (void) DPSrectfill: (float)x : (float)y : (float)w : (float)h; +- (void) DPSrectstroke: (float)x : (float)y : (float)w : (float)h; +- (void) DPSreversepath; +- (void) DPSrlineto: (float)x : (float)y; +- (void) DPSrmoveto: (float)x : (float)y; +- (void) DPSstroke; + +- (void) GSSendBezierPath: (NSBezierPath *)path; +- (void) GSRectFillList: (const NSRect *)rects : (int) count; + +- (void)DPSimage: (NSAffineTransform*) matrix + : (int) pixelsWide : (int) pixelsHigh + : (int) bitsPerSample : (int) samplesPerPixel + : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar + : (BOOL) hasAlpha : (NSString *) colorSpaceName + : (const unsigned char *const [5]) data; + +@end + +#endif diff --git a/Headers/gsc/GSStreamContext.h b/Headers/gsc/GSStreamContext.h new file mode 100644 index 0000000..0ed777f --- /dev/null +++ b/Headers/gsc/GSStreamContext.h @@ -0,0 +1,42 @@ +/* GSStreamContext - Output Postscript to a stream + + Copyright (C) 1999 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Mar 1999 + + This file is part of the GNU Objective C User Interface library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _GSStreamContext_h_INCLUDE +#define _GSStreamContext_h_INCLUDE + +#include +#include + +@class GSGState; + +@interface GSStreamContext : NSGraphicsContext +{ + FILE *gstream; +} + +- (GSGState *) currentGState; + +@end + +#endif /* _GSStreamContext_h_INCLUDE */ diff --git a/Headers/x11/StdCmap.h b/Headers/x11/StdCmap.h new file mode 100644 index 0000000..a1cdd2e --- /dev/null +++ b/Headers/x11/StdCmap.h @@ -0,0 +1,112 @@ +/* $XConsortium: StdCmap.h,v 1.4 94/04/17 20:16:15 converse Exp $ */ + +/* + +Copyright (c) 1988 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + +*/ + +/* + * The interfaces described by this header file are for miscellaneous utilities + * and are not part of the Xlib standard. + */ + +#ifndef _XMU_STDCMAP_H_ +#define _XMU_STDCMAP_H_ + +#include + +_XFUNCPROTOBEGIN + +Status XmuAllStandardColormaps( +#if NeedFunctionPrototypes + Display* /* dpy */ +#endif +); + +Status XmuCreateColormap( +#if NeedFunctionPrototypes + Display* /* dpy */, + XStandardColormap* /* colormap */ +#endif +); + +void XmuDeleteStandardColormap( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + Atom /* property */ +#endif +); + +Status XmuGetColormapAllocation( +#if NeedFunctionPrototypes + XVisualInfo* /* vinfo */, + Atom /* property */, + unsigned long* /* red_max_return */, + unsigned long* /* green_max_return */, + unsigned long* /* blue_max_return */ +#endif +); + +Status XmuLookupStandardColormap( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + VisualID /* visualid */, + unsigned int /* depth */, + Atom /* property */, + Bool /* replace */, + Bool /* retain */ +#endif +); + +XStandardColormap *XmuStandardColormap( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + VisualID /* visualid */, + unsigned int /* depth */, + Atom /* property */, + Colormap /* cmap */, + unsigned long /* red_max */, + unsigned long /* green_max */, + unsigned long /* blue_max */ +#endif +); + +Status XmuVisualStandardColormaps( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + VisualID /* visualid */, + unsigned int /* depth */, + Bool /* replace */, + Bool /* retain */ +#endif +); + +_XFUNCPROTOEND + +#endif /* _XMU_STDCMAP_H_ */ diff --git a/Headers/x11/XGDragView.h b/Headers/x11/XGDragView.h new file mode 100644 index 0000000..dad1b70 --- /dev/null +++ b/Headers/x11/XGDragView.h @@ -0,0 +1,120 @@ +/* -*- mode: ObjC -*- + XGDragView + + View that is dragged during drag and drop + + Written By: woudshoo@xs4all.nl + Date: Nov 2001 + + This file is part of the GNU Objective C User Interface library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#include +#include +#include +#include "x11/xdnd.h" +#include "x11/XGServerWindow.h" + +/*" + Drag and drop support functions + "*/ + +void GSEnsureDndIsInitialized (void); +DndClass xdnd (void); +Atom GSActionForDragOperation(unsigned int op); +NSDragOperation GSDragOperationForAction(Atom xaction); + + +/* + used in the operation mask to indicate that the + user can not change the drag action by + pressing modifiers. +*/ + +#define NSDragOperationIgnoresModifiers 0xffff + +/*" + WRO (notes made 18 Nov 2001) + + The object that is dragged over the screen. + It hijacks the event loop and manages the complete + drag and drop sequence. + "*/ +@interface XGDragView : NSView +{ + + NSCell *dragCell; /*" the graphics that is dragged"*/ + NSPasteboard *dragPasteboard; + NSPoint dragPoint; /*" in base coordinates, only valid when dragWindow != nil "*/ + gswindow_device_t *dragWindev; + + /* information used in the drag and drop event loop */ + NSPoint offset; /*" offset of image w.r.t. cursor "*/ + NSPoint dragPosition; /*" in screen coordinates "*/ + NSPoint newPosition; /*" position, not yet processed "*/ + int wx, wy; /*" position of image in X-coordinates "*/ + Window targetWindow; /*" XWindow that is the current drag target "*/ + + int dragSequence; + id dragSource; + + unsigned int dragMask; /*" Operations supported by the source "*/ + unsigned int operationMask; /*" user specified operation mask (key modifiers). + this is either a mask of type _NSDragOperation, + or NSDragOperationIgnoresModifiers, which + is defined as 0xffff "*/ + unsigned int targetMask; /*" Operations supported by the target, only valid if + targetIsDndAware is true "*/ + + id dragWindow; /*" NSWindow in this application that is the current target "*/ + Atom *typelist; + BOOL dragExternal; /*" YES if target and source are in a different application "*/ + BOOL isDragging; /*" Yes if we are currently dragging "*/ + BOOL slideBack; /*" slide back when drag fails? "*/ + NSMutableDictionary *cursors; +} + ++ (XGDragView*) sharedDragView; + +- (BOOL) isDragging; + +- (void) setupDragInfoFromXEvent: (XEvent *)xEvent; +- (void) updateDragInfoFromEvent: (NSEvent *)event; +- (void) resetDragInfo; +- (void) _sendLocalEvent: (GSAppKitSubtype)subtype + action: (NSDragOperation)action + position: (NSPoint)eventLocation + timestamp: (NSTimeInterval)time + toWindow: (NSWindow*)dWindow; +- (void) dragImage: (NSImage*)anImage + at: (NSPoint)screenLocation + offset: (NSSize)initialOffset + event: (NSEvent*)event + pasteboard: (NSPasteboard*)pboard + source: (id)sourceObject + slideBack: (BOOL)slideFlag; +- (void) postDragEvent: (NSEvent *)theEvent; +- (void) _setCursor; +- (void) _handleDrag: (NSEvent*)theEvent; +- (void) _handleEventDuringDragging: (NSEvent*) theEvent; +- (void) _updateAndMoveImageToCorrectPosition; +- (void) _moveDraggedImageToNewPosition; +- (void) _slideDraggedImageTo: (NSPoint)screenPoint + numberOfSteps: (int) steps + waitAfterSlide: (BOOL) waitFlag; +- (Window) _xWindowAcceptingDnDunderX: (int) x Y: (int) y; +@end diff --git a/Headers/x11/XGGeneric.h b/Headers/x11/XGGeneric.h new file mode 100644 index 0000000..89a8415 --- /dev/null +++ b/Headers/x11/XGGeneric.h @@ -0,0 +1,99 @@ +/* Generic header info common to X backends for GNUstep + + Copyright (C) 2000 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + Date: Mar 2000 + + This file is part of the GNUstep project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef INCLUDED_XGGENERIC_H +#define INCLUDED_XGGENERIC_H + +/* + * Flags to indicate which protocols the WindowManager follows + */ +typedef enum { + XGWM_UNKNOWN = 0, + XGWM_WINDOWMAKER = 1, + XGWM_GNOME = 2, + XGWM_KDE = 4, + XGWM_EWMH = 8 +} XGWMProtocols; + +typedef struct { + Atom win_type_atom; + Atom win_desktop_atom; + Atom win_normal_atom; + Atom win_floating_atom; + Atom win_menu_atom; + Atom win_dock_atom; + Atom win_modal_atom; +} XGWMWinTypes; + +/* + * Structure containing ivars that are common to all X backend contexts. + */ +struct XGGeneric { + int wm; + struct { + unsigned useWindowMakerIcons:1; + unsigned borderedBorderless:1; + unsigned doubleParentWindow:1; + } flags; + Time lastTime; + Time lastClick; + Window lastClickWindow; + int lastClickX; + int lastClickY; + Time lastMotion; + Atom protocols_atom; + Atom delete_win_atom; + Atom take_focus_atom; + Atom miniaturize_atom; + Atom win_decor_atom; + Atom titlebar_state_atom; + char *rootName; + long currentFocusWindow; + long desiredFocusWindow; + long focusRequestNumber; + unsigned char lMouse; + unsigned char mMouse; + unsigned char rMouse; + unsigned char upMouse; + unsigned char downMouse; + int lMouseMask; + int mMouseMask; + int rMouseMask; + Window appRootWindow; + void *cachedWindow; // last gswindow_device_t used. + XPoint parent_offset; // WM defined parent info + XGWMWinTypes wintypes; +}; + +/* GNOME Window layers */ +#define WIN_LAYER_DESKTOP 0 +#define WIN_LAYER_BELOW 2 +#define WIN_LAYER_NORMAL 4 +#define WIN_LAYER_ONTOP 6 +#define WIN_LAYER_DOCK 8 +#define WIN_LAYER_ABOVE_DOCK 10 +#define WIN_LAYER_MENU 12 + +#endif + diff --git a/Headers/x11/XGInputServer.h b/Headers/x11/XGInputServer.h new file mode 100644 index 0000000..252c7a2 --- /dev/null +++ b/Headers/x11/XGInputServer.h @@ -0,0 +1,57 @@ +/* XGInputServer - Keyboard input handling + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Adam Fedor + Date: January 2002 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef _GNUstep_H_XGInputServer +#define _GNUstep_H_XGInputServer + +#include +#include + +@protocol XInputFiltering +- (BOOL) filterEvent: (XEvent *)event; +- (NSString *) lookupStringForEvent: (XKeyEvent *)event + window: (gswindow_device_t *)window + keysym: (KeySym *)keysymptr; +@end + + +@interface XIMInputServer: NSInputServer +{ + id delegate; + NSString *server_name; + XIM xim; + XIMStyle xim_style; + NSMutableData *dbuf; + NSStringEncoding encoding; +} + +- (id) initWithDelegate: (id)aDelegate + display: (Display *)dpy + name: (NSString *)name; +- (void) ximFocusICWindow: (gswindow_device_t *)windev; +- (void) ximCloseIC: (XIC)xic; +@end + +#endif diff --git a/Headers/x11/XGServer.h b/Headers/x11/XGServer.h new file mode 100644 index 0000000..3144fcc --- /dev/null +++ b/Headers/x11/XGServer.h @@ -0,0 +1,85 @@ +/* XGServer + + Backend server using the X11. + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Adam Fedor + Date: Mar 2002 + + This file is part of the GNUstep Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _XGServer_h_INCLUDE +#define _XGServer_h_INCLUDE + +#include +#include +#include +#include +#include "x11/XGGeneric.h" + +/* + * Enumerated type to say how we should draw pixels to the X display - used + * to select different drawing mechanisms to try to optimise. + */ +typedef enum { + XGDM_FAST15, + XGDM_FAST16, + XGDM_FAST32, + XGDM_FAST32_BGR, + XGDM_PORTABLE +} XGDrawMechanism; + +@interface XGServer : GSDisplayServer +{ +@public + void *context; + Window grabWindow; + XGDrawMechanism drawMechanism; + struct XGGeneric generic; + id inputServer; +} + ++ (Display*) currentXDisplay; +- (XGDrawMechanism) drawMechanism; +- (Display*)xDisplay; +- (Window)xDisplayRootWindow; +- (Window)xAppRootWindow; + +- (XColor)xColorFromColor: (XColor)color; + +- (void *) xrContext; + ++ (void) waitAllContexts; +@end + +/* + * Synchronize with X event queue - soak up events. + * Waits for up to 1 second for event. + */ +@interface XGServer (XSync) +- (BOOL) xSyncMap: (void*)window; +@end + +@interface XGServer (XGGeneric) +- (NSRect) _OSFrameToXFrame: (NSRect)o for: (void*)window; +- (NSRect) _OSFrameToXHints: (NSRect)o for: (void*)window; +- (NSRect) _XFrameToOSFrame: (NSRect)x for: (void*)window; +@end + +#endif /* _XGServer_h_INCLUDE */ diff --git a/Headers/x11/XGServerWindow.h b/Headers/x11/XGServerWindow.h new file mode 100644 index 0000000..8c5ea42 --- /dev/null +++ b/Headers/x11/XGServerWindow.h @@ -0,0 +1,112 @@ +/* Window ops for X11 server + + Copyright (C) 1999 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1999 + + This file is part of the GNU Objective C User Interface library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _XGServerWindow_h_INCLUDE +#define _XGServerWindow_h_INCLUDE + +#define BOOL XWINDOWSBOOL // prevent X windows BOOL +#include // warning +#undef BOOL +#include + +// +// WindowMaker window manager interaction +// +typedef struct { + CARD32 flags; + CARD32 window_style; + CARD32 window_level; + CARD32 reserved; + Pixmap miniaturize_pixmap; // pixmap for miniaturize button + Pixmap close_pixmap; // pixmap for close button + Pixmap miniaturize_mask; // miniaturize pixmap mask + Pixmap close_mask; // close pixmap mask + CARD32 extra_flags; +} GNUstepWMAttributes; + +#define GSWindowStyleAttr (1<<0) +#define GSWindowLevelAttr (1<<1) +#define GSMiniaturizePixmapAttr (1<<3) +#define GSClosePixmapAttr (1<<4) +#define GSMiniaturizeMaskAttr (1<<5) +#define GSCloseMaskAttr (1<<6) +#define GSExtraFlagsAttr (1<<7) + +#define GSDocumentEditedFlag (1<<0) +#define GSWindowWillResizeNotificationsFlag (1<<1) +#define GSWindowWillMoveNotificationsFlag (1<<2) +#define GSNoApplicationIconFlag (1<<5) +#define WMFHideOtherApplications 10 +#define WMFHideApplication 12 + +typedef struct _gswindow_device_t { + Display *display; + Window ident; + Window root; + Window parent; + int screen; + GC gc; + long number; + int depth; + int border; + int map_state; + int visibility; + NSBackingStoreType type; + NSRect xframe; + Drawable buffer; + Drawable alpha_buffer; + BOOL is_exposed; + NSMutableArray *exposedRects; + Region region; // Used between several expose events + XWMHints gen_hints; + XSizeHints siz_hints; + GNUstepWMAttributes win_attrs; + XSetWindowAttributes xwn_attrs; + int xoff; + int yoff; + int boff; + Atom protocols[4]; + int numProtocols; + XIC ic; +} gswindow_device_t; + +#define GET_XDRAWABLE(win) ((win)->buffer ? (win)->buffer: (win)->ident) + +@interface XGServer (DPSWindow) ++ (gswindow_device_t *) _windowForXWindow: (Window)xWindow; ++ (gswindow_device_t *) _windowForXParent: (Window)xWindow; ++ (gswindow_device_t *) _windowWithTag: (int)windowNumber; +- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win; +- (void) _processExposedRectangles: (int)win; +- (void) _initializeCursorForXWindow: (Window) win; +- (void) _destroyServerWindows; + +/* This needs to go in GSDisplayServer */ +- (void) _DPSsetcursor: (Cursor)c : (BOOL)set; +@end + +extern Pixmap +xgps_cursor_mask(Display *xdpy, Drawable draw, const char *data, + int w, int h, int colors); +#endif diff --git a/Headers/x11/XGSlideView.h b/Headers/x11/XGSlideView.h new file mode 100644 index 0000000..60b6526 --- /dev/null +++ b/Headers/x11/XGSlideView.h @@ -0,0 +1,43 @@ +/** -*- mode: ObjC -*- + XGSlideView + + View that is slid by NSWorkspace + + Copyright (C) 2002 Free Software Foundation, Inc. + + Written By: enrico@imago.ro + Date: Jan 2002 + + This file is part of the GNU Objective C User Interface library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#include +#include +#include "x11/XGServerWindow.h" + +@class NSCell; + +@interface XGSlideView : NSView +{ + NSCell *slideCell; + gswindow_device_t *slideWindev; +} + ++ (BOOL) _slideImage: (NSImage*)image + from: (NSPoint)fromPoint + to: (NSPoint)toPoint; +@end diff --git a/Headers/x11/wraster.h b/Headers/x11/wraster.h new file mode 100644 index 0000000..4e39863 --- /dev/null +++ b/Headers/x11/wraster.h @@ -0,0 +1,459 @@ +/* + * Raster graphics library + * + * Copyright (c) 1997 ~ 2000 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Environment variables: + * + * WRASTER_GAMMA // + * gamma correction value. Must be greater than 0 + * Only for PseudoColor visuals. + * + * Default: + * WRASTER_GAMMA 1/1/1 + * + * + * If you want a specific value for a screen, append the screen number + * preceded by a hash to the variable name as in + * WRASTER_GAMMA#1 + * for screen number 1 + */ + +#ifndef RLRASTER_H_ +#define RLRASTER_H_ + + +/* version of the header for the library: 0.20 */ +#define WRASTER_HEADER_VERSION 20 + + +#include +#include + +#ifdef XSHM +#include +#endif + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* RBestMatchRendering or RDitheredRendering */ +#define RC_RenderMode (1<<0) + +/* number of colors per channel for colormap in PseudoColor mode */ +#define RC_ColorsPerChannel (1<<1) + +/* do gamma correction */ +#define RC_GammaCorrection (1<<2) + +/* visual id to use */ +#define RC_VisualID (1<<3) + +/* shared memory usage */ +#define RC_UseSharedMemory (1<<4) + +/* use default instead of best visual */ +#define RC_DefaultVisual (1<<5) + +/* filter type for smoothed scaling */ +#define RC_ScalingFilter (1<<6) + +/* standard colormap usage */ +#define RC_StandardColormap (1<<7) + + + + + + +/* std colormap usage/creation modes */ +enum { + RUseStdColormap, /* default. fallbacks to RIgnore.. if + there is none defined */ + RCreateStdColormap, + RIgnoreStdColormap +}; + + + +typedef struct RContextAttributes { + int flags; + int render_mode; + int colors_per_channel; /* for PseudoColor */ + float rgamma; /* gamma correction for red, */ + float ggamma; /* green, */ + float bgamma; /* and blue */ + VisualID visualid; /* visual ID to use */ + int use_shared_memory; /* True of False */ + int scaling_filter; + int standard_colormap_mode; /* what to do with std cma */ +} RContextAttributes; + + +/* + * describes a screen in terms of depth, visual, number of colors + * we can use, if we should do dithering, and what colors to use for + * dithering. + */ +typedef struct RContext { + Display *dpy; + int screen_number; + Colormap cmap; + + RContextAttributes *attribs; + + GC copy_gc; + + Visual *visual; + int depth; + Window drawable; /* window to pass for XCreatePixmap().*/ + /* generally = root */ + int vclass; + + unsigned long black; + unsigned long white; + + int red_offset; /* only used in 24bpp */ + int green_offset; + int blue_offset; + + /* only used for pseudocolor and grayscale */ + + XStandardColormap *std_rgb_map; /* standard RGB colormap */ + XStandardColormap *std_gray_map; /* standard grayscale colormap */ + + int ncolors; /* total number of colors we can use */ + XColor *colors; /* internal colormap */ + unsigned long *pixels; /* RContext->colors[].pixel */ + + struct { + unsigned int use_shared_pixmap:1; + unsigned int optimize_for_speed:1; + } flags; +} RContext; + + +typedef struct RColor { + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; +} RColor; + + +typedef struct RHSVColor { + unsigned short hue; /* 0-359 */ + unsigned char saturation; /* 0-255 */ + unsigned char value; /* 0-255 */ +} RHSVColor; + + + +typedef struct RPoint { + int x, y; +} RPoint; + + +typedef struct RSegment { + int x1, y1, x2, y2; +} RSegment; + + + +/* image formats */ +enum RImageFormat { + RRGBFormat, + RRGBAFormat +}; + + +/* + * internal 24bit+alpha image representation + */ +typedef struct RImage { + unsigned char *data; /* image data RGBA or RGB */ + unsigned width, height; /* size of the image */ + enum RImageFormat format; + RColor background; /* background color */ +} RImage; + + +/* + * internal wrapper for XImage. Used for shm abstraction + */ +typedef struct RXImage { + XImage *image; + + /* Private data. Do not access */ +#ifdef XSHM + XShmSegmentInfo info; + char is_shared; +#endif +} RXImage; + + +/* image display modes */ +enum { + RDitheredRendering = 0, + RBestMatchRendering = 1 +}; + + +/* smoothed scaling filter types */ +enum { + RBoxFilter, + RTriangleFilter, + RBellFilter, + RBSplineFilter, + RLanczos3Filter, + RMitchellFilter +}; + + +/* note that not all operations are supported in all functions */ +enum { + RClearOperation, /* clear with 0 */ + RCopyOperation, + RNormalOperation, /* same as combine */ + RAddOperation, + RSubtractOperation +}; + + +enum { + RAbsoluteCoordinates = 0, + RRelativeCoordinates = 1 +}; + + +enum { + RSunkenBevel = -1, + RNoBevel = 0, + RRaisedBevel = 1 +}; +/* bw compat */ +#define RBEV_SUNKEN RSunkenBevel +/* 1 pixel wide */ +#define RBEV_RAISED RRaisedBevel +/* 1 pixel wide on top/left 2 on bottom/right */ +#define RBEV_RAISED2 2 +/* 2 pixel width */ +#define RBEV_RAISED3 3 + +enum { + RHorizontalGradient = 2, + RVerticalGradient = 3, + RDiagonalGradient = 4 +}; +/* for backwards compatibility */ +#define RGRD_HORIZONTAL RHorizontalGradient +#define RGRD_VERTICAL RVerticalGradient +#define RGRD_DIAGONAL RDiagonalGradient + + + +/* error codes */ +#define RERR_NONE 0 +#define RERR_OPEN 1 /* cant open file */ +#define RERR_READ 2 /* error reading from file */ +#define RERR_WRITE 3 /* error writing to file */ +#define RERR_NOMEMORY 4 /* out of memory */ +#define RERR_NOCOLOR 5 /* out of color cells */ +#define RERR_BADIMAGEFILE 6 /* image file is corrupted or invalid */ +#define RERR_BADFORMAT 7 /* image file format is unknown */ +#define RERR_BADINDEX 8 /* no such image index in file */ + +#define RERR_BADVISUALID 16 /* invalid visual ID requested for context */ +#define RERR_STDCMAPFAIL 17 /* failed to created std colormap */ + +#define RERR_XERROR 127 /* internal X error */ +#define RERR_INTERNAL 128 /* should not happen */ + + +/* + * Returns a NULL terminated array of strings containing the + * supported formats, such as: TIFF, XPM, PNG, JPEG, PPM, GIF + * Do not free the returned data. + */ +char **RSupportedFileFormats(void); + + +char *RGetImageFileFormat(char *file); + +/* + * Xlib contexts + */ +RContext *RCreateContext(Display *dpy, int screen_number, + RContextAttributes *attribs); + +void RDestroyContext(RContext *context); + +Bool RGetClosestXColor(RContext *context, RColor *color, XColor *retColor); + +/* + * RImage creation + */ +RImage *RCreateImage(unsigned width, unsigned height, int alpha); + +RImage *RCreateImageFromXImage(RContext *context, XImage *image, XImage *mask); + +RImage *RCreateImageFromDrawable(RContext *context, Drawable drawable, + Pixmap mask); + +RImage *RLoadImage(RContext *context, char *file, int index); + + +void RDestroyImage(RImage *image); + +RImage *RGetImageFromXPMData(RContext *context, char **xpmData); + +/* + * RImage storing + */ +Bool RSaveImage(RImage *image, char *filename, char *format); + +/* + * Area manipulation + */ +RImage *RCloneImage(RImage *image); + +RImage *RGetSubImage(RImage *image, int x, int y, unsigned width, + unsigned height); + +void RCombineImageWithColor(RImage *image, RColor *color); + +void RCombineImages(RImage *image, RImage *src); + +void RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width, + unsigned height, int dx, int dy); + +void RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness); + +void RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy, + unsigned width, unsigned height, int dx, int dy, + int opaqueness); + +RImage *RScaleImage(RImage *image, unsigned new_width, unsigned new_height); + +RImage *RSmoothScaleImage(RImage *src, unsigned new_width, + unsigned new_height); + +RImage *RRotateImage(RImage *image, float angle); + + +RImage *RMakeTiledImage(RImage *tile, unsigned width, unsigned height); + +RImage* RMakeCenteredImage(RImage *image, unsigned width, unsigned height, + RColor *color); + +/* + * Drawing + */ +Bool RGetPixel(RImage *image, int x, int y, RColor *color); + +void RPutPixel(RImage *image, int x, int y, RColor *color); + +void ROperatePixel(RImage *image, int operation, int x, int y, RColor *color); + +void RPutPixels(RImage *image, RPoint *points, int npoints, int mode, + RColor *color); + +void ROperatePixels(RImage *image, int operation, RPoint *points, + int npoints, int mode, RColor *color); + +int RDrawLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color); + +int ROperateLine(RImage *image, int operation, int x0, int y0, int x1, int y1, + RColor *color); + +void RDrawLines(RImage *image, RPoint *points, int npoints, int mode, + RColor *color); + +void ROperateLines(RImage *image, int operation, RPoint *points, int npoints, + int mode, RColor *color); + +void RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color); + +void ROperateSegments(RImage *image, int operation, RSegment *segs, int nsegs, + RColor *color); + +/* + * Color convertion + */ +void RRGBtoHSV(RColor *color, RHSVColor *hsv); +void RHSVtoRGB(RHSVColor *hsv, RColor *rgb); + +/* + * Painting + */ +void RClearImage(RImage *image, RColor *color); + +void RFillImage(RImage *image, RColor *color); + +void RBevelImage(RImage *image, int bevel_type); + +RImage *RRenderGradient(unsigned width, unsigned height, RColor *from, + RColor *to, int style); + + +RImage *RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, + int style); + + + +/* + * Convertion into X Pixmaps + */ +int RConvertImage(RContext *context, RImage *image, Pixmap *pixmap); + +int RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap, + Pixmap *mask, int threshold); + + +/* + * misc. utilities + */ +RXImage *RCreateXImage(RContext *context, int depth, + unsigned width, unsigned height); + +RXImage *RGetXImage(RContext *context, Drawable d, int x, int y, + unsigned width, unsigned height); + +void RDestroyXImage(RContext *context, RXImage *ximage); + +void RPutXImage(RContext *context, Drawable d, GC gc, RXImage *ximage, + int src_x, int src_y, int dest_x, int dest_y, + unsigned width, unsigned height); + +/* do not free the returned string! */ +const char *RMessageForError(int errorCode); + +int RBlurImage(RImage *image); + +/****** Global Variables *******/ + +extern int RErrorCode; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/Headers/x11/xdnd.h b/Headers/x11/xdnd.h new file mode 100644 index 0000000..a821070 --- /dev/null +++ b/Headers/x11/xdnd.h @@ -0,0 +1,133 @@ +/* + xdnd.c, xdnd.h - C program library for handling the Xdnd protocol + + Copyright (C) 1998 Paul Sheer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + + Further info can also be obtained by emailing the author at, + psheer@obsidian.co.za +*/ + +#ifndef _X_DND_H +#define _X_DND_H + +#define XDND_VERSION 2 + +/* XdndEnter */ +#define XDND_THREE 3 +#define XDND_ENTER_SOURCE_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_ENTER_THREE_TYPES(e) (((e)->xclient.data.l[1] & 0x1UL) == 0) +#define XDND_ENTER_THREE_TYPES_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL) +#define XDND_ENTER_VERSION(e) ((e)->xclient.data.l[1] >> 24) +#define XDND_ENTER_VERSION_SET(e,v) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24) +#define XDND_ENTER_TYPE(e,i) ((e)->xclient.data.l[2 + i]) /* i => (0, 1, 2) */ + +/* XdndPosition */ +#define XDND_POSITION_SOURCE_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_POSITION_ROOT_X(e) ((e)->xclient.data.l[2] >> 16) +#define XDND_POSITION_ROOT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFUL) +#define XDND_POSITION_ROOT_SET(e,x,y) (e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL) +#define XDND_POSITION_TIME(e) ((e)->xclient.data.l[3]) +#define XDND_POSITION_ACTION(e) ((e)->xclient.data.l[4]) + +/* XdndStatus */ +#define XDND_STATUS_TARGET_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_STATUS_WILL_ACCEPT(e) ((e)->xclient.data.l[1] & 0x1L) +#define XDND_STATUS_WILL_ACCEPT_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL) +#define XDND_STATUS_WANT_POSITION(e) ((e)->xclient.data.l[1] & 0x2UL) +#define XDND_STATUS_WANT_POSITION_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x2UL) | (((b) == 0) ? 0 : 0x2UL) +#define XDND_STATUS_RECT_X(e) ((e)->xclient.data.l[2] >> 16) +#define XDND_STATUS_RECT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFL) +#define XDND_STATUS_RECT_WIDTH(e) ((e)->xclient.data.l[3] >> 16) +#define XDND_STATUS_RECT_HEIGHT(e) ((e)->xclient.data.l[3] & 0xFFFFL) +#define XDND_STATUS_RECT_SET(e,x,y,w,h) {(e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL); (e)->xclient.data.l[3] = ((w) << 16) | ((h) & 0xFFFFUL); } +#define XDND_STATUS_ACTION(e) ((e)->xclient.data.l[4]) + +/* XdndLeave */ +#define XDND_LEAVE_SOURCE_WIN(e) ((e)->xclient.data.l[0]) + +/* XdndDrop */ +#define XDND_DROP_SOURCE_WIN(e) ((e)->xclient.data.l[0]) +#define XDND_DROP_TIME(e) ((e)->xclient.data.l[2]) + +/* XdndFinished */ +#define XDND_FINISHED_TARGET_WIN(e) ((e)->xclient.data.l[0]) + +typedef struct _DndClass DndClass; + +struct _DndClass { + + Display *display; + + Atom XdndAware; + Atom XdndSelection; + Atom XdndEnter; + Atom XdndLeave; + Atom XdndPosition; + Atom XdndDrop; + Atom XdndFinished; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndActionMove; + Atom XdndActionLink; + Atom XdndActionAsk; + Atom XdndActionPrivate; + Atom XdndTypeList; + Atom XdndActionList; + Atom XdndActionDescription; + Atom Xdnd_NON_PROTOCOL_ATOM; + Atom version; + Window root_window; + +#define XDND_DROP_STAGE_IDLE 0 +#define XDND_DRAG_STAGE_DRAGGING 1 +#define XDND_DRAG_STAGE_ENTERED 2 +#define XDND_DROP_STAGE_CONVERTING 3 +#define XDND_DROP_STAGE_ENTERED 4 + int stage; + int dragging_version; + int internal_drag; + int want_position; + int ready_to_drop; + int will_accept; + XRectangle rectangle; + Window dropper_window, dragger_window; + Atom *dragger_typelist; + Atom desired_type; + Atom supported_action; + Time time; +/* drop position from last XdndPosition */ + int x, y; + +/* block for only this many seconds on not receiving a XdndFinished from target, default : 10 */ + int time_out; +}; + +void xdnd_init (DndClass * dnd, Display * display); +void xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist); +int xdnd_is_dnd_aware (DndClass * dnd, Window window, int *version, Atom * typelist); +void xdnd_set_type_list (DndClass * dnd, Window window, Atom * typelist); +void xdnd_send_enter (DndClass * dnd, Window window, Window from, Atom * typelist); +void xdnd_send_position (DndClass * dnd, Window window, Window from, Atom action, int x, int y, unsigned long etime); +void xdnd_send_status (DndClass * dnd, Window window, Window from, int will_accept, + int want_position, int x, int y, int w, int h, Atom action); +void xdnd_send_leave (DndClass * dnd, Window window, Window from); +void xdnd_send_drop (DndClass * dnd, Window window, Window from, unsigned long etime); +void xdnd_send_finished (DndClass * dnd, Window window, Window from, int error); +int xdnd_convert_selection (DndClass * dnd, Window window, Window requester, Atom type); +void xdnd_selection_send (DndClass * dnd, XSelectionRequestEvent * request, unsigned char *data, int length); + +#endif /* !_X_DND_H */ diff --git a/Headers/xdps/NSDPSContext.h b/Headers/xdps/NSDPSContext.h new file mode 100644 index 0000000..ba42e0d --- /dev/null +++ b/Headers/xdps/NSDPSContext.h @@ -0,0 +1,136 @@ +/* + NSDPSContext.h + + Encapsulation of Display Postscript contexts + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef _GNUstep_H_NSDPSContext +#define _GNUstep_H_NSDPSContext + +/* Define this to avoid including redefinitions of ps functions introduced + by NSGraphicsContext */ +#define _PSOperators_h_INCLUDE + +#define BOOL XWINDOWSBOOL // prevent X windows BOOL +#include // warning +#undef BOOL +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + ALPHAIMAGE_EXT = 1, + COMPOSITE_EXT = 2, + COMPOSITERECT_EXT = 4, + DISSOLVE_EXT = 8, + READIMAGE_EXT = 16, + SETALPHA_EXT = 32, + FLUSHPAGE_EXT = 64 +} op_extensions_t; + +@class NSData; +@class NSMutableData; +@class NSAffineTransform; +@class GSDisplayServer; + +// +// NSDPSContext class interface +// +@interface NSDPSContext : NSGraphicsContext +{ + DPSContext dps_context; + BOOL is_screen_context; + DPSErrorProc error_proc; + DPSTextProc text_proc; + NSDPSContext *chained_parent; + NSDPSContext *chained_child; + BOOL is_output_traced; + BOOL is_synchronized; + float ctm[6], invctm[6]; + int dps_revision; + op_extensions_t ext_flags; + + NSDPSContext *next_context; + GSDisplayServer *server; + +@public + void *context; +} + +- (void)wait; + +// +// Managing Returned Text and Errors +// ++ (NSString *)stringForDPSError:(const DPSBinObjSeqRec *)error; +- (DPSErrorProc)errorProc; +- (void)setErrorProc:(DPSErrorProc)proc; +- (void)setTextProc:(DPSTextProc)proc; +- (DPSTextProc)textProc; + +// +// Managing Chained Contexts +// +- (void)chainChildContext:(NSDPSContext *)child; +- (NSDPSContext *)childContext; +- (NSDPSContext *)parentContext; +- (void)unchainContext; + +// +// Debugging Aids +// ++ (BOOL)areAllContextsOutputTraced; ++ (BOOL)areAllContextsSynchronized; ++ (void)setAllContextsOutputTraced:(BOOL)flag; ++ (void)setAllContextsSynchronized:(BOOL)flag; +- (BOOL)isOutputTraced; +- (BOOL)isSynchronized; +- (void)setOutputTraced:(BOOL)flag; +- (void)setSynchronized:(BOOL)flag; + +@end + +@interface NSDPSContext (GNUstepXDPS) + +- (Display *)xDisplay; +- (DPSContext)xDPSContext; +- (void *)xrContext; + +- (NSPoint) userPointFromXPoint: (NSPoint)xPoint; +- (NSPoint) XPointFromUserPoint: (NSPoint)userPoint; +- (NSRect) userRectFromXRect: (NSRect)xrect; +- (NSRect) XRectFromUserRect: (NSRect)urect; + +- (op_extensions_t) operatorExtensions; + +@end + +#endif /* _GNUstep_H_NSDPSContext */ diff --git a/Headers/xlib/XGContext.h b/Headers/xlib/XGContext.h new file mode 100644 index 0000000..d9cc744 --- /dev/null +++ b/Headers/xlib/XGContext.h @@ -0,0 +1,47 @@ +/* XGContext + + Backend drawing context using the Xlib library. + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written By: Adam Fedor + Date: Nov 1998 + + This file is part of the GNU Objective C User Interface library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _XGContext_h_INCLUDE +#define _XGContext_h_INCLUDE + +#include "gsc/GSContext.h" +#include "x11/XGServer.h" +#include +#include +#include + +@interface XGContext : GSContext +{ + XGDrawMechanism drawMechanism; +} + +- (XGDrawMechanism) drawMechanism; +- (Display*) xDisplay; +- (void *) xrContext; + +@end + +#endif /* _XGContext_h_INCLUDE */ diff --git a/Headers/xlib/XGGState.h b/Headers/xlib/XGGState.h new file mode 100644 index 0000000..8683c93 --- /dev/null +++ b/Headers/xlib/XGGState.h @@ -0,0 +1,78 @@ +/* XGGState - Implements graphic state drawing for Xlib + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1995 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _XGGState_h_INCLUDE +#define _XGGState_h_INCLUDE + +#include +#include +#include "gsc/GSGState.h" +#include "xlib/xrtools.h" + +@class NSBezierPath; +@class NSFont; + +@interface XGGState : GSGState +{ +@public + void *context; + GC xgcntxt; + int window; + XGCValues gcv; + Drawable draw; + Drawable alpha_buffer; + Region clipregion; + xr_device_color_t color; + + BOOL drawingAlpha; + BOOL sharedGC; /* Do we own the GC or share it? */ +} + +- (void) setWindow: (int)win; +- (void) setDrawable: (Drawable)theDrawable; +- (void) setGraphicContext: (GC)xGraphicContext; +- (void) setGCValues: (XGCValues)values withMask: (int)mask; +- (void) setClipMask; +- (Region) xClipRegion; +- (void) setColor: (xr_device_color_t)acolor; + +- (BOOL) hasDrawable; +- (BOOL) hasGraphicContext; +- (Drawable) drawable; +- (GC) graphicContext; +- (NSPoint) offset; +- (NSRect) clipRect; + +- (void) setFont: (NSFont*)font; +- (NSFont*) currentFont; + +- (XPoint) viewPointToX: (NSPoint)aPoint; +- (XRectangle) viewRectToX: (NSRect)aRect; +- (XPoint) windowPointToX: (NSPoint)aPoint; +- (XRectangle) windowRectToX: (NSRect)aRect; + +@end + +#endif /* _XGGState_h_INCLUDE */ + diff --git a/Headers/xlib/XGGeometry.h b/Headers/xlib/XGGeometry.h new file mode 100644 index 0000000..6c6ceb3 --- /dev/null +++ b/Headers/xlib/XGGeometry.h @@ -0,0 +1,250 @@ +/* -*- mode: ObjC -*- + + XGGeometry + + Point and rectangle manipulations for X-structures + + Written by: woudshoo@xs4all.nl + Date: Nov, 2001 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +/* + This file implements the NSGeometry manipulation functions for + the XPoint and XRectangle structures. + + So most code is copied from NSGeometry, with only the structs changed +*/ + +#ifndef _XGGeometry_h_INCLUDE +#define _XGGeometry_h_INCLUDE + +#include +#include +#include "xlib/XGGState.h" +#include "x11/XGServerWindow.h" + +XRectangle +accessibleRectForWindow (gswindow_device_t *win); + +void +clipXRectsForCopying (gswindow_device_t* winA, XRectangle* rectA, + gswindow_device_t* winB, XRectangle* rectB); + +static inline XPoint +XGMakePoint (short x, short y) +{ + XPoint p; + + p.x = x; + p.y = y; + + return p; +} + +static inline XRectangle +XGMakeRect (short x, short y, unsigned short w, unsigned short h) +{ + XRectangle rect; + + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + + return rect; +} + + +static inline short +XGMinX (XRectangle aRect) +{ + return aRect.x; +} + +static inline short +XGMinY (XRectangle aRect) +{ + return aRect.y; +} + + +static inline short +XGMaxX (XRectangle aRect) +{ + return aRect.x + aRect.width; +} + +static inline short +XGMaxY (XRectangle aRect) +{ + return aRect.y + aRect.height; +} + +static inline short +XGWidth (XRectangle aRect) +{ + return aRect.width; +} + +static inline short +XGHeight (XRectangle aRect) +{ + return aRect.height; +} + + +static inline XRectangle +XGIntersectionRect (XRectangle aRect, XRectangle bRect) +{ + if (XGMaxX (aRect) <= XGMinX (bRect) || XGMaxX (bRect) <= XGMinX (aRect) + || XGMaxY (aRect) <= XGMinY (bRect) || XGMaxY (bRect) <= XGMinY (aRect)) + { + return XGMakeRect (0, 0, 0, 0); + } + else + { + XRectangle rect; + + if (XGMinX (aRect) <= XGMinX (bRect)) + rect.x = bRect.x; + else + rect.x = aRect.x; + + if (XGMaxX (aRect) >= XGMaxX (bRect)) + rect.width = XGMaxX (bRect) - rect.x; + else + rect.width = XGMaxX (aRect) - rect.x; + + if (XGMinY (aRect) <= XGMinY (bRect)) + rect.y = bRect.y; + else + rect.y = aRect.y; + + if (XGMaxY (aRect) >= XGMaxY (bRect)) + rect.height = XGMaxY (bRect) - rect.y; + else + rect.height = XGMaxY (aRect) - rect.y; + + return rect; + } +} + + +static inline BOOL +XGIsEmptyRect (XRectangle aRect) +{ + if (aRect.width == 0 || aRect.height == 0) + return YES; + else + return NO; +} + + +// Just in case this are not defined on a system +#ifndef SHRT_MAX +#define SHRT_MAX 32767 +#endif +#ifndef SHRT_MIN +#define SHRT_MIN (-32768) +#endif + +/* Quick floor using C casts . This casts to short as this is the type X uses + for all geometry. */ +static inline short gs_floor (float f) +{ + if (f >= 0) + { + if (f > SHRT_MAX) + return SHRT_MAX; + else + return (short)f; + } + else + { + if (f < SHRT_MIN) + return SHRT_MIN; + else + { + int g = (int)f; + + if (f - ((float)g) > 0) + { + return g - 1; + } + else + { + return g; + } + } + } +} + +/* + * Inline functions to convert from OpenStep view coordinates or + * OpenStep window coordinates to X window coordinates. + */ +static inline XPoint +XGWindowPointToX (XGGState *s, NSPoint p) +{ + XPoint newPoint; + + newPoint.x = gs_floor(p.x + s->offset.x); + + newPoint.y = gs_floor(s->offset.y - p.y); + + return newPoint; +} + +static inline XRectangle +XGWindowRectToX (XGGState *s, NSRect r) +{ + XRectangle newRect; + + newRect.x = gs_floor(r.origin.x + s->offset.x); + /* We gs_floor the extreme points, and get the width as the difference */ + newRect.width = gs_floor(r.origin.x + s->offset.x + r.size.width) + - newRect.x; + + newRect.y = gs_floor(s->offset.y - r.origin.y - r.size.height); + newRect.height = gs_floor(s->offset.y - r.origin.y) - newRect.y; + + return newRect; +} + +/* + * Inline functions to convert from OpenStep view coordinates or + * OpenStep window coordinates to X window coordinates. + */ + +static inline XPoint +XGViewPointToX(XGGState *s, NSPoint p) +{ + p = [s->ctm pointInMatrixSpace: p]; + return XGWindowPointToX(s, p); +} + +static inline XRectangle +XGViewRectToX(XGGState *s, NSRect r) +{ + r = [s->ctm rectInMatrixSpace: r]; + return XGWindowRectToX(s, r); +} + +#endif /* _XGGeometry_h_INCLUDE */ diff --git a/Headers/xlib/XGPrivate.h b/Headers/xlib/XGPrivate.h new file mode 100644 index 0000000..c37a35e --- /dev/null +++ b/Headers/xlib/XGPrivate.h @@ -0,0 +1,99 @@ +/* + XGPrivate.h + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Adam Fedor + Date: Mar 2002 + + This file is part of the GNUstep GUI X/GPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef _XGPrivate_h_INCLUDE +#define _XGPrivate_h_INCLUDE + +#include "xlib/XGContext.h" +#include "xlib/xrtools.h" +#include + +/* Font function (defined in XGFontManager) */ +extern NSString *XGXFontName(NSString *fontName, float size); + +/* Font functions (defined in XGCommonFont) */ +extern NSString *XGFontName(Display *dpy, XFontStruct *font_struct); +extern NSString *XGFontFamily(Display *dpy, XFontStruct *font_struct); +extern float XGFontPointSize(Display *dpy, XFontStruct *font_struct); +extern int XGWeightOfFont(Display *dpy, XFontStruct *info); +extern NSFontTraitMask XGTraitsOfFont(Display *dpy, XFontStruct *info); +extern BOOL XGFontIsFixedPitch(Display *dpy, XFontStruct *font_struct); +extern NSString *XGFontPropString(Display *dpy, XFontStruct *font_struct, + Atom atom); +extern unsigned long XGFontPropULong(Display *dpy, XFontStruct *font_struct, + Atom atom); + +@interface XGFontEnumerator : GSFontEnumerator +{ +} +@end + +@interface XGFontInfo : GSFontInfo +{ + XFontStruct *font_info; +} +@end + +@interface GSFontInfo (XBackend) + +- (void) drawString: (NSString*)string + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp; +- (void) draw: (const char*) s lenght: (int) len + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp; +- (float) widthOf: (const char*) s lenght: (int) len; +- (void) setActiveFor: (Display*) xdpy gc: (GC) xgcntxt; + +@end + +/* In XGBitmap.m */ +extern int _pixmap_combine_alpha(RContext *context, + RXImage *source_im, RXImage *source_alpha, + RXImage *dest_im, RXImage *dest_alpha, + XRectangle srect, + NSCompositingOperation op, + XGDrawMechanism drawMechanism, + float fraction); + +extern int _bitmap_combine_alpha(RContext *context, + unsigned char * data_planes[5], + int width, int height, + int bits_per_sample, int samples_per_pixel, + int bits_per_pixel, int bytes_per_row, + int colour_space, BOOL one_is_black, + BOOL is_planar, BOOL has_alpha, BOOL fast_min, + RXImage *dest_im, RXImage *dest_alpha, + XRectangle srect, XRectangle drect, + NSCompositingOperation op, + XGDrawMechanism drawMechanism); + + +#endif + + + + diff --git a/Headers/xlib/XftFontInfo.h b/Headers/xlib/XftFontInfo.h new file mode 100644 index 0000000..4f93364 --- /dev/null +++ b/Headers/xlib/XftFontInfo.h @@ -0,0 +1,51 @@ +/* + XftFontInfo + + NSFont helper for GNUstep GUI X/GPS Backend + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Fred Kiefer + Date: July 2001 + + This file is part of the GNUstep GUI X/GPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +// Include this before we include any objC defines, otherwise id is defined +#include +#define id xwindowsid +#include +#undef id + +#include + +@interface XftFontInfo : GSFontInfo +{ + XftFont *font_info; +} + +- (void) drawString: (NSString*)string + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp; +- (void) draw: (const char*) s lenght: (int) len + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp; +- (float) widthOf: (const char*) s lenght: (int) len; +- (void) setActiveFor: (Display*) xdpy gc: (GC) xgcntxt; + +@end diff --git a/Headers/xlib/xrtools.h b/Headers/xlib/xrtools.h new file mode 100644 index 0000000..abdbdba --- /dev/null +++ b/Headers/xlib/xrtools.h @@ -0,0 +1,59 @@ +/* xrtools - Color conversion routines and other low-level X support + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1994 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#ifndef _xrtools_h_INCLUDE +#define _xrtools_h_INCLUDE + +#ifdef HAVE_WRASTER_H +#include "wraster.h" +#else +#include "x11/wraster.h" +#endif + +typedef enum { + gray_colorspace, rgb_colorspace, hsb_colorspace, cmyk_colorspace +} xr_device_colorspace_t; + +typedef struct _xr_device_color { + xr_device_colorspace_t space; + float field[6]; +} xr_device_color_t; + +/* Internal conversion of colors to pixels values */ +extern u_long xrGrayToPixel(RContext * context, float gray); +extern u_long xrRGBToPixel(RContext * context, float red, + float green, float blue); +extern u_long xrHSBToPixel(RContext * context, float h, float s, float b); +extern u_long xrCMYKToPixel(RContext * context, float c, float m, + float y, float k); +extern u_long xrColorToPixel(RContext * context, xr_device_color_t color); + +extern xr_device_color_t xrConvertToGray(xr_device_color_t color); +extern xr_device_color_t xrConvertToRGB(xr_device_color_t color); +extern xr_device_color_t xrConvertToHSB(xr_device_color_t color); +extern xr_device_color_t xrConvertToCMYK(xr_device_color_t color); + +#endif + + diff --git a/Source/.cvsignore b/Source/.cvsignore new file mode 100644 index 0000000..d3e972b --- /dev/null +++ b/Source/.cvsignore @@ -0,0 +1,3 @@ +ix86 +*_obj +*.bundle diff --git a/Source/GNUmakefile b/Source/GNUmakefile new file mode 100644 index 0000000..daafd9f --- /dev/null +++ b/Source/GNUmakefile @@ -0,0 +1,74 @@ +# +# Top level makefile for GNUstep Backend +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Install into the system root by default +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../config.make + +# The library to be compiled, as a library or as a bundle +ifeq ($(BACKEND_BUNDLE),) +LIBRARY_NAME=libgnustep-back +else +BUNDLE_NAME=libgnustep-back +endif + +# +# The list of subproject directories +# +SUBPROJECTS = gsc +ifneq ($(BUILD_XLIB),) +SUBPROJECTS += xlib +endif +ifneq ($(BUILD_XDPS),) +SUBPROJECTS += xdps +endif +ifneq ($(BUILD_X11),) +SUBPROJECTS += x11 +endif +ifneq ($(BUILD_WIN32),) +SUBPROJECTS += win32 +endif +ifneq ($(BUILD_WINLIB),) +SUBPROJECTS += winlib +endif +libgnustep-back_SUBPROJECTS=$(SUBPROJECTS) + +libgnustep-back_OBJC_FILES=GSBackend.m + +libgnustep-back_PRINCIPAL_CLASS=GSBackend + +-include GNUmakefile.preamble + +ifeq ($(BACKEND_BUNDLE),) +include $(GNUSTEP_MAKEFILES)/library.make +else +include $(GNUSTEP_MAKEFILES)/bundle.make +endif + +-include GNUmakefile.postamble diff --git a/Source/GNUmakefile.postamble b/Source/GNUmakefile.postamble new file mode 100644 index 0000000..ebd255a --- /dev/null +++ b/Source/GNUmakefile.postamble @@ -0,0 +1,68 @@ +# +# GNUakefile.postamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Things to do before compiling +before-all:: $(GNUSTEP_TARGET_DIR)/config.h + +# Things to do after compiling +# after-all:: + +# Things to do before installing +# before-install:: + +# Things to do after installing +# after-install:: + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +# after-uninstall:: + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +# after-clean:: + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +after-distclean:: + rm -rf $(GNUSTEP_TARGET_DIR)/config.h + rm -rf $(GNUSTEP_TARGET_CPU) + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check:: + +# +# The config.h file is specific to a target +# +$(GNUSTEP_TARGET_DIR)/config.h: ../config.status + $(GNUSTEP_MAKEFILES)/mkinstalldirs $(GNUSTEP_TARGET_DIR) + -cp ../config.h $(GNUSTEP_TARGET_DIR) diff --git a/Source/GNUmakefile.preamble b/Source/GNUmakefile.preamble new file mode 100644 index 0000000..2532df8 --- /dev/null +++ b/Source/GNUmakefile.preamble @@ -0,0 +1,64 @@ +# +# GNUmakefile.preamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +ADDITIONAL_CPPFLAGS += -Wall + +# Additional flags to pass to the Objective-C compiler +#ADDITIONAL_OBJCFLAGS += + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS += + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS += -I../Headers \ + -I$(GNUSTEP_TARGET_DIR) + +# Additional LDFLAGS to pass to the linker +#ADDITIONAL_LDFLAGS += + +# Additional library directories the linker should search +#ADDITIONAL_LIB_DIRS += + +# +# Flags dealing with installing and uninstalling +# + +# What are the libraries this library depends upon. This is needed for some +# systems where building a shared library requires to pass to the linker +# all the libraries the target library depends upon. + +#LIBRARIES_DEPEND_UPON = + +# Flags for compiling as a bundle +ifneq ($(BACKEND_BUNDLE),) +libgnustep-back_BUNDLE_LIBS = $(GRAPHIC_LIBS) +ADDITIONAL_INCLUDE_DIRS += $(GRAPHIC_CFLAGS) +ADDITIONAL_LIB_DIRS += $(GRAPHIC_LFLAGS) +endif + diff --git a/Source/GSBackend.m b/Source/GSBackend.m new file mode 100644 index 0000000..85ad303 --- /dev/null +++ b/Source/GSBackend.m @@ -0,0 +1,107 @@ +/* GSBackend - backend initialize class + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Adam Fedor + Date: Mar 2002 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "config.h" +#include +#include +#include + +@interface GSBackend : NSObject +{ +} ++ (void) initializeBackend; +@end + +/* Call the correct initalization routines for the choosen + backend. This depends both on configuration data and defaults. + There is also a method to get a different backend class for different + configure parameters (so you could only load in the backend configurations + you wanted. But that is not implemented yet). */ + +#ifdef BUILD_X11 +#include +#endif +#ifdef BUILD_XLIB +#include +#endif +#ifdef BUILD_XDPS +#include +#endif +#ifdef BUILD_WIN32 +// win32 header here +#endif +#ifdef BUILD_WINLIB +// winlib header here +#endif + +@implementation GSBackend + ++ (void) initializeBackend +{ + Class contextClass; + NSString *context; + NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; + + /* Load in only one server */ +#ifdef BUILD_X11 + [XGServer initializeBackend]; +#else +#ifdef BUILD_WIN32 +// win32 initialize here +#else + [NSException raise: NSInternalInconsistencyException + format: @"No Window Server configured in backend"]; +#endif +#endif + + /* The way the frontend is currently structured + it's not possible to have more than one */ +#ifdef BUILD_XDPS + context = @"xdps"; +#endif +#ifdef BUILD_WINLIB + context = @"xwin32"; +#endif +#ifdef BUILD_XLIB + context = @"xlib"; +#endif + + /* What backend context? */ + if ([defs stringForKey: @"GSContext"]) + context = [defs stringForKey: @"GSContext"]; + + if ([context isEqual: @"xdps"]) + contextClass = objc_get_class("NSDPSContext"); + else if ([context isEqual: @"win32"]) + contextClass = objc_get_class("WIN32Context"); + else + contextClass = objc_get_class("XGContext"); + + [contextClass initializeBackend]; +} + +@end + + diff --git a/Source/gsc/GNUmakefile b/Source/gsc/GNUmakefile new file mode 100644 index 0000000..8bb1c23 --- /dev/null +++ b/Source/gsc/GNUmakefile @@ -0,0 +1,59 @@ +# +# Main makefile for GNUstep Backend generic contexts/gstates +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# If you are interested in a warranty or support for this source code, +# contact Scott Christley at scottc@net-community.com +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../back.make +include $(GNUSTEP_MAKEFILES)/common.make + +include ../../config.make + +SUBPROJECT_NAME=gsc + +# The Objective-C source files to be compiled +gsc_OBJC_FILES = \ +GSContext.m \ +GSGState.m \ +GSStreamContext.m \ +externs.m + +gsc_HEADER_FILES_DIR = ../../Headers/gsc +gsc_HEADER_FILES_INSTALL_DIR = gnustep/gsc + +gsc_HEADER_FILES = \ +GSContext.h \ +GSGState.h \ +GSGStateOps.h + +-include GNUmakefile.preamble + +include $(GNUSTEP_MAKEFILES)/subproject.make + +-include GNUmakefile.postamble + diff --git a/Source/gsc/GNUmakefile.preamble b/Source/gsc/GNUmakefile.preamble new file mode 100644 index 0000000..69fb20a --- /dev/null +++ b/Source/gsc/GNUmakefile.preamble @@ -0,0 +1,54 @@ +# +# GNUmakefile.preamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +GNUSTEP_INSTALL_LIBDIR=$(GNUSTEP_LIBRARIES_ROOT) +ADDITIONAL_CPPFLAGS = -DGNUSTEP_INSTALL_LIBDIR=\"$(GNUSTEP_INSTALL_LIBDIR)\" \ + -DGNUSTEP_INSTALL_PREFIX=$(GNUSTEP_INSTALL_PREFIX) \ + $(CONFIG_SYSTEM_DEFS) + +# Additional flags to pass to the Objective-C compiler +#ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +#ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I../../Headers -I../$(GNUSTEP_TARGET_DIR) + +# Additional LDFLAGS to pass to the linker +#ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +#ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# + + diff --git a/Source/gsc/GSContext.m b/Source/gsc/GSContext.m new file mode 100644 index 0000000..2cc7f6f --- /dev/null +++ b/Source/gsc/GSContext.m @@ -0,0 +1,937 @@ +/* -*- mode:ObjC -*- + GSContext - Generic drawing context for non-PS backends + + Copyright (C) 1998,1999 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1998 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gsc/GSContext.h" +#include "gsc/GSStreamContext.h" +#include "gsc/GSGState.h" + +#define GSI_ARRAY_TYPES GSUNION_OBJ + +#if GS_WITH_GC == 0 +#define GSI_ARRAY_RELEASE(A, X) [(X).obj release] +#define GSI_ARRAY_RETAIN(A, X) [(X).obj retain] +#else +#define GSI_ARRAY_RELEASE(A, X) +#define GSI_ARRAY_RETAIN(A, X) (X).obj +#endif + +#ifdef GSIArray +#undef GSIArray +#endif +#include + +/* Error macros */ +#define CHECK_NULL_OUTPUT(outvar) \ + do { if (outvar == NULL) {\ + DPS_ERROR(DPSnulloutput, @"NULL output variable specified"); \ + return; } } while(0) + +#define CHECK_INVALID_FONT(ident) \ + do { if (ident >= [fontid count]) { \ + DPS_ERROR(DPSinvalidfont, @"Cannot find indicated font"); \ + return; } } while(0) + +#define CHECK_STACK_UNDERFLOW(stack) \ + do { if (GSIArrayCount((GSIArray)stack) == 0) { \ + DPS_ERROR(DPSstackunderflow, @"Attempt to pop from empty stack"); \ + return; } } while(0) + +#if 0 +#define CHECK_TYPECHECK(obj, kind) \ + do { if ([kind class] != Nil && !GSObjCIsKindOf(GSObjCClass(obj), [kind class])) {\ + DPS_ERROR(DPStypecheck, @"Invalid object"); \ + return; } } while(0) +#else +#define CHECK_TYPECHECK(obj,kind) +#endif + +#define ctxt_pop(object, stack, kind) \ + do { \ + CHECK_STACK_UNDERFLOW(stack); \ + object = (GSIArrayLastItem((GSIArray)stack)).obj; \ + CHECK_TYPECHECK(object, kind); \ + AUTORELEASE(RETAIN(object)); \ + GSIArrayRemoveLastItem((GSIArray)stack); \ + } while (0) + +#define ctxt_push(object, stack) \ + GSIArrayAddItem((GSIArray)stack, (GSIArrayItem)object) + +/* Globally unique gstate number */ +static unsigned int unique_index = 0; + +@interface GSContext (PrivateOps) +- (void)DPSdefineuserobject; +- (void)DPSexecuserobject: (int)index; +- (void)DPSundefineuserobject: (int)index; +- (void)DPSclear; +- (void)DPScopy: (int)n; +- (void)DPScount: (int *)n; +- (void)DPSdup; +- (void)DPSexch; +- (void)DPSindex: (int)i; +- (void)DPSpop; +@end + +/** + + GSContext +

+ This class is a reasonable attempt at providing PostScript-like + drawing operations. Don't even begin to think that this is a full + PostScript implementation, however. Only operations that do not + require stack handling are implemented. Some other functions that + would require stack handling and are needed for drawing are + implemented in a different way (e.g. colorspace and images). These + functions should also allow for a reasonable simulation of Quartz + functionality. +

+
*/ +@implementation GSContext + +- (id) initWithContextInfo: (NSDictionary *)info +{ + NSString *contextType; + NSZone *z = [self zone]; + + contextType = [info objectForKey: + NSGraphicsContextRepresentationFormatAttributeName]; + if (contextType && [contextType isEqual: NSGraphicsContextPSFormat]) + { + /* Don't call self, since we aren't initialized */ + [super dealloc]; + return [[GSStreamContext allocWithZone: z] initWithContextInfo: info]; + } + + /* A context is only associated with one server. Do not retain + the server, however */ + server = GSCurrentServer(); + + /* Initialize lists and stacks */ + opstack = NSZoneMalloc(z, sizeof(GSIArray_t)); + GSIArrayInitWithZoneAndCapacity((GSIArray)opstack, z, 2); + gstack = NSZoneMalloc(z, sizeof(GSIArray_t)); + GSIArrayInitWithZoneAndCapacity((GSIArray)gstack, z, 2); + gtable = NSCreateMapTable(NSIntMapKeyCallBacks, + NSObjectMapValueCallBacks, 20); + + [super initWithContextInfo: info]; + + return self; +} + +/** + Closes all backend resources and dealloc other ivars. +*/ +- (void) dealloc +{ + NSDebugLog(@"Destroying GS Context"); + GSIArrayEmpty((GSIArray)opstack); + NSZoneFree([self zone], opstack); + GSIArrayEmpty((GSIArray)gstack); + NSZoneFree([self zone], gstack); + NSFreeMapTable(gtable); + [super dealloc]; +} + +/** + Returns YES, since this is a display context. +*/ +- (BOOL)isDrawingToScreen +{ + return YES; +} + +/** + Returns the current GSGState object +*/ +- (GSGState *) currentGState +{ + return gstate; +} + +@end + +@implementation GSContext (Ops) + +/* ----------------------------------------------------------------------- */ +/* Color operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentalpha: (float *)a +{ + [gstate DPScurrentalpha: a]; +} + +- (void) DPScurrentcmykcolor: (float*)c : (float*)m : (float*)y : (float*)k +{ + [gstate DPScurrentcmykcolor:c :m :y :k]; +} + +- (void) DPScurrentgray: (float*)gray +{ + CHECK_NULL_OUTPUT(gray); + [gstate DPScurrentgray: gray]; +} + +- (void) DPScurrenthsbcolor: (float*)h : (float*)s : (float*)b +{ + CHECK_NULL_OUTPUT(h); + CHECK_NULL_OUTPUT(s); + CHECK_NULL_OUTPUT(b); + [gstate DPScurrenthsbcolor:h :s :b]; +} + +- (void) DPScurrentrgbcolor: (float*)r : (float*)g : (float*)b +{ + CHECK_NULL_OUTPUT(r); + CHECK_NULL_OUTPUT(g); + CHECK_NULL_OUTPUT(b); + [gstate DPScurrentrgbcolor:r :g :b]; +} + +- (void) DPSsetalpha: (float)a +{ + [gstate DPSsetalpha: a]; +} + +- (void) DPSsetcmykcolor: (float)c : (float)m : (float)y : (float)k +{ + [gstate DPSsetcmykcolor:c :m :y :k]; +} + +- (void) DPSsetgray: (float)gray +{ + [gstate DPSsetgray: gray]; +} + +- (void) DPSsethsbcolor: (float)h : (float)s : (float)b +{ + [gstate DPSsethsbcolor:h :s :b]; +} + +- (void) DPSsetrgbcolor: (float)r : (float)g : (float)b +{ + [gstate DPSsetrgbcolor:r :g :b]; +} + +- (void) GSSetFillColorspace: (NSDictionary *)dict +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetStrokeColorspace: (NSDictionary *)dict +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetFillColor: (float *)values +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetStrokeColor: (float *)values +{ + [self notImplemented: _cmd]; +} + +/* ----------------------------------------------------------------------- */ +/* Text operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSashow: (float)x : (float)y : (const char *)s +{ + [gstate DPSashow: x : y : s]; +} + +- (void) DPSawidthshow: (float)cx : (float)cy : (int)c : (float)ax : (float)ay : (const char *)s +{ + [gstate DPSawidthshow: cx : cy : c : ax : ay : s]; +} + +- (void) DPScharpath: (const char *)s : (int)b +{ + [gstate DPScharpath: s : b]; +} + +- (void) DPSshow: (const char *)s +{ + [gstate DPSshow: s]; +} + +- (void) DPSwidthshow: (float)x : (float)y : (int)c : (const char *)s +{ + [gstate DPSwidthshow: x : y : c : s]; +} + +- (void) DPSxshow: (const char *)s : (const float*)numarray : (int)size +{ + [gstate DPSxshow: s : numarray : size]; +} + +- (void) DPSxyshow: (const char *)s : (const float*)numarray : (int)size +{ + [gstate DPSxyshow: s : numarray : size]; +} + +- (void) DPSyshow: (const char *)s : (const float*)numarray : (int)size +{ + [gstate DPSyshow: s : numarray : size]; +} + +- (void) GSSetCharacterSpacing: (float)extra +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetFont: (NSFont*)font +{ + [gstate setFont: font]; +} + +- (void) GSSetFontSize: (float)size +{ + [self notImplemented: _cmd]; +} + +- (NSAffineTransform *) GSGetTextCTM +{ + [self notImplemented: _cmd]; + return nil; +} + +- (NSPoint) GSGetTextPosition +{ + [self notImplemented: _cmd]; + return NSMakePoint(0,0); +} + +- (void) GSSetTextCTM: (NSAffineTransform *)ctm +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetTextDrawingMode: (GSTextDrawingMode)mode +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetTextPosition: (NSPoint)loc +{ + [self notImplemented: _cmd]; +} + +- (void) GSShowText: (const char *)string : (size_t) length +{ + [self notImplemented: _cmd]; +} + +- (void) GSShowGlyphs: (const NSGlyph *)glyphs : (size_t) length +{ + [self notImplemented: _cmd]; +} + +/* ----------------------------------------------------------------------- */ +/* Gstate Handling */ +/* ----------------------------------------------------------------------- */ + +- (void) DPScurrentgstate: (int)gst +{ + if (gst) + { + /* Associate/copy current gstate with gst */ + ctxt_push([NSNumber numberWithInt: gst], opstack); + ctxt_push(gstate, opstack); + [self DPSdefineuserobject]; + [self DPSexecuserobject: gst]; + } +} + +- (void) DPSgrestore +{ + if (GSIArrayCount((GSIArray)gstack) == 0) + return; + RELEASE(gstate); + gstate = (GSIArrayLastItem((GSIArray)gstack)).obj; + ctxt_pop(gstate, gstack, GSGState); + RETAIN(gstate); +} + +- (void) DPSgsave +{ + ctxt_push(gstate, gstack); + AUTORELEASE(gstate); + gstate = [gstate copy]; +} + +- (void) DPSgstate +{ + ctxt_push(AUTORELEASE([gstate copy]), opstack); +} + +- (void) DPSinitgraphics +{ + [gstate DPSinitgraphics]; +} + +- (void) DPSsetgstate: (int)gst +{ + if (gst) + { + [self DPSexecuserobject: gst]; + RELEASE(gstate); + ctxt_pop(gstate, opstack, GSGState); + RETAIN(gstate); + } + else + DESTROY(gstate); +} + +/* Should work the same as 'unique_index exch defineuserobject' */ +- (int) GSDefineGState +{ + GSGState *obj; + if(gstate == nil) + { + DPS_ERROR(DPSundefined, @"No gstate"); + return 0; + } + ctxt_pop(obj, opstack, GSGState); + NSMapInsert(gtable, (void *)++unique_index, obj); + return unique_index; +} + +- (void) GSUndefineGState: (int)gst +{ + [self DPSundefineuserobject: gst]; +} + +/* Should work the same as 'currentgstate pop' */ +- (void) GSReplaceGState: (int)gst +{ + if(gst <= 0) + return; + NSMapInsert(gtable, (void *)gst, gstate); +} + +/* ----------------------------------------------------------------------- */ +/* Gstate operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentflat: (float*)flatness +{ + CHECK_NULL_OUTPUT(flatness); + [gstate DPScurrentflat: flatness]; +} + +- (void) DPScurrentlinecap: (int*)linecap +{ + [gstate DPScurrentlinecap: linecap]; +} + +- (void) DPScurrentlinejoin: (int*)linejoin +{ + [gstate DPScurrentlinejoin: linejoin]; +} + +- (void) DPScurrentlinewidth: (float*)width +{ + [gstate DPScurrentlinewidth: width]; +} + +- (void) DPScurrentmiterlimit: (float*)limit +{ + CHECK_NULL_OUTPUT(limit); + [gstate DPScurrentmiterlimit: limit]; +} + +- (void) DPScurrentpoint: (float*)x : (float*)y +{ + CHECK_NULL_OUTPUT(x); + CHECK_NULL_OUTPUT(y); + [gstate DPScurrentpoint:x :y]; +} + +- (void) DPScurrentstrokeadjust: (int*)b +{ + CHECK_NULL_OUTPUT(b); + [gstate DPScurrentstrokeadjust: b]; +} + +- (void) DPSsetdash: (const float*)pat : (int)size : (float)offset +{ + [gstate DPSsetdash: pat : size : offset]; +} + +- (void) DPSsetflat: (float)flatness +{ + [gstate DPSsetflat: flatness]; +} + +- (void) DPSsethalftonephase: (float)x : (float)y +{ + [self notImplemented: _cmd]; +} + +- (void) DPSsetlinecap: (int)linecap +{ + [gstate DPSsetlinecap: linecap]; +} + +- (void) DPSsetlinejoin: (int)linejoin +{ + [gstate DPSsetlinejoin: linejoin]; +} + +- (void) DPSsetlinewidth: (float)width +{ + [gstate DPSsetlinewidth: width]; +} + +- (void) DPSsetmiterlimit: (float)limit +{ + [gstate DPSsetmiterlimit: limit]; +} + +- (void) DPSsetstrokeadjust: (int)b +{ + [gstate DPSsetstrokeadjust: b]; +} + +/* ----------------------------------------------------------------------- */ +/* Matrix operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSconcat: (const float*)m +{ + [gstate DPSconcat: m]; +} + +- (void) DPSinitmatrix +{ + [gstate DPSinitmatrix]; +} + +- (void) DPSrotate: (float)angle +{ + [gstate DPSrotate: angle]; +} + +- (void) DPSscale: (float)x : (float)y +{ + [gstate DPSscale:x :y]; +} + +- (void) DPStranslate: (float)x : (float)y +{ + [gstate DPStranslate:x :y]; +} + +- (NSAffineTransform *) GSCurrentCTM +{ + [self notImplemented: _cmd]; + return nil; +} + +- (void) GSSetCTM: (NSAffineTransform *)ctm +{ + [self notImplemented: _cmd]; +} + +- (void) GSConcatCTM: (NSAffineTransform *)ctm +{ + [self notImplemented: _cmd]; +} + +/* ----------------------------------------------------------------------- */ +/* Paint operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSarc: (float)x : (float)y : (float)r : (float)angle1 + : (float)angle2 +{ + [gstate DPSarc: x : y : r : angle1 : angle2]; +} + +- (void) DPSarcn: (float)x : (float)y : (float)r : (float)angle1 + : (float)angle2 +{ + [gstate DPSarcn: x : y : r : angle1 : angle2]; +} + +- (void) DPSarct: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r; +{ + [gstate DPSarct: x1 : y1 : x2 : y2 : r]; +} + +- (void) DPSclip +{ + [gstate DPSclip]; +} + +- (void) DPSclosepath +{ + [gstate DPSclosepath]; +} + +- (void) DPScurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 + : (float)x3 : (float)y3 +{ + [gstate DPScurveto: x1 : y1 : x2 : y2 : x3 : y3]; +} + +- (void) DPSeoclip +{ + [gstate DPSeoclip]; +} + +- (void) DPSeofill +{ + [gstate DPSeofill]; +} + +- (void) DPSfill +{ + [gstate DPSfill]; +} + +- (void) DPSflattenpath +{ + [gstate DPSflattenpath]; +} + +- (void) DPSinitclip +{ + [gstate DPSinitclip]; +} + +- (void) DPSlineto: (float)x : (float)y +{ + [gstate DPSlineto: x : y]; +} + +- (void) DPSmoveto: (float)x : (float)y +{ + [gstate DPSmoveto: x : y]; +} + +- (void) DPSnewpath +{ + [gstate DPSnewpath]; +} + +- (void) DPSpathbbox: (float*)llx : (float*)lly : (float*)urx : (float*)ury +{ + [gstate DPSpathbbox: llx : lly : urx : ury]; +} + +- (void) DPSrcurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 + : (float)x3 : (float)y3 +{ + [gstate DPSrcurveto: x1 : y1 : x2 : y2 : x3 : y3]; +} + +- (void) DPSrectclip: (float)x : (float)y : (float)w : (float)h +{ + [gstate DPSrectclip: x : y : w : h]; +} + +- (void) DPSrectfill: (float)x : (float)y : (float)w : (float)h +{ + [gstate DPSrectfill:x :y :w :h]; +} + +- (void) DPSrectstroke: (float)x : (float)y : (float)w : (float)h +{ + [gstate DPSrectstroke:x :y :w :h]; +} + +- (void) DPSreversepath +{ + [gstate DPSreversepath]; +} + +- (void) DPSrlineto: (float)x : (float)y +{ + [gstate DPSrlineto: x : y]; +} + +- (void) DPSrmoveto: (float)x : (float)y +{ + [gstate DPSrmoveto: x : y]; +} + +- (void) DPSstroke +{ + [gstate DPSstroke]; +} + +- (void) GSSendBezierPath: (NSBezierPath *)path +{ + [self notImplemented: _cmd]; +} + +- (void) GSRectClipList: (const NSRect *)rects : (int) count +{ + [self notImplemented: _cmd]; +} + +- (void) GSRectFillList: (const NSRect *)rects : (int) count +{ + [self notImplemented: _cmd]; +} + +/* ----------------------------------------------------------------------- */ +/* Window system ops */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentoffset: (int *)x : (int *)y +{ + if (x && y) + { + NSPoint offset = [gstate offset]; + *x = offset.x; + *y = offset.y; + } +} + +- (void) DPSsetoffset: (short int)x : (short int)y +{ + [gstate setOffset: NSMakePoint(x,y)]; +} + +/*-------------------------------------------------------------------------*/ +/* Graphics Extension Ops */ +/*-------------------------------------------------------------------------*/ +- (void) DPScomposite: (float)x : (float)y : (float)w : (float)h + : (int)gstateNum : (float)dx : (float)dy : (int)op +{ + NSRect rect; + NSPoint p; + GSGState *g = gstate; + + if (gstateNum) + { + [self DPSexecuserobject: gstateNum]; + ctxt_pop(g, opstack, GSGState); + } + + rect = NSMakeRect(x, y, w, h); + p = NSMakePoint(dx, dy); + + [gstate compositeGState: g fromRect: rect toPoint: p op: op]; +} + +- (void) DPScompositerect: (float)x : (float)y : (float)w : (float)h : (int)op +{ + [gstate compositerect: NSMakeRect(x, y, w, h) op: op]; +} + +- (void) DPSdissolve: (float)x : (float)y : (float)w : (float)h + : (int)gstateNum : (float)dx : (float)dy : (float)delta +{ + NSRect rect; + NSPoint p; + GSGState *g = gstate; + + if (gstateNum) + { + [self DPSexecuserobject: gstateNum]; + ctxt_pop(g, opstack, GSGState); + } + + rect = NSMakeRect(x, y, w, h); + p = NSMakePoint(dx, dy); + + [gstate dissolveGState: g fromRect: rect toPoint: p delta: delta]; +} + +- (void) GSDrawImage: (NSRect) rect: (void *) imageref +{ + [self notImplemented: _cmd]; +} + +/* ----------------------------------------------------------------------- */ +/* Client functions */ +/* ----------------------------------------------------------------------- */ +- (void) DPSPrintf: (char *)fmt : (va_list)args +{ + /* Do nothing. We can't parse PostScript */ +} + +- (void) DPSWriteData: (char *)buf : (unsigned int)count +{ + /* Do nothing. We can't parse PostScript */ +} + +@end + +/* ----------------------------------------------------------------------- */ +/* NSGraphics Ops */ +/* ----------------------------------------------------------------------- */ +@implementation GSContext (NSGraphics) +/* + * Render Bitmap Images + */ +- (void) NSDrawBitmap: (NSRect) rect : (int) pixelsWide : (int) pixelsHigh + : (int) bitsPerSample : (int) samplesPerPixel + : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar + : (BOOL) hasAlpha : (NSString *) colorSpaceName + : (const unsigned char *const [5]) data +{ + NSAffineTransform *trans; + NSSize scale; + + // Compute the transformation matrix + scale = NSMakeSize(NSWidth(rect) / pixelsWide, + NSHeight(rect) / pixelsHigh); + trans = [NSAffineTransform transform]; + [trans translateToPoint: rect.origin]; + [trans scaleBy: scale.width : scale.height]; + + /* This does essentially what the DPS...image operators do, so + as to avoid an extra method call */ + [gstate DPSimage: trans + : pixelsWide : pixelsHigh + : bitsPerSample : samplesPerPixel + : bitsPerPixel : bytesPerRow + : isPlanar + : hasAlpha : colorSpaceName + : data]; +} + +- (void) GSWSetViewIsFlipped: (BOOL) flipped +{ + if(gstate) + gstate->viewIsFlipped = flipped; +} + +/* ----------------------------------------------------------------------- */ +/* Data operations - Obsolete but possibly still useful */ +/* ----------------------------------------------------------------------- */ + +- (void)DPSdefineuserobject +{ + int n; + id obj; + NSNumber *number; + ctxt_pop(obj, opstack, NSObject); + ctxt_pop(number, opstack, NSNumber); + n = [number intValue]; + if (n < 0) + DPS_ERROR(DPSinvalidparam, @"Invalid userobject index"); + else + NSMapInsert(gtable, (void *)n, obj); +} + +- (void)DPSexecuserobject: (int)index +{ + if (index < 0 || NSMapGet(gtable, (void *)index) == nil) + { + DPS_ERROR(DPSinvalidparam, @"Invalid userobject index"); + return; + } + ctxt_push((id)NSMapGet(gtable, (void *)index), opstack); +} + +- (void)DPSundefineuserobject: (int)index +{ + if (index < 0 || NSMapGet(gtable, (void *)index) == nil) + { + DPS_ERROR(DPSinvalidparam, @"Invalid gstate index"); + return; + } + NSMapRemove(gtable, (void *)index); +} + +- (void)DPSclear +{ + GSIArrayEmpty((GSIArray)opstack); + GSIArrayInitWithZoneAndCapacity((GSIArray)opstack, [self zone], 2); +} + +- (void)DPScopy: (int)n +{ + unsigned count = GSIArrayCount((GSIArray)opstack); + int i; + + for (i = 0; i < n; i++) + { + NSObject *obj = (GSIArrayItemAtIndex((GSIArray)opstack, count - n + i)).obj; + + ctxt_push(obj, opstack); + } +} + +- (void)DPScount: (int *)n +{ + CHECK_NULL_OUTPUT(n); + *n = GSIArrayCount((GSIArray)opstack); +} + +- (void)DPSdup +{ + NSObject *obj = (GSIArrayLastItem((GSIArray)opstack)).obj; + + ctxt_push(obj, opstack); +} + +- (void)DPSexch +{ + unsigned count = GSIArrayCount((GSIArray)opstack); + + if (count < 2) + { + DPS_ERROR(DPSstackunderflow, @"Attempt to exch in empty stack"); + return; + } + GSIArrayInsertItem((GSIArray)opstack, + GSIArrayLastItem((GSIArray)opstack), count-2); + GSIArrayRemoveLastItem((GSIArray)opstack); +} + +- (void)DPSindex: (int)i +{ + unsigned count = GSIArrayCount((GSIArray)opstack); + NSObject *obj = (GSIArrayItemAtIndex((GSIArray)opstack, count - i)).obj; + + ctxt_push(obj, opstack); +} + +- (void)DPSpop +{ + id obj; + ctxt_pop(obj, opstack, NSObject); +} +@end diff --git a/Source/gsc/GSGState.m b/Source/gsc/GSGState.m new file mode 100644 index 0000000..baf0266 --- /dev/null +++ b/Source/gsc/GSGState.m @@ -0,0 +1,603 @@ +/* GSGState - Generic graphic state + + Copyright (C) 1998 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Mar 2002 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#include "config.h" +#include +#include +#include +#include +#include "gsc/GSContext.h" +#include "gsc/GSGState.h" +#include "math.h" + +#define CHECK_PATH \ + if (!path) \ + { \ + path = [NSBezierPath new]; \ + } + +#define AINDEX 5 + +@implementation GSGState + +/* Designated initializer. */ +- initWithDrawContext: (GSContext *)drawContext +{ + [super init]; + + drawcontext = drawContext; + ctm = [[NSAffineTransform allocWithZone: GSObjCZone(self)] init]; + path = nil; + font = nil; + offset = NSMakePoint(0, 0); + return self; +} + +- (void) dealloc +{ + TEST_RELEASE(font); + TEST_RELEASE(path); + RELEASE(ctm); + [super dealloc]; +} + +- (id) deepen +{ + NSZone *zone = GSObjCZone(self); + + if (path) + self->path = [path copyWithZone: zone]; + + self->ctm = [ctm copyWithZone: zone]; + + // Just retain the font + if (font != nil) + RETAIN(font); + + return self; +} + +- copyWithZone: (NSZone *)zone +{ + GSGState *new = (GSGState *)NSCopyObject(self, 0, zone); + /* Do a deep copy since gstates are isolated from each other */ + return [new deepen]; +} + +- (void) setFont: (NSFont*)newFont +{ + if (font == newFont) + return; + ASSIGN(font, newFont); +} + +- (NSFont*) currentFont +{ + return font; +} + +- (void) setOffset: (NSPoint)theOffset +{ + offset = theOffset; +} + +- (NSPoint) offset +{ + return offset; +} + +- (void) compositeGState: (GSGState *)source + fromRect: (NSRect)aRect + toPoint: (NSPoint)aPoint + op: (NSCompositingOperation)op +{ + [self subclassResponsibility: _cmd]; +} + +- (void) dissolveGState: (GSGState *)source + fromRect: (NSRect)aRect + toPoint: (NSPoint)aPoint + delta: (float)delta +{ + [self subclassResponsibility: _cmd]; +} + +- (void) compositerect: (NSRect)aRect + op: (NSCompositingOperation)op +{ + [self subclassResponsibility: _cmd]; +} + +- (NSPoint) pointInMatrixSpace: (NSPoint)aPoint +{ + return [ctm pointInMatrixSpace: aPoint]; +} + +- (NSPoint) deltaPointInMatrixSpace: (NSPoint)aPoint +{ + return [ctm deltaPointInMatrixSpace: aPoint]; +} + +- (NSRect) rectInMatrixSpace: (NSRect)rect +{ + return [ctm rectInMatrixSpace: rect]; +} + +@end + +@implementation GSGState (Ops) + +/* ----------------------------------------------------------------------- */ +/* Color operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentalpha: (float*)a +{ + [self notImplemented: _cmd]; +} + +- (void) DPScurrentcmykcolor: (float*)c : (float*)m : (float*)y : (float*)k +{ + [self notImplemented: _cmd]; +} + +- (void) DPScurrentgray: (float*)gray +{ + [self notImplemented: _cmd]; +} + +- (void) DPScurrenthsbcolor: (float*)h : (float*)s : (float*)b +{ + [self notImplemented: _cmd]; +} + +- (void) DPScurrentrgbcolor: (float*)r : (float*)g : (float*)b +{ + [self notImplemented: _cmd]; +} + +- (void) DPSsetalpha: (float)a +{ + [self notImplemented: _cmd]; +} + +- (void) DPSsetcmykcolor: (float)c : (float)m : (float)y : (float)k +{ + [self notImplemented: _cmd]; +} + +- (void) DPSsetgray: (float)gray +{ + [self notImplemented: _cmd]; +} + +- (void) DPSsethsbcolor: (float)h : (float)s : (float)b +{ + [self notImplemented: _cmd]; +} + +- (void) DPSsetrgbcolor: (float)r : (float)g : (float)b +{ + [self notImplemented: _cmd]; +} + + +- (void) GSSetFillColorspace: (NSDictionary *)dict +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetStrokeColorspace: (NSDictionary *)dict +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetFillColor: (float *)values +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetStrokeColor: (float *)values +{ + [self notImplemented: _cmd]; +} + +/* ----------------------------------------------------------------------- */ +/* Text operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSashow: (float)x : (float)y : (const char*)s +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSawidthshow: (float)cx : (float)cy : (int)c : (float)ax : (float)ay + : (const char*)s +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPScharpath: (const char*)s : (int)b +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSshow: (const char*)s +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSwidthshow: (float)x : (float)y : (int)c : (const char*)s +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSxshow: (const char*)s : (const float*)numarray : (int)size +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSxyshow: (const char*)s : (const float*)numarray : (int)size +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSyshow: (const char*)s : (const float*)numarray : (int)size +{ + [self subclassResponsibility: _cmd]; +} + + +/* ----------------------------------------------------------------------- */ +/* Gstate operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSinitgraphics +{ + [self subclassResponsibility: _cmd]; +} + +- (void)DPScurrentflat: (float *)flatness +{ + if (path) + *flatness = [path flatness]; + else + *flatness = 1.0; +} + +- (void) DPScurrentlinecap: (int*)linecap +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPScurrentlinejoin: (int*)linejoin +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPScurrentlinewidth: (float*)width +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPScurrentmiterlimit: (float*)limit +{ + [self subclassResponsibility: _cmd]; +} + +- (void)DPScurrentpoint: (float *)x : (float *)y +{ + NSAffineTransform *ictm; + NSPoint user; + + // This is rather slow, but it is not used very often + ictm = [ctm copyWithZone: GSObjCZone(self)]; + [ictm inverse]; + user = [ictm pointInMatrixSpace: [path currentPoint]]; + RELEASE(ictm); + *x = user.x; + *y = user.y; +} + +- (void) DPScurrentstrokeadjust: (int*)b +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSsetdash: (const float*)pat : (int)size : (float)offset +{ + [self subclassResponsibility: _cmd]; +} + +- (void)DPSsetflat: (float)flatness +{ + if (path) + [path setFlatness: flatness]; +} + +- (void) DPSsetlinecap: (int)linecap +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSsetlinejoin: (int)linejoin +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSsetlinewidth: (float)width +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSsetmiterlimit: (float)limit +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSsetstrokeadjust: (int)b +{ + [self subclassResponsibility: _cmd]; +} + +/* ----------------------------------------------------------------------- */ +/* Matrix operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSconcat: (const float *)m +{ + [ctm concatenateWithMatrix: m]; +} + +- (void)DPSinitmatrix +{ + [ctm makeIdentityMatrix]; +} + +- (void)DPSrotate: (float)angle +{ + [ctm rotateByDegrees: angle]; +} + +- (void)DPSscale: (float)x : (float)y +{ + [ctm scaleBy: x : y]; +} + +- (void)DPStranslate: (float)x : (float)y +{ + [ctm translateToPoint: NSMakePoint(x, y)]; +} + +- (NSAffineTransform *) GSCurrentCTM +{ + return [ctm copy]; +} + +- (void) GSSetCTM: (NSAffineTransform *)newctm +{ + ASSIGN(ctm, newctm); +} + +- (void) GSConcatCTM: (NSAffineTransform *)newctm +{ + [ctm concatenateWith: newctm]; +} + +/* ----------------------------------------------------------------------- */ +/* Paint operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSarc: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2 +{ + NSPoint center = [ctm pointInMatrixSpace: NSMakePoint(x, y)]; + NSSize radius = [ctm sizeInMatrixSpace: NSMakeSize(r, r)]; + + CHECK_PATH; + [path appendBezierPathWithArcWithCenter: center + radius: radius.width + startAngle: angle1 + endAngle: angle2 + clockwise: NO]; +} + +- (void) DPSarcn: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2 +{ + NSPoint center = [ctm pointInMatrixSpace: NSMakePoint(x, y)]; + NSSize radius = [ctm sizeInMatrixSpace: NSMakeSize(r, r)]; + + CHECK_PATH; + [path appendBezierPathWithArcWithCenter: center + radius: radius.width + startAngle: angle1 + endAngle: angle2 + clockwise: YES]; +} + +- (void)DPSarct: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r +{ + [self notImplemented: _cmd]; +} + +- (void) DPSclip +{ + [self subclassResponsibility: _cmd]; +} + +- (void)DPSclosepath +{ + CHECK_PATH; + [path closePath]; +} + +- (void)DPScurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3 : (float)y3 +{ + NSPoint p1 = [ctm pointInMatrixSpace: NSMakePoint(x1, y1)]; + NSPoint p2 = [ctm pointInMatrixSpace: NSMakePoint(x2, y2)]; + NSPoint p3 = [ctm pointInMatrixSpace: NSMakePoint(x3, y3)]; + + CHECK_PATH; + [path curveToPoint: p3 controlPoint1: p1 controlPoint2: p2]; +} + +- (void) DPSeoclip +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSeofill +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSfill +{ + [self subclassResponsibility: _cmd]; +} + +- (void)DPSflattenpath +{ + if (path) + ASSIGN(path, [path bezierPathByFlatteningPath]); +} + +- (void) DPSinitclip; +{ + [self subclassResponsibility: _cmd]; +} + +- (void)DPSlineto: (float)x : (float)y +{ + NSPoint p = [ctm pointInMatrixSpace: NSMakePoint(x, y)]; + + CHECK_PATH; + [path lineToPoint: p]; +} + +- (void)DPSmoveto: (float)x : (float)y +{ + NSPoint p = [ctm pointInMatrixSpace: NSMakePoint(x, y)]; + + CHECK_PATH; + [path moveToPoint: p]; +} + +- (void)DPSnewpath +{ + if (path) + [path removeAllPoints]; +} + +- (void)DPSpathbbox: (float *)llx : (float *)lly : (float *)urx : (float *)ury +{ + if (path) + { + NSRect rect = [path controlPointBounds]; + + // FIXME Should convert back to user space + if (llx) + *llx = NSMinX(rect); + if (lly) + *lly = NSMinY(rect); + if (urx) + *urx = NSMaxX(rect); + if (ury) + *ury = NSMaxY(rect); + } +} + +- (void)DPSrcurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3 : (float)y3 +{ + NSPoint p1 = [ctm deltaPointInMatrixSpace: NSMakePoint(x1, y1)]; + NSPoint p2 = [ctm deltaPointInMatrixSpace: NSMakePoint(x2, y2)]; + NSPoint p3 = [ctm deltaPointInMatrixSpace: NSMakePoint(x3, y3)]; + + CHECK_PATH; + [path relativeCurveToPoint: p3 + controlPoint1: p1 + controlPoint2: p2]; +} + +- (void) DPSrectclip: (float)x : (float)y : (float)w : (float)h +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSrectfill: (float)x : (float)y : (float)w : (float)h +{ + [self subclassResponsibility: _cmd]; +} + +- (void) DPSrectstroke: (float)x : (float)y : (float)w : (float)h +{ + [self subclassResponsibility: _cmd]; +} + +- (void)DPSreversepath +{ + if (path) + ASSIGN(path, [path bezierPathByReversingPath]); +} + +- (void)DPSrlineto: (float)x : (float)y +{ + NSPoint p = [ctm deltaPointInMatrixSpace: NSMakePoint(x, y)]; + + CHECK_PATH; + [path relativeLineToPoint: p]; +} + +- (void)DPSrmoveto: (float)x : (float)y +{ + NSPoint p = [ctm deltaPointInMatrixSpace: NSMakePoint(x, y)]; + + CHECK_PATH; + [path relativeMoveToPoint: p]; +} + +- (void) DPSstroke; +{ + [self subclassResponsibility: _cmd]; +} + +- (void) GSSendBezierPath: (NSBezierPath *)newpath +{ + if (path) + [path appendBezierPath: path]; + else + ASSIGN(path, newpath); +} + +- (void) GSRectFillList: (const NSRect *)rects : (int) count +{ + [self notImplemented: _cmd]; +} + +- (void)DPSimage: (NSAffineTransform*) matrix + : (int) pixelsWide : (int) pixelsHigh + : (int) bitsPerSample : (int) samplesPerPixel + : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar + : (BOOL) hasAlpha : (NSString *) colorSpaceName + : (const unsigned char *const [5]) data +{ + [self subclassResponsibility: _cmd]; +} +@end + + diff --git a/Source/gsc/GSStreamContext.m b/Source/gsc/GSStreamContext.m new file mode 100644 index 0000000..7911af6 --- /dev/null +++ b/Source/gsc/GSStreamContext.m @@ -0,0 +1,790 @@ +/* -*- C++ -*- + GSStreamContext - Drawing context using the XR Library. + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1995 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#include "config.h" +#include "gsc/GSContext.h" +#include "gsc/GSStreamContext.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +@interface GSStreamContext (Private) + +- (void) output: (const char*)s; + +@end + +@implementation GSStreamContext + +- (void) destroyContext; +{ + if (gstream) + fclose(gstream); + [super destroyContext]; +} + +- initWithContextInfo: (NSDictionary *)info +{ + if (info && [info objectForKey: @"NSOutputFile"]) + { + NSString *path = [info objectForKey: @"NSOutputFile"]; + gstream = fopen([path fileSystemRepresentation], "w"); + if (!gstream) + { + NSDebugLLog(@"GSContext", @"%@: Could not open printer file %@", + DPSinvalidfileaccess, path); + return nil; + } + } + else + { + NSDebugLLog(@"GSContext", @"%@: No stream file specified", + DPSconfigurationerror); + return nil; + } + + [super initWithContextInfo: info]; + return self; +} + +- (BOOL)isDrawingToScreen +{ + return NO; +} + +- (GSGState *) currentGState +{ + return nil; +} + +@end + +@implementation GSStreamContext (Ops) +/* ----------------------------------------------------------------------- */ +/* Color operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentalpha: (float*) a +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentcmykcolor: (float*) c: (float*) m: (float*) y: (float*) k +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentgray: (float*) gray +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrenthsbcolor: (float*) h: (float*) s: (float*) b +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentrgbcolor: (float*) r: (float*) g: (float*) b +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPSsetalpha: (float) a +{ + fprintf(gstream, "%g setalpha\n", a); +} + +- (void) DPSsetcmykcolor: (float) c: (float) m: (float) y: (float) k +{ + fprintf(gstream, "%g %g %g %g setcmykcolor\n", c, m, y, k); +} + +- (void) DPSsetgray: (float) gray +{ + fprintf(gstream, "%g setgray\n", gray); +} + +- (void) DPSsethsbcolor: (float) h: (float) s: (float) b +{ + fprintf(gstream, "%g %g %g sethsbcolor\n", h, s, b); +} + +- (void) DPSsetrgbcolor: (float) r: (float) g: (float) b +{ + fprintf(gstream, "%g %g %g setrgbcolor\n", r, g, b); +} + + +- (void) GSSetFillColorspace: (NSDictionary *) dict +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetStrokeColorspace: (NSDictionary *) dict +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetFillColor: (float *) values +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetStrokeColor: (float *) values +{ + [self notImplemented: _cmd]; +} + + +/* ----------------------------------------------------------------------- */ +/* Text operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSashow: (float) x: (float) y: (const char*) s +{ + fprintf(gstream, "%g %g %s ashow\n", x, y, s); +} + +- (void) DPSawidthshow: (float) cx: (float) cy: (int) c: (float) ax: (float) ay: (const char*) s +{ + fprintf(gstream, "%g %g %d %g %g %s awidthshow\n", cx, cy, c, ax, ay, s); +} + +- (void) DPScharpath: (const char*) s: (int) b +{ + fprintf(gstream, "%s %d charpath\n", s, b); +} + +- (void) DPSshow: (const char*) s +{ + fprintf(gstream, "%s show\n", s); +} + +- (void) DPSwidthshow: (float) x: (float) y: (int) c: (const char*) s +{ + fprintf(gstream, "%g %g %d %s widthshow\n", x, y, c, s); +} + +- (void) DPSxshow: (const char*) s: (const float*) numarray: (int) size +{ +} + +- (void) DPSxyshow: (const char*) s: (const float*) numarray: (int) size +{ +} + +- (void) DPSyshow: (const char*) s: (const float*) numarray: (int) size +{ +} + + +- (void) GSSetCharacterSpacing: (float) extra +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetFont: (NSFont*) font +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetFontSize: (float) size +{ + [self notImplemented: _cmd]; +} + +- (NSAffineTransform *) GSGetTextCTM +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); + return nil; +} + +- (NSPoint) GSGetTextPosition +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); + return NSMakePoint(0,0); +} + +- (void) GSSetTextCTM: (NSAffineTransform *) ctm +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetTextDrawingMode: (GSTextDrawingMode) mode +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetTextPosition: (NSPoint) loc +{ + [self notImplemented: _cmd]; +} + +- (void) GSShowText: (const char *) string: (size_t) length +{ + [self notImplemented: _cmd]; +} + +- (void) GSShowGlyphs: (const NSGlyph *) glyphs: (size_t) length +{ + [self notImplemented: _cmd]; +} + + +/* ----------------------------------------------------------------------- */ +/* Gstate Handling */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentgstate: (int) gst +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPSgrestore +{ + fprintf(gstream, "grestore\n"); +} + +- (void) DPSgsave +{ + fprintf(gstream, "gsave\n"); +} + +- (void) DPSgstate +{ +} + +- (void) DPSinitgraphics +{ + fprintf(gstream, "initgraphics\n"); +} + +- (void) DPSsetgstate: (int) gst +{ +} + + +- (int) GSDefineGState +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); + return 0; +} + +- (void) GSUndefineGState: (int) gst +{ + [self notImplemented: _cmd]; +} + +- (void) GSReplaceGState: (int) gst +{ + [self notImplemented: _cmd]; +} + +- (void) GSCreateGState: (int) gst +{ + [self notImplemented: _cmd]; +} + +- (void) GSSetGState: (int) gst +{ + [self notImplemented: _cmd]; +} + + +/* ----------------------------------------------------------------------- */ +/* Gstate operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentflat: (float*) flatness +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentlinecap: (int*) linecap +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentlinejoin: (int*) linejoin +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentlinewidth: (float*) width +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentmiterlimit: (float*) limit +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentpoint: (float*) x: (float*) y +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentstrokeadjust: (int*) b +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPSsetdash: (const float*) pat: (int) size: (float) offset +{ + int i; + fprintf(gstream, "["); + for (i = 0; i < size; i++) + fprintf(gstream, "%f ", pat[i]); + fprintf(gstream, "] %g setdash\n", offset); +} + +- (void) DPSsetflat: (float) flatness +{ + fprintf(gstream, "%g setflat\n", flatness); +} + +- (void) DPSsethalftonephase: (float) x: (float) y +{ + fprintf(gstream, "%g %g sethalftonephase\n", x, y); +} + +- (void) DPSsetlinecap: (int) linecap +{ + fprintf(gstream, "%d setlinecap\n", linecap); +} + +- (void) DPSsetlinejoin: (int) linejoin +{ + fprintf(gstream, "%d setlinejoin\n", linejoin); +} + +- (void) DPSsetlinewidth: (float) width +{ + fprintf(gstream, "%g setlinewidth\n", width); +} + +- (void) DPSsetmiterlimit: (float) limit +{ + fprintf(gstream, "%g setmiterlimit\n", limit); +} + +- (void) DPSsetstrokeadjust: (int) b +{ + fprintf(gstream, "%d setstrokeadjust\n", b); +} + + +/* ----------------------------------------------------------------------- */ +/* Matrix operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSconcat: (const float*) m +{ + fprintf(gstream, "[%g %g %g %g %g %g] concat\n", + m[0], m[1], m[2], m[3], m[4], m[5]); +} + +- (void) DPSinitmatrix +{ + fprintf(gstream, "initmatrix\n"); +} + +- (void) DPSrotate: (float) angle +{ + fprintf(gstream, "%g rotate\n", angle); +} + +- (void) DPSscale: (float) x: (float) y +{ + fprintf(gstream, "%g %g scale\n", x, y); +} + +- (void) DPStranslate: (float) x: (float) y +{ + fprintf(gstream, "%g %g translate\n", x, y); +} + + +- (NSAffineTransform *) GSCurrentCTM +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); + return nil; +} + +- (void) GSSetCTM: (NSAffineTransform *) ctm +{ + [self notImplemented: _cmd]; +} + +- (void) GSConcatCTM: (NSAffineTransform *) ctm +{ + [self notImplemented: _cmd]; +} + + +/* ----------------------------------------------------------------------- */ +/* Paint operations */ +/* ----------------------------------------------------------------------- */ +- (void) DPSarc: (float) x: (float) y: (float) r: (float) angle1: (float) angle2 +{ + fprintf(gstream, "%g %g %g %g %g arc\n", x, y, r, angle1, angle2); +} + +- (void) DPSarcn: (float) x: (float) y: (float) r: (float) angle1: (float) angle2 +{ + fprintf(gstream, "%g %g %g %g %g arcn\n", x, y, r, angle1, angle2); +} + +- (void) DPSarct: (float) x1: (float) y1: (float) x2: (float) y2: (float) r +{ + fprintf(gstream, "%g %g %g %g %g arct\n", x1, y1, x2, y2, r); +} + +- (void) DPSclip +{ + fprintf(gstream, "clip\n"); +} + +- (void) DPSclosepath +{ + fprintf(gstream, "closepath\n"); +} + +- (void) DPScurveto: (float) x1: (float) y1: (float) x2: (float) y2: (float) x3: (float) y3 +{ + fprintf(gstream, "%g %g %g %g %g %g curveto\n", x1, y1, x2, y2, x3, y3); +} + +- (void) DPSeoclip +{ + fprintf(gstream, "eoclip\n"); +} + +- (void) DPSeofill +{ + fprintf(gstream, "eofill\n"); +} + +- (void) DPSfill +{ + fprintf(gstream, "fill\n"); +} + +- (void) DPSflattenpath +{ + fprintf(gstream, "flattenpath\n"); +} + +- (void) DPSinitclip +{ + fprintf(gstream, "initclip\n"); +} + +- (void) DPSlineto: (float) x: (float) y +{ + fprintf(gstream, "%g %g lineto\n", x, y); +} + +- (void) DPSmoveto: (float) x: (float) y +{ + fprintf(gstream, "%g %g moveto\n", x, y); +} + +- (void) DPSnewpath +{ + fprintf(gstream, "newpath\n"); +} + +- (void) DPSpathbbox: (float*) llx: (float*) lly: (float*) urx: (float*) ury +{ +} + +- (void) DPSrcurveto: (float) x1: (float) y1: (float) x2: (float) y2: (float) x3: (float) y3 +{ + fprintf(gstream, "%g %g %g %g %g %g rcurveto\n", x1, y1, x2, y2, x3, y3); +} + +- (void) DPSrectclip: (float) x: (float) y: (float) w: (float) h +{ + fprintf(gstream, "%g %g %g %g rectclip\n", x, y, w, h); +} + +- (void) DPSrectfill: (float) x: (float) y: (float) w: (float) h +{ + fprintf(gstream, "%g %g %g %g rectfill\n", x, y, w, h); +} + +- (void) DPSrectstroke: (float) x: (float) y: (float) w: (float) h +{ + fprintf(gstream, "%g %g %g %g rectstroke\n", x, y, w, h); +} + +- (void) DPSreversepath +{ + fprintf(gstream, "reversepath\n"); +} + +- (void) DPSrlineto: (float) x: (float) y +{ + fprintf(gstream, "%g %g rlineto\n", x, y); +} + +- (void) DPSrmoveto: (float) x: (float) y +{ + fprintf(gstream, "%g %g rmoveto\n", x, y); +} + +- (void) DPSstroke +{ + fprintf(gstream, "stroke\n"); +} + + +- (void) GSSendBezierPath: (NSBezierPath *) path +{ + [self notImplemented: _cmd]; +} + +- (void) GSRectClipList: (const NSRect *) rects: (int) count +{ + [self notImplemented: _cmd]; +} + +- (void) GSRectFillList: (const NSRect *) rects: (int) count +{ + [self notImplemented: _cmd]; +} + + +/* ----------------------------------------------------------------------- */ +/* Window system ops */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentgcdrawable: (void**) gc: (void**) draw: (int*) x: (int*) y +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPScurrentoffset: (int*) x: (int*) y +{ + NSLog(@"DPSinvalidcontext: getting values from stream context"); +} + +- (void) DPSsetgcdrawable: (void*) gc: (void*) draw: (int) x: (int) y +{ +} + +- (void) DPSsetoffset: (short int) x: (short int) y +{ +} + + +/*-------------------------------------------------------------------------*/ +/* Graphics Extensions Ops */ +/*-------------------------------------------------------------------------*/ +- (void) DPScomposite: (float) x: (float) y: (float) w: (float) h: (int) gstateNum: (float) dx: (float) dy: (int) op +{ + fprintf(gstream, "%g %g %g %g %d %g %g %d composite\n", x, y, w, h, gstateNum, dx, dy, op); +} + +- (void) DPScompositerect: (float) x: (float) y: (float) w: (float) h: (int) op +{ + fprintf(gstream, "%g %g %g %g %d compositerect\n", x, y, w, h, op); +} + +- (void) DPSdissolve: (float) x: (float) y: (float) w: (float) h: (int) gstateNum: (float) dx: (float) dy: (float) delta +{ + fprintf(gstream, "%g %g %g %g %d %g %g %g dissolve\n", x, y, w, h, gstateNum, dx, dy, delta); +} + + +- (void) GSDrawImage: (NSRect) rect: (void *) imageref +{ + [self notImplemented: _cmd]; +} + + +/* ----------------------------------------------------------------------- */ +/* Client functions */ +/* ----------------------------------------------------------------------- */ +- (void) DPSPrintf: (char *)fmt : (va_list)args +{ + vfprintf(gstream, fmt, args); +} + +- (void) DPSWriteData: (char *)buf : (unsigned int)count +{ + /* Not sure here. Should we translate to ASCII if it's not + already? */ +} + +@end + +static char *hexdigits = "0123456789abcdef"; + +void +writeHex(FILE *gstream, const unsigned char *data, int count) +{ + int i; + for (i = 0; i < count; i++) + { + fprintf(gstream, "%c%c", hexdigits[(int)(data[0]/16)], + hexdigits[(data[0] % 16)]); + if (i && i % 40 == 0) + fprintf(gstream, "\n"); + } +} + +@implementation GSStreamContext (Graphics) + +- (void) NSDrawBitmap: (NSRect) rect : (int) pixelsWide : (int) pixelsHigh + : (int) bitsPerSample : (int) samplesPerPixel + : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar + : (BOOL) hasAlpha : (NSString *) colorSpaceName + : (const unsigned char *const [5]) data +{ + int bytes; + NSSize scale; + + scale = NSMakeSize(NSWidth(rect) / pixelsWide, + NSHeight(rect) / pixelsHigh); + /* Save scaling */ + fprintf(gstream, "matrix\ncurrentmatrix\n"); + fprintf(gstream, "%f %f translate %f %f scale\n", + NSMinX(rect), NSMinY(rect), scale.width, scale.height); + + if (bitsPerSample == 0) + bitsPerSample = 8; + bytes = + (bitsPerSample * pixelsWide * pixelsHigh + 7) / 8; + if (bytes * samplesPerPixel != bytesPerRow * pixelsHigh) + { + NSLog(@"Image Rendering Error: Dodgy bytesPerRow value %d", bytesPerRow); + NSLog(@" pixelsHigh=%d, bytes=%d, samplesPerPixel=%d", + bytesPerRow, pixelsHigh, bytes); + return; + } + + if(samplesPerPixel > 1) + { + if(isPlanar || hasAlpha) + { + if(bitsPerSample != 8) + { + NSLog(@"Image format conversion not supported for bps!=8"); + return; + } + } + fprintf(gstream, "%d %d %d [%d 0 0 -%d 0 %d]\n", + pixelsWide, pixelsHigh, bitsPerSample, pixelsWide, + pixelsHigh, pixelsHigh); + fprintf(gstream, "{currentfile %d string readhexstring pop}\n", + bytesPerRow); + fprintf(gstream, "false %d colorimage\n", + hasAlpha?(samplesPerPixel-1):samplesPerPixel); + } + else + { + fprintf(gstream, "%d %d %d [%d 0 0 -%d 0 %d]\n", + pixelsWide, pixelsHigh, bitsPerSample, pixelsWide, + pixelsHigh, pixelsHigh); + fprintf(gstream, "currentfile image\n"); + } + + // The context is now waiting for data on its standard input + if(isPlanar || hasAlpha) + { + // We need to do a format conversion. + // We do this on the fly, sending data to the context as soon as + // it is computed. + int i, j, spp, alpha; + unsigned char val; + if(hasAlpha) + spp = samplesPerPixel - 1; + else + spp = samplesPerPixel; + + for(j=0; j + Date: Dec 1998 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +NSString *DPSconfigurationerror = @"DPSconfigurationerror: %@"; +NSString *DPSinvalidaccess = @"DPSinvalidaccess: %@"; +NSString *DPSinvalidcontext = @"DPSinvalidcontext: %@"; +NSString *DPSinvalidexit = @"DPSinvalidexit: %@"; +NSString *DPSinvalidfileaccess = @"DPSinvalidfileaccess: %@"; +NSString *DPSinvalidfont = @"DPSinvalidfont: %@"; +NSString *DPSinvalidid = @"DPSinvalidid: %@"; +NSString *DPSinvalidrestore = @"DPSinvalidrestore: %@"; +NSString *DPSinvalidparam = @"DPSinvalidparam: %@"; +NSString *DPSioerror = @"DPSioerror: %@"; +NSString *DPSlimitcheck = @"DPSlimitcheck: %@"; +NSString *DPSnocurrentpoint = @"DPSnocurrentpoint: %@"; +NSString *DPSnulloutput = @"DPSnulloutput: %@"; +NSString *DPSrangecheck = @"DPSrangecheck: %@"; +NSString *DPSstackoverflow = @"DPSstackoverflow: %@"; +NSString *DPSstackunderflow = @"DPSstackunderflow: %@"; +NSString *DPStypecheck = @"DPStypecheck: %@"; +NSString *DPSundefined = @"DPSundefined: %@"; +NSString *DPSundefinedfilename = @"DPSundefinedfilename: %@"; +NSString *DPSundefinedresource = @"DPSundefinedresource: %@"; +NSString *DPSundefinedresult = @"DPSundefinedresult: %@"; +NSString *DPSunmatchedmark = @"DPSunmatchedmark: %@"; +NSString *DPSunregistered = @"DPSunregistered: %@"; +NSString *DPSVMerror = @"DPSVMerror: %@"; diff --git a/Source/x11/GNUmakefile b/Source/x11/GNUmakefile new file mode 100644 index 0000000..e20a271 --- /dev/null +++ b/Source/x11/GNUmakefile @@ -0,0 +1,80 @@ +# +# Main makefile for GNUstep Backend x11 +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# If you are interested in a warranty or support for this source code, +# contact Scott Christley at scottc@net-community.com +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../back.make + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../../config.make + +# The library to be compiled, as a library or as a bundle +SUBPROJECT_NAME=x11 + +# The C source files to be compiled +ifeq ($(WITH_WRASTER),yes) +x11_C_FILES = \ +xdnd.c +else +x11_C_FILES = \ +StdCmap.c \ +context.c \ +convert.c \ +draw.c \ +gradient.c \ +misc.c \ +raster.c \ +scale.c \ +xdnd.c \ +xutil.c +endif + +# The Objective-C source files to be compiled +x11_OBJC_FILES = \ +XGServer.m \ +XGServerEvent.m \ +XGServerWindow.m \ +XGDragView.m \ +XGSlideView.m \ +XIMInputServer.m + +x11_HEADER_FILES_DIR = ../Headers/x11 +x11_HEADER_FILES_INSTALL_DIR = gnustep/x11 + +x11_HEADER_FILES = \ +XGServer.h \ +XGServerWindow.h + +-include GNUmakefile.preamble + +include $(GNUSTEP_MAKEFILES)/subproject.make + +-include GNUmakefile.postamble + diff --git a/Source/x11/GNUmakefile.preamble b/Source/x11/GNUmakefile.preamble new file mode 100644 index 0000000..c470ff9 --- /dev/null +++ b/Source/x11/GNUmakefile.preamble @@ -0,0 +1,55 @@ +# +# GNUmakefile.preamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +GNUSTEP_INSTALL_LIBDIR=$(GNUSTEP_LIBRARIES_ROOT) +ADDITIONAL_CPPFLAGS = -DGNUSTEP_INSTALL_LIBDIR=\"$(GNUSTEP_INSTALL_LIBDIR)\" \ + -DGNUSTEP_INSTALL_PREFIX=$(GNUSTEP_INSTALL_PREFIX) \ + $(CONFIG_SYSTEM_DEFS) + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I../../Headers \ + -I../$(GNUSTEP_TARGET_DIR) + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# + + diff --git a/Source/x11/StdCmap.c b/Source/x11/StdCmap.c new file mode 100644 index 0000000..62c0a94 --- /dev/null +++ b/Source/x11/StdCmap.c @@ -0,0 +1,219 @@ +/* $XConsortium: StdCmap.c,v 1.14 94/04/17 20:16:14 rws Exp $ */ + +/* + +Copyright (c) 1989 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + +*/ + +/* + * Author: Donna Converse, MIT X Consortium + */ + +#include +#include +#include +#include +#include + +#define lowbit(x) ((x) & (~(x) + 1)) + +static Status valid_args(); /* argument restrictions */ + +/* + * To create any one standard colormap, use XmuStandardColormap(). + * + * Create a standard colormap for the given screen, visualid, and visual + * depth, with the given red, green, and blue maximum values, with the + * given standard property name. Return a pointer to an XStandardColormap + * structure which describes the newly created colormap, upon success. + * Upon failure, return NULL. + * + * XmuStandardColormap() calls XmuCreateColormap() to create the map. + * + * Resources created by this function are not made permanent; that is the + * caller's responsibility. + */ + +XStandardColormap *XmuStandardColormap(dpy, screen, visualid, depth, property, + cmap, red_max, green_max, blue_max) + Display *dpy; /* specifies X server connection */ + int screen; /* specifies display screen */ + VisualID visualid; /* identifies the visual type */ + unsigned int depth; /* identifies the visual type */ + Atom property; /* a standard colormap property */ + Colormap cmap; /* specifies colormap ID or None */ + unsigned long red_max, green_max, blue_max; /* allocations */ +{ + XStandardColormap *stdcmap; + Status status; + XVisualInfo vinfo_template, *vinfo; + long vinfo_mask; + int n; + + /* Match the required visual information to an actual visual */ + vinfo_template.visualid = visualid; + vinfo_template.screen = screen; + vinfo_template.depth = depth; + vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask; + if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL) + return 0; + + /* Check the validity of the combination of visual characteristics, + * allocation, and colormap property. Create an XStandardColormap + * structure. + */ + + if (! valid_args(vinfo, red_max, green_max, blue_max, property) + || ((stdcmap = XAllocStandardColormap()) == NULL)) { + XFree((char *) vinfo); + return 0; + } + + /* Fill in the XStandardColormap structure */ + + if (cmap == DefaultColormap(dpy, screen)) { + /* Allocating out of the default map, cannot use XFreeColormap() */ + Window win = XCreateWindow(dpy, RootWindow(dpy, screen), 1, 1, 1, 1, + 0, 0, InputOnly, vinfo->visual, + (unsigned long) 0, + (XSetWindowAttributes *)NULL); + stdcmap->killid = (XID) XCreatePixmap(dpy, win, 1, 1, depth); + XDestroyWindow(dpy, win); + stdcmap->colormap = cmap; + } else { + stdcmap->killid = ReleaseByFreeingColormap; + stdcmap->colormap = XCreateColormap(dpy, RootWindow(dpy, screen), + vinfo->visual, AllocNone); + } + stdcmap->red_max = red_max; + stdcmap->green_max = green_max; + stdcmap->blue_max = blue_max; + if (property == XA_RGB_GRAY_MAP) + stdcmap->red_mult = stdcmap->green_mult = stdcmap->blue_mult = 1; + else if (vinfo->class == TrueColor || vinfo->class == DirectColor) { + stdcmap->red_mult = lowbit(vinfo->red_mask); + stdcmap->green_mult = lowbit(vinfo->green_mask); + stdcmap->blue_mult = lowbit(vinfo->blue_mask); + } else { + stdcmap->red_mult = (red_max > 0) + ? (green_max + 1) * (blue_max + 1) : 0; + stdcmap->green_mult = (green_max > 0) ? blue_max + 1 : 0; + stdcmap->blue_mult = (blue_max > 0) ? 1 : 0; + } + stdcmap->base_pixel = 0; /* base pixel may change */ + stdcmap->visualid = vinfo->visualid; + + /* Make the colormap */ + + status = XmuCreateColormap(dpy, stdcmap); + + /* Clean up */ + + XFree((char *) vinfo); + if (!status) { + + /* Free the colormap or the pixmap, if we created one */ + if (stdcmap->killid == ReleaseByFreeingColormap) + XFreeColormap(dpy, stdcmap->colormap); + else if (stdcmap->killid != None) + XFreePixmap(dpy, stdcmap->killid); + + XFree((char *) stdcmap); + return (XStandardColormap *) NULL; + } + return stdcmap; +} + +/****************************************************************************/ +static Status valid_args(vinfo, red_max, green_max, blue_max, property) + XVisualInfo *vinfo; /* specifies visual */ + unsigned long red_max, green_max, blue_max; /* specifies alloc */ + Atom property; /* specifies property name */ +{ + unsigned long ncolors; /* number of colors requested */ + + /* Determine that the number of colors requested is <= map size */ + + if ((vinfo->class == DirectColor) || (vinfo->class == TrueColor)) { + unsigned long mask; + + mask = vinfo->red_mask; + while (!(mask & 1)) + mask >>= 1; + if (red_max > mask) + return 0; + mask = vinfo->green_mask; + while (!(mask & 1)) + mask >>= 1; + if (green_max > mask) + return 0; + mask = vinfo->blue_mask; + while (!(mask & 1)) + mask >>= 1; + if (blue_max > mask) + return 0; + } else if (property == XA_RGB_GRAY_MAP) { + ncolors = red_max + green_max + blue_max + 1; + if (ncolors > vinfo->colormap_size) + return 0; + } else { + ncolors = (red_max + 1) * (green_max + 1) * (blue_max + 1); + if (ncolors > vinfo->colormap_size) + return 0; + } + + /* Determine that the allocation and visual make sense for the property */ + + switch (property) + { + case XA_RGB_DEFAULT_MAP: + if (red_max == 0 || green_max == 0 || blue_max == 0) + return 0; + break; + case XA_RGB_RED_MAP: + if (red_max == 0) + return 0; + break; + case XA_RGB_GREEN_MAP: + if (green_max == 0) + return 0; + break; + case XA_RGB_BLUE_MAP: + if (blue_max == 0) + return 0; + break; + case XA_RGB_BEST_MAP: + if (red_max == 0 || green_max == 0 || blue_max == 0) + return 0; + break; + case XA_RGB_GRAY_MAP: + if (red_max == 0 || blue_max == 0 || green_max == 0) + return 0; + break; + default: + return 0; + } + return 1; +} diff --git a/Source/x11/XGDragView.m b/Source/x11/XGDragView.m new file mode 100644 index 0000000..1ea5ea2 --- /dev/null +++ b/Source/x11/XGDragView.m @@ -0,0 +1,1293 @@ +/* + XGDragView - Drag and Drop code for X11 backends. + + Copyright (C) 1998,1999,2001 Free Software Foundation, Inc. + + Created by: Wim Oudshoorn + Date: Nov 2001 + + Written by: Adam Fedor + Date: Nov 1998 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "x11/XGServer.h" +#include "x11/XGServerWindow.h" +#include "x11/XGDragView.h" + +#include + +/* Size of the dragged window */ +#define DWZ 48 +#define ALPHA_THRESHOLD 158 + +#define XDPY [XGServer currentXDisplay] + +#define SLIDE_TIME_STEP .02 /* in seconds */ +#define SLIDE_NR_OF_STEPS 20 + +@interface XGRawWindow : NSWindow +@end + +@interface NSImage (BackEnd) +- (Pixmap) xPixmapMask; +@end + +@interface NSCursor (BackendPrivate) +- (void *)_cid; +- (void) _setCid: (void *)val; +@end + +// --- DRAG AND DROP SUPPORT (XDND) ----------------------------------- + +/* + * This will get initialized when we declare a window that will + * accept dragging or if we start a dragging ourself. Up to than + * even the dragging messages are not defined. + */ +static DndClass dnd; +static BOOL xDndInitialized = NO; + +void +GSEnsureDndIsInitialized (void) +{ + if (xDndInitialized == NO) + { + xDndInitialized = YES; + xdnd_init (&dnd, XDPY); + } +} + + +DndClass xdnd (void) +{ + return dnd; // FIX ME rename with private desig +} + + +Atom +GSActionForDragOperation(unsigned int op) +{ + Atom xaction; + if (op == NSDragOperationAll) + xaction = dnd.XdndActionPrivate; + else if (op & NSDragOperationCopy) + xaction = dnd.XdndActionCopy; + else if (op & NSDragOperationLink) + xaction = dnd.XdndActionLink; + else if (op & NSDragOperationGeneric) + xaction = dnd.XdndActionCopy; + else if (op & NSDragOperationPrivate) + xaction = dnd.XdndActionPrivate; + else + xaction = None; + return xaction; +} + + +NSDragOperation +GSDragOperationForAction(Atom xaction) +{ + NSDragOperation action; + if (xaction == dnd.XdndActionCopy) + action = NSDragOperationCopy; + else if (xaction == dnd.XdndActionMove) + action = NSDragOperationCopy; + else if (xaction == dnd.XdndActionLink) + action = NSDragOperationLink; + else if (xaction == dnd.XdndActionAsk) + action = NSDragOperationGeneric; + else if (xaction == dnd.XdndActionPrivate) + action = NSDragOperationPrivate; + else + action = NSDragOperationNone; + return action; +} + +// The result of this function must be freed by the caller +static inline +Atom * +mimeTypeForPasteboardType(Display *xDisplay, NSZone *zone, NSArray *types) +{ + Atom *typelist; + int count = [types count]; + int i; + + typelist = NSZoneMalloc(zone, (count+1) * sizeof(Atom)); + for (i = 0; i < count; i++) + { + NSString *mime; + + mime = [types objectAtIndex: i]; + mime = [NSPasteboard mimeTypeForPasteboardType: mime]; + typelist[i] = XInternAtom(xDisplay, [mime cString], False); + } + typelist[count] = 0; + + return typelist; +} + + + +@implementation XGDragView + +static XGDragView *sharedDragView = nil; + ++ (XGDragView*) sharedDragView +{ + if (sharedDragView == nil) + { + GSEnsureDndIsInitialized (); + sharedDragView = [XGDragView new]; + } + return sharedDragView; +} + +- (id) init +{ + self = [super init]; + if (self != nil) + { + NSRect winRect = {{0, 0}, {DWZ, DWZ}}; + XGRawWindow *sharedDragWindow = [XGRawWindow alloc]; + + dragCell = [[NSCell alloc] initImageCell: nil]; + [dragCell setBordered: NO]; + + [sharedDragWindow initWithContentRect: winRect + styleMask: NSBorderlessWindowMask + backing: NSBackingStoreNonretained + defer: NO]; + [sharedDragWindow setContentView: self]; + RELEASE(self); + + // Cache the X structure of our window + dragWindev = [XGServer _windowWithTag: [sharedDragWindow windowNumber]]; + } + + return self; +} + +- (BOOL) isDragging +{ + return isDragging; +} + +- (void) dealloc +{ + [super dealloc]; + RELEASE(cursors); +} + +- (void) drawRect: (NSRect)rect +{ + [dragCell drawWithFrame: rect inView: self]; +} + + +/* + * External drag operation + */ +- (void) setupDragInfoFromXEvent: (XEvent *)xEvent +{ + // Start a dragging session from another application + dragSource = nil; + dragExternal = YES; + operationMask = NSDragOperationAll; + + ASSIGN(dragPasteboard, [NSPasteboard pasteboardWithName: NSDragPboard]); +} + +- (void) updateDragInfoFromEvent: (NSEvent*)event +{ + // Store the drag info, so that we can send status messages as response + dragWindow = [event window]; + dragPoint = [event locationInWindow]; + dragSequence = [event timestamp]; + dragMask = [event data2]; +} + +- (void) resetDragInfo +{ + DESTROY(dragPasteboard); +} + +/* + * Local drag operation + */ + +/* + * TODO: + * - use initialOffset + * - use screenLocation + * - implement slideBack + */ +- (void) dragImage: (NSImage*)anImage + at: (NSPoint)screenLocation + offset: (NSSize)initialOffset + event: (NSEvent*)event + pasteboard: (NSPasteboard*)pboard + source: (id)sourceObject + slideBack: (BOOL)slideFlag +{ + if (anImage == nil) + { + anImage = [NSImage imageNamed: @"common_Close"]; + } + + [dragCell setImage: anImage]; + + ASSIGN(dragPasteboard, pboard); + dragSource = RETAIN(sourceObject); + dragSequence = [event timestamp]; + dragExternal = NO; + slideBack = slideFlag; + + NSDebugLLog(@"NSDragging", @"Start drag with %@", [pboard types]); + typelist = mimeTypeForPasteboardType (XDPY, [self zone], [pboard types]); + [self _handleDrag: event]; + NSZoneFree([self zone], typelist); + typelist = NULL; + RELEASE(dragSource); +} + +- (void) _sendLocalEvent: (GSAppKitSubtype)subtype + action: (NSDragOperation)action + position: (NSPoint)eventLocation + timestamp: (NSTimeInterval)time + toWindow: (NSWindow*)dWindow +{ + NSEvent *e; + NSGraphicsContext *context = GSCurrentContext(); + gswindow_device_t *windev; + + windev = [XGServer _windowWithTag: [dWindow windowNumber]]; + eventLocation = NSMakePoint(eventLocation.x - NSMinX(windev->xframe), + eventLocation.y - NSMinY(windev->xframe)); + eventLocation.y = NSHeight(windev->xframe) - eventLocation.y; + + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: time + windowNumber: windev->number + context: context + subtype: subtype + data1: dragWindev->ident + data2: action]; + [dWindow sendEvent: e]; +} + +- (void) postDragEvent: (NSEvent *)theEvent +{ + gswindow_device_t *window; + + window = [XGServer _windowWithTag: [theEvent windowNumber]]; + if ([theEvent subtype] == GSAppKitDraggingStatus) + { + NSDragOperation action = [theEvent data2]; + + if (dragExternal) + { + Atom xaction; + + xaction = GSActionForDragOperation(action); + xdnd_send_status(&dnd, + [theEvent data1], + window->ident, + (action != NSDragOperationNone), + 0, + 0, 0, 0, 0, + xaction); + } + else + { + if (action != targetMask) + { + targetMask = action; + [self _setCursor]; + } + } + } + else if ([theEvent subtype] == GSAppKitDraggingFinished) + { + if (dragExternal) + { + xdnd_send_finished(&dnd, + [theEvent data1], + window->ident, + 0); + } + } + else + { + NSDebugLLog(@"NSDragging", @"Internal: unhandled post external event"); + } +} + +/* + Method to initialize the dragview before it is put on the screen. + It only initializes the instance variables that have to do with + moving the image over the screen and variables that are used + to keep track where we are. + + So it is typically used just before the dragview is actually displayed. + + Pre coniditions: + - dragCell is initialized with the image to drag. + - typelist is initialized with the dragging types + Post conditions: + - all instance variables pertaining to moving the window are initialized + - all instance variables pertaining to X-Windows are initialized + + */ +- (void) _setupWindow: (NSPoint) dragStart +{ + NSSize imageSize = [[dragCell image] size]; + Pixmap pixmap = 0; + + offset = NSMakePoint (imageSize.width / 2.0, imageSize.height / 2.0); + + [_window setFrame: NSMakeRect (dragStart.x - offset.x, + dragStart.y - offset.y, + imageSize.width, imageSize.height) + display: NO]; + + // Unset the target window + targetWindow = 0; + + NSDebugLLog (@"NSDragging", @"---dragWindow: %x <- %x", + dragWindev->parent, dragWindev->ident); + + /* setup the wx and wy coordinates, used for moving the view around */ + wx = dragWindev->siz_hints.x; + wy = dragWindev->siz_hints.y; + + dragPosition = dragStart; + newPosition = dragStart; + + // FIXME this should be integrated with xPixmapMask + // but that method should be reorganized + if ([[[dragCell image] backgroundColor] alphaComponent] * 256 + <= ALPHA_THRESHOLD) + { + // Make it a shaped window containing a pixmap + // Need to lockFocus to do this. FIXME when image caching works + [self lockFocus]; + pixmap = [[dragCell image] xPixmapMask]; + [self unlockFocus]; + } + + if (pixmap) + { + XShapeCombineMask(XDPY, dragWindev->ident, ShapeBounding, 0, 0, + pixmap, ShapeSet); + XFreePixmap(XDPY, pixmap); + } + else + { + XShapeCombineMask(XDPY, dragWindev->ident, ShapeBounding, 0, 0, + 0, ShapeSet); + } + + [_window orderFront: nil]; +} + + +/* + updates the operationMask by examining modifier keys + pressed during -theEvent-. + + If the current value of operationMask == NSDragOperationIgnoresModifiers + it will return immediately without updating the operationMask + + This method will return YES if the operationMask + is changed, NO if it is still the same. +*/ +- (BOOL) _updateOperationMask: (NSEvent*) theEvent +{ + unsigned int mod = [theEvent modifierFlags]; + unsigned int oldOperationMask = operationMask; + + if (operationMask == NSDragOperationIgnoresModifiers) + { + return NO; + } + + if (mod & NSControlKeyMask) + { + operationMask = NSDragOperationLink; + } + else if (mod & NSAlternateKeyMask) + { + operationMask = NSDragOperationCopy; + } + else if (mod & NSCommandKeyMask) + { + operationMask = NSDragOperationGeneric; + } + else + { + operationMask = NSDragOperationAll; + } + + return (operationMask != oldOperationMask); +} + +/* + _setCursor examines the state of the dragging and update + the cursor accordingly. It will not save the current cursor, + if you want to keep the original you have to save it yourself. + + The code recogines 4 cursors: + + - NONE - when the source does not allow dragging + - COPY - when the current operation is ONLY Copy + - LINK - when the current operation is ONLY Link + - GENERIC - all other cases + + And two colors + + - GREEN - when the target accepts the drop + - BLACK - when the target does not accept the drop + + Note that the code to figure out which of the 4 cursor to use + depends on the fact that + + {NSDragOperationNone, NSDragOperationCopy, NSDragOperationLink} = {0, 1, 2} +*/ +- (void) _setCursor +{ + NSCursor *newCursor; + NSString *name; + NSString *iname; + int mask; + + mask = dragMask & operationMask; + + if (targetWindow) + mask &= targetMask; + + NSDebugLLog (@"NSDragging", + @"drag, operation, target mask = (%x, %x, %x), dnd aware = %d\n", + dragMask, operationMask, targetMask, + (targetWindow != (Window) None)); + + if (cursors == nil) + cursors = RETAIN([NSMutableDictionary dictionary]); + + name = nil; + newCursor = nil; + switch (mask) + { + case NSDragOperationNone: + name = @"NoCursor"; + iname = @"common_noCursor"; + break; + case NSDragOperationCopy: + name = @"CopyCursor"; + iname = @"common_copyCursor"; + break; + case NSDragOperationLink: + name = @"LinkCursor"; + iname = @"common_linkCursor"; + break; + case NSDragOperationGeneric: + break; + default: + // FIXME: Should not happen, add warning? + } + + if (name != nil) + { + newCursor = [cursors objectForKey: name]; + if (newCursor == nil) + { + NSImage *image = [NSImage imageNamed: iname]; + newCursor = [[NSCursor alloc] initWithImage: image]; + [cursors setObject: newCursor forKey: name]; + RELEASE(newCursor); + } + } + if (newCursor == nil) + { + name = @"ArrowCursor"; + newCursor = [cursors objectForKey: name]; + if (newCursor == nil) + { + /* Make our own arrow cursor, since we want to color it */ + void *c; + + newCursor = [[NSCursor alloc] initWithImage: nil]; + [GSCurrentServer() standardcursor: GSArrowCursor : &c]; + [newCursor _setCid: c]; + [cursors setObject: newCursor forKey: name]; + RELEASE(newCursor); + } + } + + [newCursor set]; + + if ((targetWindow != (Window) None) && mask != NSDragOperationNone) + { + [GSCurrentServer() setcursorcolor: [NSColor greenColor] + : [NSColor blackColor] + : [newCursor _cid]]; + } + else + { + [GSCurrentServer() setcursorcolor: [NSColor blackColor] + : [NSColor whiteColor] + : [newCursor _cid]]; + } +} + +/* + The dragging support works by hijacking the NSApp event loop. + + - this function loops until the dragging operation is finished + and consumes all NSEvents during the drag operation. + + - It sets up periodic events. The drawing and communication + with DraggingSource and DraggingTarget is handled in the + periodic event code. The use of periodic events is purely + a performance improvement. If no periodic events are used + the system can not process them all on time. + At least on a 333Mhz laptop, using fairly simple + DraggingTarget code. + + PROBLEMS: + + - No autoreleasePools are created. So long drag operations can consume + memory + + - It seems that sometimes a periodic event get lost. +*/ +- (void) _handleDrag: (NSEvent*)theEvent +{ + // Caching some often used values. These values do not + // change in this method. + Display *xDisplay = [XGServer currentXDisplay]; + // Use eWindow for coordination transformation + NSWindow *eWindow = [theEvent window]; + NSDate *theDistantFuture = [NSDate distantFuture]; + NSImage *dragImage = [dragCell image]; + unsigned int eventMask = NSLeftMouseDownMask | NSLeftMouseUpMask + | NSLeftMouseDraggedMask | NSMouseMovedMask + | NSPeriodicMask | NSAppKitDefinedMask | NSFlagsChangedMask; + + NSPoint startPoint; + + // Storing values, to restore after we have finished. + NSCursor *cursorBeforeDrag = [NSCursor currentCursor]; + + isDragging = YES; + startPoint = [eWindow convertBaseToScreen: [theEvent locationInWindow]]; + + [self _setupWindow: startPoint]; + + // Notify the source that dragging has started + if ([dragSource respondsToSelector: + @selector(draggedImage:beganAt:)]) + { + [dragSource draggedImage: dragImage + beganAt: startPoint]; + } + + NSDebugLLog(@"NSDragging", @"Drag window X origin %d %d\n", wx, wy); + + + // --- Setup up the masks for the drag operation --------------------- + + if ([dragSource respondsToSelector: + @selector(ignoreModifierKeysWhileDragging)] + && [dragSource ignoreModifierKeysWhileDragging]) + { + operationMask = NSDragOperationIgnoresModifiers; + } + else + { + operationMask = 0; + [self _updateOperationMask: theEvent]; + } + + dragMask = [dragSource draggingSourceOperationMaskForLocal: !dragExternal]; + targetMask = NSDragOperationAll; + + // --- Setup the event loop ------------------------------------------ + + [self _updateAndMoveImageToCorrectPosition]; + [NSEvent startPeriodicEventsAfterDelay: 0.02 withPeriod: 0.03]; + + // --- Loop that handles all events durring drag operation ----------- + + while ([theEvent type] != NSLeftMouseUp) + { + [self _handleEventDuringDragging: theEvent]; + + theEvent = [NSApp nextEventMatchingMask: eventMask + untilDate: theDistantFuture + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + } + + + // --- Event loop for drag operation stopped ------------------------ + + [NSEvent stopPeriodicEvents]; + [self _updateAndMoveImageToCorrectPosition]; + + NSDebugLLog(@"NSDragging", @"dnd ending %x\n", targetWindow); + + // --- Deposit the drop ---------------------------------------------- + if ((targetWindow != (Window) None) + && ((targetMask & dragMask & operationMask) != NSDragOperationNone)) + { + // FIXME: (22 Jan 2002) + // We remove the dragged image from the screen before + // sending the dnd drop event to the destination. + // This code should actually be rewritten, because + // the depositing of the drop consist of three steps + // - prepareForDragOperation + // - performDragOperation + // - concludeDragOperation. + // The dragged image should be removed from the screen + // between the prepare and the perform operation. + // The three steps are now executed in the NSWindow class + // and the NSWindow class does not have access to + // the image. (at least not through the xdnd protocol) + [_window orderOut: nil]; + [cursorBeforeDrag set]; + NSDebugLLog(@"NSDragging", @"sending dnd drop\n"); + if (!dragExternal) + { + [self _sendLocalEvent: GSAppKitDraggingDrop + action: 0 + position: NSZeroPoint + timestamp: CurrentTime + toWindow: dragWindow]; + } + else + { + if (targetWindow == dragWindev->root) + { + // FIXME There is an xdnd extension for root drop + } + xdnd_send_drop(&dnd, targetWindow, dragWindev->ident, CurrentTime); + } + + //CHECKME: Why XSync here? + XSync(xDisplay, False); + if ([dragSource respondsToSelector: + @selector(draggedImage:endedAt:deposited:)]) + { + NSPoint point; + + point = [theEvent locationInWindow]; + point = [[theEvent window] convertBaseToScreen: point]; + [dragSource draggedImage: dragImage + endedAt: point + deposited: YES]; + } + } + else + { + if (slideBack) + { + [self slideDraggedImageTo: startPoint]; + } + [_window orderOut: nil]; + [cursorBeforeDrag set]; + + if ([dragSource respondsToSelector: + @selector(draggedImage:endedAt:deposited:)]) + { + NSPoint point; + + point = [theEvent locationInWindow]; + point = [[theEvent window] convertBaseToScreen: point]; + [dragSource draggedImage: dragImage + endedAt: point + deposited: NO]; + } + } + isDragging = NO; +} + + +/* + * Handle the events for the event loop during drag and drop + */ +- (void) _handleEventDuringDragging: (NSEvent *) theEvent +{ + switch ([theEvent type]) + { + case NSAppKitDefined: + { + GSAppKitSubtype sub = [theEvent subtype]; + + switch (sub) + { + case GSAppKitWindowMoved: + /* + * Keep window up-to-date with its current position. + */ + [NSApp sendEvent: theEvent]; + break; + + case GSAppKitDraggingStatus: + NSDebugLLog(@"NSDragging", @"got GSAppKitDraggingStatus\n"); + if ([theEvent data1] == targetWindow) + { + int newTargetMask = [theEvent data2]; + + if (newTargetMask != targetMask) + { + targetMask = newTargetMask; + [self _setCursor]; + } + } + break; + + case GSAppKitDraggingFinished: + NSLog(@"Internal: got GSAppKitDraggingFinished out of seq"); + break; + + case GSAppKitWindowFocusIn: + case GSAppKitWindowFocusOut: + case GSAppKitWindowLeave: + case GSAppKitWindowEnter: + break; + + default: + NSLog(@"Internal: dropped NSAppKitDefined (%d) event", sub); + break; + } + } + break; + + case NSMouseMoved: + case NSLeftMouseDragged: + case NSLeftMouseDown: + case NSLeftMouseUp: + newPosition = [[theEvent window] convertBaseToScreen: + [theEvent locationInWindow]]; + break; + case NSFlagsChanged: + if ([self _updateOperationMask: theEvent]) + { + // If flags change, send update to allow + // destination to take note. + if (dragWindow) + { + [self _sendLocalEvent: GSAppKitDraggingUpdate + action: dragMask & operationMask + position: NSMakePoint(wx + offset.x, wy + offset.y) + timestamp: CurrentTime + toWindow: dragWindow]; + } + else + { + xdnd_send_position(&dnd, targetWindow, dragWindev->ident, + GSActionForDragOperation(dragMask & operationMask), + wx + offset.x, wy + offset.y, CurrentTime); + } + [self _setCursor]; + } + break; + case NSPeriodic: + /* + * targetWindow check is needed because otherwise events only + * arrive after an initial mouse move. + */ + if (newPosition.x != dragPosition.x || newPosition.y != dragPosition.y) + { + [self _updateAndMoveImageToCorrectPosition]; + } + break; + default: + NSLog(@"Internal: dropped event (%d) during dragging", [theEvent type]); + } +} + +/* + * This method will move the drag image and update all associated data + */ +- (void) _updateAndMoveImageToCorrectPosition +{ + NSWindow *oldDragWindow; + BOOL oldDragExternal; + gswindow_device_t *dwindev; + Window mouseWindow; + BOOL changeCursor = NO; + + //--- Move drag image to the new position ----------------------------------- + + [self _moveDraggedImageToNewPosition]; + + //--- Store old values ----------------------------------------------------- + + oldDragWindow = dragWindow; + oldDragExternal = dragExternal; + + + //--- Determine target XWindow --------------------------------------------- + + mouseWindow = [self _xWindowAcceptingDnDunderX: wx + offset.x + Y: wy + offset.y]; + + //--- Determine target NSWindow -------------------------------------------- + + dwindev = [XGServer _windowForXWindow: mouseWindow]; + + if (dwindev != 0) + { + dragWindow = GSWindowWithNumber(dwindev->number); + } + else + { + dragWindow = nil; + } + + // If we have are not hovering above a window that we own + // we are dragging to an external application. + + dragExternal = (mouseWindow != (Window) None) && (dragWindow == nil); + + if (dragWindow) + { + dragPoint = [dragWindow convertScreenToBase: dragPosition]; + } + + NSDebugLLog(@"NSDragging", @"mouse window %x\n", mouseWindow); + + + + //--- send exit message if necessary ------------------------------------- + + if ((mouseWindow != targetWindow) && targetWindow) + { + /* If we change windows and the old window is dnd aware, we send an + dnd exit */ + + NSDebugLLog(@"NSDragging", @"sending dnd exit\n"); + + if (oldDragWindow) + { + [self _sendLocalEvent: GSAppKitDraggingExit + action: dragMask & operationMask + position: NSZeroPoint + timestamp: dragSequence + toWindow: oldDragWindow]; + } + else + { + xdnd_send_leave(&dnd, targetWindow, dragWindev->ident); + } + } + + // Reset drag mask when we switch from external to internal or back + // + if (oldDragExternal != dragExternal) + { + int newMask; + + newMask = [dragSource draggingSourceOperationMaskForLocal: dragExternal]; + if (newMask != dragMask) + { + dragMask = newMask; + changeCursor = YES; + } + } + + + if (mouseWindow == targetWindow && targetWindow) + { // same window, sending update + NSDebugLLog(@"NSDragging", @"sending dnd pos\n"); + if (dragWindow) + { + [self _sendLocalEvent: GSAppKitDraggingUpdate + action: dragMask & operationMask + position: NSMakePoint (wx + offset.x, wy + offset.y) + timestamp: CurrentTime + toWindow: dragWindow]; + } + else + { + xdnd_send_position(&dnd, targetWindow, dragWindev->ident, + GSActionForDragOperation (dragMask & operationMask), wx + offset.x, + wy + offset.y, CurrentTime); + } + } + else if (mouseWindow != (Window) None) + { + //FIXME: We might force the cursor update here, if the + //target wants to change the cursor. + + NSDebugLLog(@"NSDragging", + @"sending dnd enter/pos\n"); + + if (dragWindow) + { + [self _sendLocalEvent: GSAppKitDraggingEnter + action: dragMask + position: NSMakePoint (wx + offset.x, wy + offset.y) + timestamp: CurrentTime + toWindow: dragWindow]; + } + else + { + xdnd_send_enter(&dnd, mouseWindow, dragWindev->ident, typelist); + xdnd_send_position(&dnd, mouseWindow, dragWindev->ident, + GSActionForDragOperation (dragMask & operationMask), + wx + offset.x, wy + offset.y, CurrentTime); + } + } + + if (targetWindow != mouseWindow) + { + targetWindow = mouseWindow; + changeCursor = YES; + } + + if (changeCursor) + { + [self _setCursor]; + } +} + +/* NSDraggingInfo protocol */ +- (NSWindow*) draggingDestinationWindow +{ + return dragWindow; +} + +- (NSPoint) draggingLocation +{ + return dragPoint; +} + +- (NSPasteboard*) draggingPasteboard +{ + return dragPasteboard; +} + +- (int) draggingSequenceNumber +{ + return dragSequence; +} + +- (id) draggingSource +{ + return dragSource; +} + +- (unsigned int) draggingSourceOperationMask +{ + // Mix in possible modifiers + return dragMask & operationMask; +} + +- (NSImage*) draggedImage +{ + if (dragSource) + return [dragCell image]; + else + return nil; +} + +- (NSPoint) draggedImageLocation +{ + NSPoint loc; + + if (dragSource) + { + NSSize size; + + size = [[dragCell image] size]; + loc = NSMakePoint(dragPoint.x-size.width/2, dragPoint.y - size.height/2); + } + else + { + loc = dragPoint; + } + return loc; +} + + +/* + * Move the dragged image immediately to the position indicated by + * the instance variable newPosition. + * + * In doing so it will update the (wx, wy) and dragPosition instance variables. + */ +- (void) _moveDraggedImageToNewPosition +{ + wx += (int) (newPosition.x - dragPosition.x); + wy += (int) (dragPosition.y - newPosition.y); + + // We use this instead of the simpler `dragPosition = newPosition' + // because we want to keep the dragPosition in sync with (wx, wy) + // and (wx, wy) are integers. + dragPosition.x += (float) ((int) newPosition.x - dragPosition.x); + dragPosition.y += (float) ((int) newPosition.y - dragPosition.y); + + XMoveWindow (XDPY, dragWindev->ident, wx, wy); +} + + +- (void) _slideDraggedImageTo: (NSPoint)screenPoint + numberOfSteps: (int) steps + waitAfterSlide: (BOOL) waitFlag +{ + // --- If we do not need multiple redrawing, just move the image immediately + // to its desired spot. + + if (steps < 2) + { + newPosition = screenPoint; + [self _moveDraggedImageToNewPosition]; + } + else + { + [NSEvent startPeriodicEventsAfterDelay: 0.02 withPeriod: SLIDE_TIME_STEP]; + + // Use the event loop to redraw the image repeatedly. + // Using the event loop to allow the application to process + // expose events. + while (steps) + { + NSEvent *theEvent = [NSApp nextEventMatchingMask: NSPeriodicMask + untilDate: [NSDate distantFuture] + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + + if ([theEvent type] != NSPeriodic) + { + NSDebugLLog (@"NSDragging", + @"Unexpected event type: %d during slide", + [theEvent type]); + } + newPosition.x = (screenPoint.x + ((float) steps - 1.0) + * dragPosition.x) / ((float) steps); + newPosition.y = (screenPoint.y + ((float) steps - 1.0) + * dragPosition.y) / ((float) steps); + + [self _moveDraggedImageToNewPosition]; + steps --; + } + [NSEvent stopPeriodicEvents]; + } + if (waitFlag) + { + [NSThread sleepUntilDate: + [NSDate dateWithTimeIntervalSinceNow: SLIDE_TIME_STEP * 2.0]]; + } +} + + +- (void) slideDraggedImageTo: (NSPoint) point +{ + [self _slideDraggedImageTo: point + numberOfSteps: SLIDE_NR_OF_STEPS + waitAfterSlide: YES]; +} + + +/* + Search all descendents of parent and return + X window containing screen coordinates (x,y) that accepts drag and drop. + -1 if we can only find the X window that we are dragging + None if there is no X window that accepts drag and drop. +*/ +- (Window) _xWindowAcceptingDnDDescendentOf: (Window) parent + underX: (int) x + Y: (int) y +{ + Window *children; + int nchildren; + Window result = None; + Window ignore, child2, root; + Display *display = XDPY; + XWindowAttributes attr; + int ret_x, ret_y; + + if (parent == dragWindev->ident) + return -1; + + XQueryTree(display, parent, &root, &ignore, &children, &nchildren); + + while (nchildren-- > 0) + { + Window child = children [nchildren]; + + if (XGetWindowAttributes (display, child, &attr) + && attr.map_state == IsViewable + && XTranslateCoordinates (display, root, child, x, y, &ret_x, &ret_y, + &child2) + && ret_x >= 0 && ret_x < attr.width + && ret_y >= 0 && ret_y < attr.height) + { + result = [self _xWindowAcceptingDnDDescendentOf: child + underX: x + Y: y]; + if (result != -1) + break; + } + } + + if (children) + { + XFree (children); + } + if (result == (Window) None) + { + if (xdnd_is_dnd_aware (&dnd, parent, &dnd.dragging_version, typelist)) + { + result = parent; + } + } + + return result; +} + +/* + Return window under the mouse that accepts drag and drop + */ +- (Window) _xWindowAcceptingDnDunderX: (int) x Y: (int) y +{ + Window result; + + result = [self _xWindowAcceptingDnDDescendentOf: dragWindev->root + underX: x + Y: y]; + if (result == -1) + return None; + else + return result; +} + +@end + + + +@interface XGServer (DragAndDrop) +- (void) _resetDragTypesForWindow: (NSWindow *)win; +@end + + +@implementation XGServer (DragAndDrop) + +- (void) _resetDragTypesForWindow: (NSWindow *)win +{ + int winNum; + Atom *typelist; + gswindow_device_t *window; + NSCountedSet *drag_set = [self dragTypesForWindow: win]; + + winNum = [win windowNumber]; + window = [isa _windowWithTag: winNum]; + + GSEnsureDndIsInitialized (); + + typelist = mimeTypeForPasteboardType(XDPY, [self zone], + [drag_set allObjects]); + NSDebugLLog(@"NSDragging", @"Set types on %x to %@", + window->ident, drag_set); + xdnd_set_dnd_aware(&dnd, window->ident, typelist); + + NSZoneFree([self zone], typelist); +} + +- (BOOL) addDragTypes: (NSArray*)types toWindow: (NSWindow *)win +{ + BOOL did_add; + int winNum; + + did_add = [super addDragTypes: types toWindow: win]; + /* Check if window device exists */ + winNum = [win windowNumber]; + if (winNum > 0 && did_add == YES) + { + [self _resetDragTypesForWindow: win]; + } + return did_add; +} + +- (BOOL) removeDragTypes: (NSArray*)types fromWindow: (NSWindow *)win +{ + BOOL did_change; + int winNum; + + did_change = [super removeDragTypes: types fromWindow: win]; + /* Check if window device exists. */ + winNum = [win windowNumber]; + if (winNum > 0 && did_change == YES) + { + [self _resetDragTypesForWindow: win]; + } + return did_change; +} + +@end + + + + +@implementation XGRawWindow + +- (BOOL) canBecomeMainWindow +{ + return NO; +} + +- (BOOL) canBecomeKeyWindow +{ + return NO; +} + +- (void) _initDefaults +{ + [super _initDefaults]; + [self setReleasedWhenClosed: NO]; + [self setExcludedFromWindowsMenu: YES]; +} + +- (void) orderWindow: (NSWindowOrderingMode)place relativeTo: (int)otherWin +{ + XSetWindowAttributes winattrs; + unsigned long valuemask; + gswindow_device_t *window; + + [super orderWindow: place relativeTo: otherWin]; + + window = [XGServer _windowWithTag: _windowNum]; + valuemask = (CWSaveUnder|CWOverrideRedirect); + winattrs.save_under = True; + /* Temporarily make this False? we don't handle it correctly (fedor) */ + winattrs.override_redirect = False; + XChangeWindowAttributes (XDPY, window->ident, valuemask, &winattrs); +} + +@end diff --git a/Source/x11/XGServer.m b/Source/x11/XGServer.m new file mode 100644 index 0000000..1941f20 --- /dev/null +++ b/Source/x11/XGServer.m @@ -0,0 +1,424 @@ +/* -*- mode:ObjC -*- + XGServer - X11 Server Class + + Copyright (C) 1998,2002 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Mar 2002 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_WRASTER_H +#include "wraster.h" +#else +#include "x11/wraster.h" +#endif + +#include "x11/XGServer.h" +#include "x11/XGInputServer.h" + +#include +#include +#include + +extern int XGErrorHandler(Display *display, XErrorEvent *err); + +@interface XGServer (Window) +- (void) _setupRootWindow; +@end + +@interface XGServer (Private) +- (void) setupRunLoopInputSourcesForMode: (NSString*)mode; +@end + +#define XDPY (((RContext *)context)->dpy) +#define XSCR (((RContext *)context)->screen_number) + +/** + + XGServer + +*/ +@implementation XGServer + +/* Initialize AppKit backend */ ++ (void)initializeBackend +{ + NSDebugLog(@"Initializing GNUstep x11 backend.\n"); + [GSDisplayServer setDefaultServerClass: [XGServer class]]; +} + +/** + Returns a pointer to the current X-Windows display variable for + the current context. +*/ ++ (Display*) currentXDisplay +{ + return [(XGServer*)GSCurrentServer() xDisplay]; +} + +- (RContextAttributes *) _getXDefaults +{ + int dummy; + RContextAttributes *attribs; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + attribs = (RContextAttributes *)malloc(sizeof(RContextAttributes)); + + attribs->flags = 0; + if ([defaults boolForKey: @"NSDefaultVisual"]) + attribs->flags |= RC_DefaultVisual; + if ((dummy = [defaults integerForKey: @"NSDefaultVisual"])) + { + attribs->flags |= RC_VisualID; + attribs->visualid = dummy; + } + if ((dummy = [defaults integerForKey: @"NSColorsPerChannel"])) + { + attribs->flags |= RC_ColorsPerChannel; + attribs->colors_per_channel = dummy; + } + + return attribs; +} + +- _initXContext +{ + Display *dpy; + int screen_number; + NSString *display_name; + RContext *rcontext; + RContextAttributes *attribs; + XColor testColor; + unsigned char r, g, b; + + display_name = [server_info objectForKey: @"DisplayName"]; + if (display_name == nil) + { + NSString *host; + NSString *dnum = @"0.0"; + + host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"]; + if (host == nil) + { + NSString *d = [[[NSProcessInfo processInfo] environment] + objectForKey: @"DISPLAY"]; + + if (d == nil) + { + host = @""; + } + else + { + if ([d hasPrefix: @":"] == YES) + { + host = @""; // local host + } + else + { + NSArray *a = [d componentsSeparatedByString: @":"]; + + if ([a count] != 2) + { + NSLog(@"X DISPLAY environment variable has bad format" + @" assuming local X server (DISPLAY=:0.0)"); + host = @""; + } + else + { + host = [a objectAtIndex: 0]; + dnum = [a lastObject]; + if ([dnum isEqual: @"0"] == NO + && [dnum hasPrefix: @"0."] == NO) + { + NSLog(@"Only one display per host fully supported."); + } + } + } + if ([host isEqual: @""] == NO) + { + /** + * If we are using the DISPLAY environment variable to + * determine where to display, set the NSHost default + * so that other parts of the system know where we are + * displaying. + */ + [[NSUserDefaults standardUserDefaults] registerDefaults: + [NSDictionary dictionaryWithObject: host + forKey: @"NSHost"]]; + } + } + } + if ([host isEqual: @""] == NO) + { + /** + * If the NSHost default told us to display somewhere, we need + * to generate a display name for X from the host name and the + * default display and screen numbers (zero). + */ + display_name = [NSString stringWithFormat: @"%@:%@", host, dnum]; + } + } + + if (display_name) + { + dpy = XOpenDisplay([display_name cString]); + } + else + { + dpy = XOpenDisplay(NULL); + display_name = [NSString stringWithCString: XDisplayName(NULL)]; + } + + /* Use the fact that the screen number is specified like an extension + e.g. hostname:0.1 */ + screen_number = [[display_name pathExtension] intValue]; + + if (dpy == NULL) + { + char *dname = XDisplayName([display_name cString]); + [NSException raise: @"DPSconfigurationerror" + format: @"Unable to connect to X Server `%s'", dname]; + } + else + NSDebugLog(@"Opened display %@", display_name); + + /* Get the visual information */ + attribs = NULL; + //attribs = [self _getXDefaults]; + rcontext = RCreateContext(dpy, screen_number, attribs); + context = (void *)rcontext; + + /* + * If we have shared memory available, only use it when the XGPS-Shm + * default is set to YES + */ + if (rcontext->attribs->use_shared_memory == True + && [[NSUserDefaults standardUserDefaults] boolForKey: @"XGPS-Shm"] != YES) + rcontext->attribs->use_shared_memory = False; + + /* + * Crude tests to see if we can accelerate creation of pixels from + * 8-bit red, green and blue color values. + */ + if (rcontext->depth == 12 || rcontext->depth == 16) + { + drawMechanism = XGDM_FAST16; + r = 8; + g = 9; + b = 7; + testColor.pixel = (((r << 5) + g) << 6) + b; + XQueryColor(rcontext->dpy, rcontext->cmap, &testColor); + if (((testColor.red >> 11) != r) + || ((testColor.green >> 11) != g) + || ((testColor.blue >> 11) != b)) + { + NSLog(@"WARNING - XGServer is unable to use the " + @"fast algorithm for writing to a 16-bit display on " + @"this host - perhaps you'd like to adjust the code " + @"to work ... and submit a patch."); + drawMechanism = XGDM_PORTABLE; + } + } + else if (rcontext->depth == 15) + { + drawMechanism = XGDM_FAST15; + r = 8; + g = 9; + b = 7; + testColor.pixel = (((r << 5) + g) << 5) + b; + XQueryColor(rcontext->dpy, rcontext->cmap, &testColor); + if (((testColor.red >> 11) != r) + || ((testColor.green >> 11) != g) + || ((testColor.blue >> 11) != b)) + { + NSLog(@"WARNING - XGServer is unable to use the " + @"fast algorithm for writing to a 15-bit display on " + @"this host - perhaps you'd like to adjust the code " + @"to work ... and submit a patch."); + drawMechanism = XGDM_PORTABLE; + } + } + else if (rcontext->depth == 24 || rcontext->depth == 32) + { + drawMechanism = XGDM_FAST32; + r = 32; + g = 33; + b = 31; + testColor.pixel = (((r << 8) + g) << 8) + b; + XQueryColor(rcontext->dpy, rcontext->cmap, &testColor); + if (((testColor.red >> 8) == r) + && ((testColor.green >> 8) == g) + && ((testColor.blue >> 8) == b)) + { + drawMechanism = XGDM_FAST32; + } + else if (((testColor.red >> 8) == b) + && ((testColor.green >> 8) == g) + && ((testColor.blue >> 8) == r)) + { + drawMechanism = XGDM_FAST32_BGR; + } + else + { + NSLog(@"WARNING - XGServer is unable to use the " + @"fast algorithm for writing to a 32-bit display on " + @"this host - perhaps you'd like to adjust the code " + @"to work ... and submit a patch."); + drawMechanism = XGDM_PORTABLE; + } + } + else + { + NSLog(@"WARNING - XGServer is unable to use a " + @"fast algorithm for writing to the display on " + @"this host - perhaps you'd like to adjust the code " + @"to work ... and submit a patch."); + drawMechanism = XGDM_PORTABLE; + } + + XSetErrorHandler(XGErrorHandler); + + if (GSDebugSet(@"XSynchronize") == YES) + XSynchronize(dpy, True); + + [self _setupRootWindow]; + inputServer = [[XIMInputServer allocWithZone: [self zone]] + initWithDelegate: nil display: dpy name: @"XIM"]; + return self; +} + +/** + Opens the X display (using a helper method) and sets up basic + display mechanisms, such as visuals and colormaps. +*/ +- (id) initWithAttributes: (NSDictionary *)info +{ + [self _initXContext]; + [super initWithAttributes: info]; + + [self setupRunLoopInputSourcesForMode: NSDefaultRunLoopMode]; + [self setupRunLoopInputSourcesForMode: NSConnectionReplyMode]; + [self setupRunLoopInputSourcesForMode: NSModalPanelRunLoopMode]; + [self setupRunLoopInputSourcesForMode: NSEventTrackingRunLoopMode]; + return self; +} + +/** + Closes all X resources, the X display and dealloc other ivars. +*/ +- (void) dealloc +{ + NSDebugLog(@"Destroying X11 Server"); + DESTROY(inputServer); + [self _destroyServerWindows]; + XCloseDisplay(XDPY); + [super dealloc]; +} + +/** + Returns the XGDrawMechanism, which roughly describes the depth of + the screen and how pixels should be drawn to the screen for maximum + speed. +*/ +- (XGDrawMechanism) drawMechanism +{ + return drawMechanism; +} + +/** + Returns a pointer to a structure which describes aspects of the + X windows display +*/ +- (void *) xrContext +{ + return context; +} + +/* + Returns a pointer to the X windows display variable +*/ +- (Display *) xDisplay +{ + return XDPY; +} + +/** + Returns the root window of the display +*/ +- (Window) xDisplayRootWindow +{ + return RootWindow(XDPY, XSCR); +} + +/** + Returns the application root window, which is used for many things + such as window hints +*/ +- (Window) xAppRootWindow +{ + return generic.appRootWindow; +} + +/** + Returns the closest color in the current colormap to the indicated + X color +*/ +- (XColor)xColorFromColor: (XColor)color +{ + Status ret; + RColor rcolor; + Colormap colormap = XDefaultColormap(XDPY, XSCR); + XAllocColor(XDPY, colormap, &color); + rcolor.red = color.red / 256; + rcolor.green = color.green / 256; + rcolor.blue = color.blue / 256; + ret = RGetClosestXColor((RContext *)context, &rcolor, &color); + if (ret == False) + NSLog(@"Failed to alloc color (%d,%d,%d)\n", + (int)rcolor.red, (int)rcolor.green, (int)rcolor.blue); + return color; +} + +/** + Wait for all contexts to finish processing. Only used with XDPS graphics. +*/ ++ (void) waitAllContexts +{ + if ([[GSCurrentContext() class] + respondsToSelector: @selector(waitAllContexts)]) + [[GSCurrentContext() class] waitAllContexts]; +} + +@end diff --git a/Source/x11/XGServerEvent.m b/Source/x11/XGServerEvent.m new file mode 100644 index 0000000..ac22c80 --- /dev/null +++ b/Source/x11/XGServerEvent.m @@ -0,0 +1,1828 @@ +/* + XGServerEvent - Window/Event code for X11 backends. + + Copyright (C) 1998,1999 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1998 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "x11/XGServerWindow.h" +#include "x11/XGInputServer.h" +#include "x11/XGDragView.h" +#include "x11/XGGeneric.h" +#include "x11/xdnd.h" + +#ifdef HAVE_WRASTER_H +#include "wraster.h" +#else +#include "x11/wraster.h" +#endif + +#include "math.h" +#include +#include + +#if LIB_FOUNDATION_LIBRARY +# include +#elif defined(NeXT_PDO) +# include +# include +#endif + +#define cWin ((gswindow_device_t*)generic.cachedWindow) + +extern Atom WM_STATE; + +// NumLock's mask (it depends on the keyboard mapping) +static unsigned int _num_lock_mask; +// Modifier state +static char _control_pressed = 0; +static char _command_pressed = 0; +static char _alt_pressed = 0; +// Keys used for the modifiers (you may set them with user preferences) +static KeyCode _control_keycodes[2]; +static KeyCode _command_keycodes[2]; +static KeyCode _alt_keycodes[2]; + +static BOOL _is_keyboard_initialized = NO; + +void __objc_xgcontextevent_linking (void) +{ +} + + +@interface XGServer (Private) +- (void) receivedEvent: (void*)data + type: (RunLoopEventType)type + extra: (void*)extra + forMode: (NSString*)mode; +- (void) setupRunLoopInputSourcesForMode: (NSString*)mode; +- (NSDate*) timedOutEvent: (void*)data + type: (RunLoopEventType)type + forMode: (NSString*)mode; +- (int) XGErrorHandler: (Display*)display : (XErrorEvent*)err; +@end + + +int +XGErrorHandler(Display *display, XErrorEvent *err) +{ + XGServer *ctxt = (XGServer*)GSCurrentServer(); + + return [ctxt XGErrorHandler: display : err]; +} + +static NSEvent*process_key_event (XEvent* xEvent, XGServer* ctxt, + NSEventType eventType); + +static unichar process_char (KeySym keysym, unsigned *eventModifierFlags); + +static unsigned process_modifier_flags(unsigned int state); + +static void initialize_keyboard (void); + +static void set_up_num_lock (void); + +static inline int check_modifier (XEvent *xEvent, KeyCode key_code) +{ + return (xEvent->xkeymap.key_vector[key_code / 8] & (1 << (key_code % 8))); +} + +#define XDPY (((RContext *)context)->dpy) +#define XSCR (((RContext *)context)->screen_number) + +@implementation XGServer (X11Methods) + +- (int) XGErrorHandler: (Display*)display : (XErrorEvent*)err +{ + int length = 1024; + char buffer[length+1]; + + /* + * Ignore attempts to set input focus to unmapped window, except for noting + * if the most recent request failed (mark the request serial number to 0) + * in which case we should repeat the request when the window becomes + * mapped again. + */ + if (err->error_code == BadMatch && err->request_code == X_SetInputFocus) + { + if (err->serial == generic.focusRequestNumber) + { + generic.focusRequestNumber = 0; + } + return 0; + } + + XGetErrorText(display, err->error_code, buffer, length); + if (err->type == 0 + && GSDebugSet(@"XSynchronize") == NO) + { + NSLog(@"X-Windows error - %s\n\ + on display: %s\n\ + type: %d\n\ + serial number: %d\n\ + request code: %d\n", + buffer, + XDisplayName(DisplayString(display)), + err->type, err->serial, err->request_code); + return 0; + } + [NSException raise: NSWindowServerCommunicationException + format: @"X-Windows error - %s\n\ + on display: %s\n\ + type: %d\n\ + serial number: %d\n\ + request code: %d\n", + buffer, + XDisplayName(DisplayString(display)), + err->type, err->serial, err->request_code]; + return 0; +} + +- (void) setupRunLoopInputSourcesForMode: (NSString*)mode +{ + int xEventQueueFd = XConnectionNumber(XDPY); + NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; + +#if defined(LIB_FOUNDATION_LIBRARY) + { + id fileDescriptor = [[[NSPosixFileDescriptor alloc] + initWithFileDescriptor: xEventQueueFd] + autorelease]; + + // Invoke limitDateForMode: to setup the current + // mode of the run loop (the doc says that this + // method and acceptInputForMode: beforeDate: are + // the only ones that setup the current mode). + + [currentRunLoop limitDateForMode: mode]; + + [fileDescriptor setDelegate: self]; + [fileDescriptor monitorFileActivity: NSPosixReadableActivity]; + } +#elif defined(NeXT_PDO) + { + id fileDescriptor = [[[NSFileHandle alloc] + initWithFileDescriptor: xEventQueueFd] + autorelease]; + + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector(activityOnFileHandle: ) + name: NSFileHandleDataAvailableNotification + object: fileDescriptor]; + [fileDescriptor waitForDataInBackgroundAndNotifyForModes: + [NSArray arrayWithObject: mode]]; + } +#else + [currentRunLoop addEvent: (void*)(gsaddr)xEventQueueFd + type: ET_RDESC + watcher: (id)self + forMode: mode]; +#endif +} + +#if LIB_FOUNDATION_LIBRARY +- (void) activity: (NSPosixFileActivities)activity + posixFileDescriptor: (NSPosixFileDescriptor*)fileDescriptor +{ + [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; +} +#elif defined(NeXT_PDO) +- (void) activityOnFileHandle: (NSNotification*)notification +{ + id fileDescriptor = [notification object]; + id runLoopMode = [[NSRunLoop currentRunLoop] currentMode]; + + [fileDescriptor waitForDataInBackgroundAndNotifyForModes: + [NSArray arrayWithObject: runLoopMode]]; + [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; +} +#endif + +- (void) receivedEvent: (void*)data + type: (RunLoopEventType)type + extra: (void*)extra + forMode: (NSString*)mode +{ + static int clickCount = 1; + static unsigned int eventFlags; + NSEvent *e = nil; + XEvent xEvent; + static NSPoint eventLocation; + NSWindow *nswin; + Window xWin; + NSEventType eventType; + NSGraphicsContext *gcontext; + float deltaX; + float deltaY; + + /* FIXME: How do you guarentee a context is associated with an event? */ + gcontext = GSCurrentContext(); + + // loop and grab all of the events from the X queue + while (XPending(XDPY) > 0) + { + XNextEvent(XDPY, &xEvent); + +#ifdef USE_XIM + if (XFilterEvent(&xEvent, None)) + { + NSDebugLLog(@"NSKeyEvent", @"Event filtered (by XIM?)\n"); + continue; + } +#endif + + switch (xEvent.type) + { + // mouse button events + case ButtonPress: + NSDebugLLog(@"NSEvent", @"%d ButtonPress: \ + xEvent.xbutton.time %u timeOfLastClick %u \n", + xEvent.xbutton.window, xEvent.xbutton.time, + generic.lastClick); + /* + * hardwired test for a double click + * + * For multiple clicks, the clicks must remain in the same + * region of the same window and must occur in a limited time. + * + * default time of 300 should be user set; + * perhaps the movement of 3 should also be a preference? + */ + { + BOOL incrementCount = YES; + +#define CLICK_TIME 300 +#define CLICK_MOVE 3 + if (xEvent.xbutton.time + >= (unsigned long)(generic.lastClick + CLICK_TIME)) + incrementCount = NO; + else if (generic.lastClickWindow != xEvent.xbutton.window) + incrementCount = NO; + else if ((generic.lastClickX - xEvent.xbutton.x) > CLICK_MOVE) + incrementCount = NO; + else if ((generic.lastClickX - xEvent.xbutton.x) < -CLICK_MOVE) + incrementCount = NO; + else if ((generic.lastClickY - xEvent.xbutton.y) > CLICK_MOVE) + incrementCount = NO; + else if ((generic.lastClickY - xEvent.xbutton.y) < -CLICK_MOVE) + incrementCount = NO; + + if (incrementCount == YES) + { + clickCount++; + } + else + { + /* + * Not a multiple-click, so we must set the stored + * location of the click to the new values and + * reset the counter. + */ + clickCount = 1; + generic.lastClickWindow = xEvent.xbutton.window; + generic.lastClickX = xEvent.xbutton.x; + generic.lastClickY = xEvent.xbutton.y; + } + } + generic.lastClick = xEvent.xbutton.time; + generic.lastTime = generic.lastClick; + + if (xEvent.xbutton.button == generic.lMouse) + eventType = NSLeftMouseDown; + else if (xEvent.xbutton.button == generic.rMouse + && generic.rMouse != 0) + eventType = NSRightMouseDown; + else if (xEvent.xbutton.button == generic.mMouse + && generic.mMouse != 0) + eventType = NSOtherMouseDown; + else if (xEvent.xbutton.button == generic.upMouse + && generic.upMouse != 0) + { + deltaY = 1.; + eventType = NSScrollWheel; + } + else if (xEvent.xbutton.button == generic.downMouse + && generic.downMouse != 0) + { + deltaY = -1.; + eventType = NSScrollWheel; + } + else + { + break; /* Unknown button */ + } + + eventFlags = process_modifier_flags(xEvent.xbutton.state); + // if pointer is grabbed use grab window + xWin = (grabWindow == 0) ? xEvent.xbutton.window : grabWindow; + if (cWin == 0 || xWin != cWin->ident) + cWin = [XGServer _windowForXWindow: xWin]; + if (cWin == 0) + break; + eventLocation.x = xEvent.xbutton.x; + eventLocation.y = NSHeight(cWin->xframe)-xEvent.xbutton.y; + + if (generic.flags.useWindowMakerIcons == 1) + { + /* + * We must hand over control of our icon/miniwindow + * to Window Maker. + */ + if ((cWin->win_attrs.window_style + & (NSMiniWindowMask | NSIconWindowMask)) != 0 + && eventType == NSLeftMouseDown && clickCount == 1) + { + if (cWin->parent == None) + break; + xEvent.xbutton.window = cWin->parent; + XUngrabPointer(XDPY, CurrentTime); + XSendEvent(XDPY, cWin->parent, True, + ButtonPressMask, &xEvent ); + XFlush(XDPY); + break; + } + } + + // create NSEvent + e = [NSEvent mouseEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval)generic.lastClick + windowNumber: cWin->number + context: gcontext + eventNumber: xEvent.xbutton.serial + clickCount: clickCount + pressure: 1.0 + buttonNumber: 0 /* FIXME */ + deltaX: 0. + deltaY: deltaY + deltaZ: 0.]; + break; + + case ButtonRelease: + NSDebugLLog(@"NSEvent", @"%d ButtonRelease\n", + xEvent.xbutton.window); + generic.lastTime = xEvent.xbutton.time; + if (xEvent.xbutton.button == generic.lMouse) + eventType = NSLeftMouseUp; + else if (xEvent.xbutton.button == generic.rMouse + && generic.rMouse != 0) + eventType = NSRightMouseUp; + else if (xEvent.xbutton.button == generic.mMouse + && generic.mMouse != 0) + eventType = NSOtherMouseUp; + else + { + // we ignore release of scrollUp or scrollDown + break; /* Unknown button */ + } + + eventFlags = process_modifier_flags(xEvent.xbutton.state); + // if pointer is grabbed use grab window + xWin = (grabWindow == 0) ? xEvent.xbutton.window : grabWindow; + if (cWin == 0 || xWin != cWin->ident) + cWin = [XGServer _windowForXWindow: xWin]; + if (cWin == 0) + break; + eventLocation.x = xEvent.xbutton.x; + eventLocation.y = NSHeight(cWin->xframe)-xEvent.xbutton.y; + + e = [NSEvent mouseEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval)generic.lastTime + windowNumber: cWin->number + context: gcontext + eventNumber: xEvent.xbutton.serial + clickCount: clickCount + pressure: 1.0 + buttonNumber: 0 /* FIXMME */ + deltaX: 0.0 + deltaY: 0.0 + deltaZ: 0.0]; + break; + + case CirculateNotify: + NSDebugLLog(@"NSEvent", @"%d CirculateNotify\n", + xEvent.xcirculate.window); + break; + + case CirculateRequest: + NSDebugLLog(@"NSEvent", @"%d CirculateRequest\n", + xEvent.xcirculaterequest.window); + break; + + case ClientMessage: + { + NSTimeInterval time; + DndClass dnd = xdnd (); + + NSDebugLLog(@"NSEvent", @"%d ClientMessage\n", + xEvent.xclient.window); + if (cWin == 0 || xEvent.xclient.window != cWin->ident) + cWin = [XGServer _windowForXWindow: xEvent.xclient.window]; + if (cWin == 0) + break; + if (xEvent.xclient.message_type == generic.protocols_atom) + { + generic.lastTime = (Time)xEvent.xclient.data.l[1]; + NSDebugLLog(@"NSEvent", @"WM Protocol - %s\n", + XGetAtomName(XDPY, xEvent.xclient.data.l[0])); + + if (xEvent.xclient.data.l[0] == generic.delete_win_atom) + { + /* + * WM is asking us to close a window + */ + eventLocation = NSMakePoint(0,0); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitWindowClose + data1: 0 + data2: 0]; + } + else if (xEvent.xclient.data.l[0] + == generic.miniaturize_atom) + { + eventLocation = NSMakePoint(0,0); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitWindowMiniaturize + data1: 0 + data2: 0]; + } + else if (xEvent.xclient.data.l[0] + == generic.take_focus_atom) + { + Window rootWin; + Window childWin; + gswindow_device_t *w = 0; + int currentX; + int currentY; + int winX; + int winY; + unsigned mask; + BOOL ok; + + /* + * WM is asking us to take the keyboard focus + */ + NSDebugLLog(@"Focus", @"check focus: %d", + cWin->number); + ok = XQueryPointer (XDPY, [self xDisplayRootWindow], + &rootWin, &childWin, ¤tX, ¤tY, + &winX, &winY, &mask); + if (ok != 0 && childWin != 0) + { + w = [XGServer _windowForXWindow: childWin]; + if (w == 0) + { + /* + * Is the mouse in the border of a window? + */ + w = [XGServer _windowForXParent: childWin]; + } + } + if (w == 0) + { + /* + * If we can't locate the window under the mouse, + * assume an existing window. + */ + nswin = [NSApp keyWindow]; + if (nswin == nil) + { + nswin = [NSApp mainWindow]; + } + if (nswin != nil) + { + w = [XGServer _windowWithTag: + [nswin windowNumber]]; + } + } + if (w != 0) + { + cWin = w; + } + nswin = [NSApp keyWindow]; + if (nswin == nil + || [nswin windowNumber] != cWin->number) + { + generic.desiredFocusWindow = 0; + generic.focusRequestNumber = 0; + eventLocation = NSMakePoint(0,0); + e = [NSEvent otherEventWithType:NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitWindowFocusIn + data1: 0 + data2: 0]; + } + if (nswin != nil + && [nswin windowNumber] == cWin->number) + { + /* + * We reassert our desire to have input + * focus in our existing key window. + */ + [self setinputstate: GSTitleBarKey + : [nswin windowNumber]]; + [self setinputfocus: [nswin windowNumber]]; + } + } + } + else if (xEvent.xclient.message_type == dnd.XdndEnter) + { + Window source; + + NSDebugLLog(@"NSDragging", @" XdndEnter message\n"); + source = XDND_ENTER_SOURCE_WIN(&xEvent); + eventLocation = NSMakePoint(0,0); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitDraggingEnter + data1: source + data2: 0]; + /* If this is a non-local drag, set the dragInfo */ + if ([XGServer _windowForXWindow: source] == NULL) + { + [[XGDragView sharedDragView] setupDragInfoFromXEvent: + &xEvent]; + } + } + else if (xEvent.xclient.message_type == dnd.XdndPosition) + { + Window source; + Atom action; + NSDragOperation operation; + + NSDebugLLog(@"NSDragging", @" XdndPosition message\n"); + source = XDND_POSITION_SOURCE_WIN(&xEvent); + eventLocation.x = XDND_POSITION_ROOT_X(&xEvent) - + NSMinX(cWin->xframe); + eventLocation.y = XDND_POSITION_ROOT_Y(&xEvent) - + NSMinY(cWin->xframe); + eventLocation.y = NSHeight(cWin->xframe) - + eventLocation.y; + time = XDND_POSITION_TIME(&xEvent); + action = XDND_POSITION_ACTION(&xEvent); + operation = GSDragOperationForAction(action); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: time + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitDraggingUpdate + data1: source + data2: operation]; + /* If this is a non-local drag, update the dragInfo */ + if ([XGServer _windowForXWindow: source] == NULL) + { + [[XGDragView sharedDragView] updateDragInfoFromEvent: + e]; + } + } + else if (xEvent.xclient.message_type == dnd.XdndStatus) + { + Window target; + Atom action; + NSDragOperation operation; + + NSDebugLLog(@"NSDragging", @" XdndStatus message\n"); + target = XDND_STATUS_TARGET_WIN(&xEvent); + eventLocation = NSMakePoint(0, 0); + if (XDND_STATUS_WILL_ACCEPT (&xEvent)) + { + action = XDND_STATUS_ACTION(&xEvent); + } + else + { + action = NSDragOperationNone; + } + + operation = GSDragOperationForAction(action); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitDraggingStatus + data1: target + data2: operation]; + } + else if (xEvent.xclient.message_type == dnd.XdndLeave) + { + Window source; + + NSDebugLLog(@"NSDragging", @" XdndLeave message\n"); + source = XDND_LEAVE_SOURCE_WIN(&xEvent); + eventLocation = NSMakePoint(0, 0); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitDraggingExit + data1: 0 + data2: 0]; + /* If this is a non-local drag, reset the dragInfo */ + if ([XGServer _windowForXWindow: source] == NULL) + { + [[XGDragView sharedDragView] resetDragInfo]; + } + } + else if (xEvent.xclient.message_type == dnd.XdndDrop) + { + Window source; + + NSDebugLLog(@"NSDragging", @" XdndDrop message\n"); + source = XDND_DROP_SOURCE_WIN(&xEvent); + eventLocation = NSMakePoint(0, 0); + time = XDND_DROP_TIME(&xEvent); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: time + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitDraggingDrop + data1: source + data2: 0]; + } + else if (xEvent.xclient.message_type == dnd.XdndFinished) + { + Window target; + + NSDebugLLog(@"NSDragging", @" XdndFinished message\n"); + target = XDND_FINISHED_TARGET_WIN(&xEvent); + eventLocation = NSMakePoint(0, 0); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitDraggingFinished + data1: target + data2: 0]; + } + } + break; + + case ColormapNotify: + // colormap attribute + NSDebugLLog(@"NSEvent", @"%d ColormapNotify\n", + xEvent.xcolormap.window); + break; + + // the window has been resized, change the width and height + // and update the window so the changes get displayed + case ConfigureNotify: + NSDebugLLog(@"NSEvent", @"%d ConfigureNotify " + @"x:%d y:%d w:%d h:%d b:%d %c", xEvent.xconfigure.window, + xEvent.xconfigure.x, xEvent.xconfigure.y, + xEvent.xconfigure.width, xEvent.xconfigure.height, + xEvent.xconfigure.border_width, + xEvent.xconfigure.send_event ? 'T' : 'F'); + if (cWin == 0 || xEvent.xconfigure.window != cWin->ident) + cWin = [XGServer _windowForXWindow:xEvent.xconfigure.window]; + /* + * Ignore events for unmapped windows. + */ + if (cWin != 0 && cWin->map_state == IsViewable) + { + NSRect r, x, n, h; + NSTimeInterval ts = (NSTimeInterval)generic.lastMotion; + + /* + * Get OpenStep frame coordinates from X frame. + * If it's not from the window mmanager, ignore x and y. + */ + r = cWin->xframe; + if (xEvent.xconfigure.send_event == 0) + { + x = NSMakeRect(r.origin.x, r.origin.y, + xEvent.xconfigure.width, xEvent.xconfigure.height); + } + else + { + x = NSMakeRect(xEvent.xconfigure.x, + xEvent.xconfigure.y, + xEvent.xconfigure.width, + xEvent.xconfigure.height); + cWin->xframe.origin = x.origin; + } + n = [self _XFrameToOSFrame: x for: cWin]; + NSDebugLLog(@"Moving", + @"Update win %d:\n original:%@\n new:%@", + cWin->number, NSStringFromRect(r), + NSStringFromRect(x)); + /* + * Set size hints info to be up to date with new size. + */ + h = [self _OSFrameToXHints: n for: cWin]; + cWin->siz_hints.width = h.size.width; + cWin->siz_hints.height = h.size.height; + //if (xEvent.xconfigure.send_event != 0) + { + cWin->siz_hints.x = h.origin.x; + cWin->siz_hints.y = h.origin.y; + } + + /* + * create GNUstep event(s) + */ + if (!NSEqualSizes(r.size, x.size)) + { + /* Resize events move the origin. There's no goo + place to pass this info back, so we put it in + the event location field */ + e = [NSEvent otherEventWithType: NSAppKitDefined + location: n.origin + modifierFlags: eventFlags + timestamp: ts + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitWindowResized + data1: n.size.width + data2: n.size.height]; + } + if (!NSEqualPoints(r.origin, x.origin)) + { + if (e != nil) + { + [event_queue addObject: e]; + } + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: eventFlags + timestamp: ts + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitWindowMoved + data1: n.origin.x + data2: n.origin.y]; + } + } + break; + + // same as ConfigureNotify but we get this event + // before the change has actually occurred + case ConfigureRequest: + NSDebugLLog(@"NSEvent", @"%d ConfigureRequest\n", + xEvent.xconfigurerequest.window); + break; + + // a window has been created + case CreateNotify: + NSDebugLLog(@"NSEvent", @"%d CreateNotify\n", + xEvent.xcreatewindow.window); + break; + + // a window has been destroyed + case DestroyNotify: + NSDebugLLog(@"NSEvent", @"%d DestroyNotify\n", + xEvent.xdestroywindow.window); + break; + + // when the pointer enters a window + case EnterNotify: + NSDebugLLog(@"NSEvent", @"%d EnterNotify\n", + xEvent.xcrossing.window); + break; + + // when the pointer leaves a window + case LeaveNotify: + NSDebugLLog(@"NSEvent", @"%d LeaveNotify\n", + xEvent.xcrossing.window); + if (cWin == 0 || xEvent.xcrossing.window != cWin->ident) + cWin = [XGServer _windowForXWindow: xEvent.xcrossing.window]; + if (cWin == 0) + break; + eventLocation = NSMakePoint(-1,-1); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: eventLocation + modifierFlags: 0 + timestamp: 0 + windowNumber: cWin->number + context: gcontext + subtype: GSAppKitWindowLeave + data1: 0 + data2: 0]; + break; + + // the visibility of a window has changed + case VisibilityNotify: + NSDebugLLog(@"NSEvent", @"%d VisibilityNotify %d\n", + xEvent.xvisibility.window, xEvent.xvisibility.state); + if (cWin == 0 || xEvent.xvisibility.window != cWin->ident) + cWin=[XGServer _windowForXWindow:xEvent.xvisibility.window]; + if (cWin != 0) + cWin->visibility = xEvent.xvisibility.state; + break; + + // a portion of the window has become visible and + // we must redisplay it + case Expose: + NSDebugLLog(@"NSEvent", @"%d Expose\n", + xEvent.xexpose.window); + { + if (cWin == 0 || xEvent.xexpose.window != cWin->ident) + cWin=[XGServer _windowForXWindow:xEvent.xexpose.window]; + if (cWin != 0) + { + XRectangle rectangle; + + rectangle.x = xEvent.xexpose.x; + rectangle.y = xEvent.xexpose.y; + rectangle.width = xEvent.xexpose.width; + rectangle.height = xEvent.xexpose.height; + NSDebugLLog(@"NSEvent", @"Expose frame %d %d %d %d\n", + rectangle.x, rectangle.y, + rectangle.width, rectangle.height); + [self _addExposedRectangle: rectangle : cWin->number]; + + if (xEvent.xexpose.count == 0) + [self _processExposedRectangles: cWin->number]; + } + break; + } + + // keyboard focus entered a window + case FocusIn: + NSDebugLLog(@"NSEvent", @"%d FocusIn\n", + xEvent.xfocus.window); + if (cWin == 0 || xEvent.xfocus.window != cWin->ident) + cWin=[XGServer _windowForXWindow:xEvent.xfocus.window]; + if (cWin == 0) + break; + NSDebugLLog(@"Focus", @"%d got focus on %d\n", + xEvent.xfocus.window, cWin->number); + generic.currentFocusWindow = cWin->number; + if (xEvent.xfocus.serial == generic.focusRequestNumber) + { + /* + * This is a response to our own request - so we mark the + * request as complete. + */ + generic.desiredFocusWindow = 0; + generic.focusRequestNumber = 0; + } + break; + + // keyboard focus left a window + case FocusOut: + { + Window fw; + int rev; + + /* + * See where the focus has moved to - + * If it has gone to 'none' or 'PointerRoot' then + * it's not one of ours. + * If it has gone to our root window - use the icon window. + * If it has gone to a window - we see if it is one of ours. + */ + XGetInputFocus(xEvent.xfocus.display, &fw, &rev); + NSDebugLLog(@"NSEvent", @"%d FocusOut\n", + xEvent.xfocus.window); + cWin = [XGServer _windowForXWindow: fw]; + if (cWin == 0) + { + cWin = [XGServer _windowForXParent: fw]; + } + if (cWin == 0) + { + nswin = nil; + } + else + { + nswin = GSWindowWithNumber(cWin->number); + } + if (nswin == nil) + { + [NSApp deactivate]; + } + cWin = [XGServer _windowForXWindow: xEvent.xfocus.window]; + NSDebugLLog(@"Focus", @"%d lost focus on %d\n", + xEvent.xfocus.window, cWin->number); + } + break; + + case GraphicsExpose: + NSDebugLLog(@"NSEvent", @"%d GraphicsExpose\n", + xEvent.xexpose.window); + break; + + case NoExpose: + NSDebugLLog(@"NSEvent", @"NoExpose\n"); + break; + + // window is moved because of a change in the size of its parent + case GravityNotify: + NSDebugLLog(@"NSEvent", @"%d GravityNotify\n", + xEvent.xgravity.window); + break; + + // a key has been pressed + case KeyPress: + NSDebugLLog(@"NSEvent", @"%d KeyPress\n", + xEvent.xkey.window); + generic.lastTime = xEvent.xkey.time; + e = process_key_event (&xEvent, self, NSKeyDown); + break; + + // a key has been released + case KeyRelease: + NSDebugLLog(@"NSEvent", @"%d KeyRelease\n", + xEvent.xkey.window); + generic.lastTime = xEvent.xkey.time; + e = process_key_event (&xEvent, self, NSKeyUp); + break; + + // reports the state of the keyboard when pointer or + // focus enters a window + case KeymapNotify: + NSDebugLLog(@"NSEvent", @"%d KeymapNotify\n", + xEvent.xkeymap.window); + // Check if control is pressed + _control_pressed = 0; + if (_control_keycodes[0] + && check_modifier (&xEvent, _control_keycodes[0])) + { + _control_pressed |= 1; + } + if (_control_keycodes[1] + && check_modifier (&xEvent, _control_keycodes[1])) + { + _control_pressed |= 2; + } + // Check if command is pressed + _command_pressed = 0; + if (_command_keycodes[0] + && check_modifier (&xEvent, _command_keycodes[0])) + { + _command_pressed |= 1; + } + if (_command_keycodes[1] + && check_modifier (&xEvent, _command_keycodes[2])) + { + _command_pressed = 2; + } + // Check if alt is pressed + _alt_pressed = 0; + if (_alt_keycodes[0] + && check_modifier (&xEvent, _alt_keycodes[0])) + { + _alt_pressed |= 1; + } + if (_alt_keycodes[1] + && check_modifier (&xEvent, _alt_keycodes[1])) + { + _alt_pressed |= 2; + } + break; + + // when a window changes state from ummapped to + // mapped or vice versa + case MapNotify: + NSDebugLLog(@"NSEvent", @"%d MapNotify\n", + xEvent.xmap.window); + if (cWin == 0 || xEvent.xmap.window != cWin->ident) + cWin=[XGServer _windowForXWindow:xEvent.xmap.window]; + if (cWin != 0) + { + cWin->map_state = IsViewable; + /* + * if the window that was just mapped wants the input + * focus, re-do the request. + */ + if (generic.desiredFocusWindow == cWin->number + && generic.focusRequestNumber == 0) + { + [self setinputfocus: cWin->number]; + } + /* + * Make sure that the newly mapped window displays. + */ + nswin = GSWindowWithNumber(cWin->number); + [nswin update]; + } + break; + + // Window is no longer visible. + case UnmapNotify: + NSDebugLLog(@"NSEvent", @"%d UnmapNotify\n", + xEvent.xunmap.window); + if (cWin == 0 || xEvent.xunmap.window != cWin->ident) + cWin=[XGServer _windowForXWindow:xEvent.xunmap.window]; + if (cWin != 0) + { + cWin->map_state = IsUnmapped; + cWin->visibility = -1; + } + break; + + // like MapNotify but occurs before the request is carried out + case MapRequest: + NSDebugLLog(@"NSEvent", @"%d MapRequest\n", + xEvent.xmaprequest.window); + break; + + // keyboard or mouse mapping has been changed by another client + case MappingNotify: + NSDebugLLog(@"NSEvent", @"%d MappingNotify\n", + xEvent.xmapping.window); + if ((xEvent.xmapping.request == MappingModifier) + || (xEvent.xmapping.request == MappingKeyboard)) + { + XRefreshKeyboardMapping (&xEvent.xmapping); + set_up_num_lock (); + } + break; + + case MotionNotify: + NSDebugLLog(@"NSMotionEvent", @"%d MotionNotify - %d %d\n", + xEvent.xmotion.window, xEvent.xmotion.x, xEvent.xmotion.y); + { + unsigned int state; + + /* + * Compress motion events to avoid flooding. + */ + while (XPending(xEvent.xmotion.display)) + { + XEvent peek; + + XPeekEvent(xEvent.xmotion.display, &peek); + if (peek.type == MotionNotify + && xEvent.xmotion.window == peek.xmotion.window + && xEvent.xmotion.subwindow == peek.xmotion.subwindow) + { + XNextEvent(xEvent.xmotion.display, &xEvent); + } + else + { + break; + } + } + + generic.lastMotion = xEvent.xmotion.time; + generic.lastTime = generic.lastMotion; + state = xEvent.xmotion.state; + if (state & generic.lMouseMask) + { + eventType = NSLeftMouseDragged; + } + else if (state & generic.rMouseMask) + { + eventType = NSRightMouseDragged; + } + else if (state & generic.mMouseMask) + { + eventType = NSOtherMouseDragged; + } + else + { + eventType = NSMouseMoved; + } + + eventFlags = process_modifier_flags(state); + // if pointer is grabbed use grab window instead + xWin = (grabWindow == 0) + ? xEvent.xmotion.window : grabWindow; + if (cWin == 0 || xWin != cWin->ident) + cWin = [XGServer _windowForXWindow: xWin]; + if (cWin == 0) + break; + + deltaX = - eventLocation.x; + deltaY = - eventLocation.y; + eventLocation = NSMakePoint(xEvent.xmotion.x, + NSHeight(cWin->xframe) +- xEvent.xmotion.y); + deltaX += eventLocation.x; + deltaY += eventLocation.y; + + e = [NSEvent mouseEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval)generic.lastTime + windowNumber: cWin->number + context: gcontext + eventNumber: xEvent.xbutton.serial + clickCount: clickCount + pressure: 1.0 + buttonNumber: 0 /* FIXME */ + deltaX: deltaX + deltaY: deltaY + deltaZ: 0]; + break; + } + + // a window property has changed or been deleted + case PropertyNotify: + NSDebugLLog(@"NSEvent", @"%d PropertyNotify - '%s'\n", + xEvent.xproperty.window, + XGetAtomName(XDPY, xEvent.xproperty.atom)); + break; + + // a client successfully reparents a window + case ReparentNotify: + NSDebugLLog(@"NSEvent", @"%d ReparentNotify - offset %d %d\n", + xEvent.xreparent.window, xEvent.xreparent.x, + xEvent.xreparent.y); + if (cWin == 0 || xEvent.xreparent.window != cWin->ident) + cWin=[XGServer _windowForXWindow:xEvent.xreparent.window]; + if (cWin != 0) + { + Window parent = xEvent.xreparent.parent; + Window new_parent = parent; + + /* Get the WM offset info which we hope is the same + for all parented windows */ + if (parent != cWin->root + && (xEvent.xreparent.x || xEvent.xreparent.y)) + { + generic.parent_offset.x = xEvent.xreparent.x; + generic.parent_offset.y = xEvent.xreparent.y; + /* FIXME: if this has changed, go through window + list and fix up hints */ + } + + // Some window manager e.g. KDE2 put in multiple windows, + // so we have to find the right parent, closest to root + /* FIXME: This section of code has caused problems with + certain users. An X error occurs in XQueryTree and + later a seg fault in XFree. It's 'commented' out for + now unless you set the default 'GSDoubleParentWindows' + */ + if (generic.flags.doubleParentWindow) { + while (new_parent && (new_parent != cWin->root)) { + Window root; + Window *children; + int nchildren; + + parent = new_parent; + NSLog(@"QueryTree window is %d (root %d cwin root %d)", + parent, root, cWin->root); + if (!XQueryTree(XDPY, parent, &root, &new_parent, + &children, &nchildren)) + { + new_parent = None; + if (children) + { + NSLog(@"Bad pointer from failed X call?"); + children = 0; + } + } + if (children) + { + XFree(children); + } + if (new_parent && new_parent != cWin->root) + { + XWindowAttributes wattr; + XGetWindowAttributes(XDPY, parent, &wattr); + if (wattr.x || wattr.y) + { + generic.parent_offset.x = wattr.x; + generic.parent_offset.y = wattr.y; + } + } + } /* while */ + } /* generic.flags.doubleParentWindow */ + cWin->parent = parent; + } + break; + + // another client attempts to change the size of a window + case ResizeRequest: + NSDebugLLog(@"NSEvent", @"%d ResizeRequest\n", + xEvent.xresizerequest.window); + break; + + // events dealing with the selection + case SelectionClear: + NSDebugLLog(@"NSEvent", @"%d SelectionClear\n", + xEvent.xselectionclear.window); + break; + + case SelectionNotify: + NSDebugLLog(@"NSEvent", @"%d SelectionNotify\n", + xEvent.xselection.requestor); + break; + + case SelectionRequest: + NSDebugLLog(@"NSEvent", @"%d SelectionRequest\n", + xEvent.xselectionrequest.requestor); + break; + + // We shouldn't get here unless we forgot to trap an event above + default: + NSLog(@"Received an untrapped event\n"); + break; + } + if (e) + [event_queue addObject: e]; + e = nil; + } +} + +// Return the key_code corresponding to the user defaults string +// Return 1 (which is an invalid keycode) if the user default +// is not set +static KeyCode +default_key_code (Display *display, NSUserDefaults *defaults, + NSString *aString) +{ + NSString *keySymString; + KeySym a_key_sym; + + keySymString = [defaults stringForKey: aString]; + if (keySymString == nil) + return 1; + + a_key_sym = XStringToKeysym ([keySymString cString]); + if (a_key_sym == NoSymbol) + { + // This is not necessarily an error. + // If you want on purpose to disable a key, + // set its default to 'NoSymbol'. + NSLog (@"KeySym %@ not found; disabling %@", keySymString, aString); + return 0; + } + + return XKeysymToKeycode (display, a_key_sym); +} + +// This function should be called before any keyboard event is dealed with. +static void +initialize_keyboard (void) +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + Display *display = [XGServer currentXDisplay]; + + // Initialize Control + _control_keycodes[0] = default_key_code (display, defaults, + @"GSFirstControlKey"); + if (_control_keycodes[0] == 1) // No User Default Set + _control_keycodes[0] = XKeysymToKeycode (display, XK_Control_L); + + _control_keycodes[1] = default_key_code (display, defaults, + @"GSSecondControlKey"); + if (_control_keycodes[1] == 1) + _control_keycodes[1] = XKeysymToKeycode (display, XK_Control_R); + + // Initialize Command + _command_keycodes[0] = default_key_code (display, defaults, + @"GSFirstCommandKey"); + if (_command_keycodes[0] == 1) + _command_keycodes[0] = XKeysymToKeycode (display, XK_Alt_L); + + _command_keycodes[1] = default_key_code (display, defaults, + @"GSSecondCommandKey"); + if (_command_keycodes[1] == 1) + _command_keycodes[1] = 0; + + // Initialize Alt + _alt_keycodes[0] = default_key_code (display, defaults, + @"GSFirstAlternateKey"); + if (_alt_keycodes[0] == 1) + { + _alt_keycodes[0] = XKeysymToKeycode (display, XK_Alt_R); + if (_alt_keycodes[0] == 0) + _alt_keycodes[0] = XKeysymToKeycode (display, XK_Mode_switch); + } + _alt_keycodes[1] = default_key_code (display, defaults, + @"GSSecondAlternateKey"); + if (_alt_keycodes[1] == 1) + _alt_keycodes[1] = 0; + + set_up_num_lock (); + + _is_keyboard_initialized = YES; +} + + +static void +set_up_num_lock (void) +{ + XModifierKeymap *modifier_map; + int i, j; + unsigned int modifier_masks[8] = + { + ShiftMask, LockMask, ControlMask, Mod1Mask, + Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask + }; + Display *display = [XGServer currentXDisplay]; + KeyCode _num_lock_keycode; + + // Get NumLock keycode + _num_lock_keycode = XKeysymToKeycode (display, XK_Num_Lock); + if (_num_lock_keycode == 0) + { + // Weird. There is no NumLock in this keyboard. + _num_lock_mask = 0; + return; + } + + // Get the current modifier mapping + modifier_map = XGetModifierMapping (display); + + // Scan the modifiers for NumLock + for (j = 0; j < 8; j++) + for (i = 0; i < (modifier_map->max_keypermod); i++) + { + if ((modifier_map->modifiermap)[i + j*modifier_map->max_keypermod] + == _num_lock_keycode) + { + _num_lock_mask = modifier_masks[j]; + XFreeModifiermap (modifier_map); + return; + } + } + // Weird. NumLock is not among the modifiers + _num_lock_mask = 0; + XFreeModifiermap (modifier_map); + return; +} + +static BOOL +keysym_is_X_modifier (KeySym keysym) +{ + switch (keysym) + { + case XK_Num_Lock: + case XK_Shift_L: + case XK_Shift_R: + case XK_Caps_Lock: + case XK_Shift_Lock: + return YES; + + default: + return NO; + } +} + +static NSEvent* +process_key_event (XEvent* xEvent, XGServer* context, NSEventType eventType) +{ + NSString *keys, *ukeys; + KeySym keysym; + NSPoint eventLocation; + unsigned short keyCode; + unsigned int eventFlags; + unichar unicode; + NSEvent *event = nil; + NSEventType originalType; + gswindow_device_t *window; + int control_key = 0; + int command_key = 0; + int alt_key = 0; + + if (_is_keyboard_initialized == NO) + initialize_keyboard (); + + /* Process NSFlagsChanged events. We can't use a switch because we + are not comparing to constants. Make sure keyCode is not 0 since + XIM events can potentially return 0 keyCodes. */ + keyCode = ((XKeyEvent *)xEvent)->keycode; + if (keyCode) + { + if (keyCode == _control_keycodes[0]) + { + control_key = 1; + } + else if (keyCode == _control_keycodes[1]) + { + control_key = 2; + } + else if (keyCode == _command_keycodes[0]) + { + command_key = 1; + } + else if (keyCode == _command_keycodes[1]) + { + command_key = 2; + } + else if (keyCode == _alt_keycodes[0]) + { + alt_key = 1; + } + else if (keyCode == _alt_keycodes[1]) + { + alt_key = 2; + } + } + + originalType = eventType; + if (control_key || command_key || alt_key) + { + eventType = NSFlagsChanged; + if (xEvent->xkey.type == KeyPress) + { + if (control_key) + _control_pressed |= control_key; + if (command_key) + _command_pressed |= command_key; + if (alt_key) + _alt_pressed |= alt_key; + } + else if (xEvent->xkey.type == KeyRelease) + { + if (control_key) + _control_pressed &= ~control_key; + if (command_key) + _command_pressed &= ~command_key; + if (alt_key) + _alt_pressed &= ~alt_key; + } + } + + /* Process modifiers */ + eventFlags = process_modifier_flags (xEvent->xkey.state); + + /* Process location */ + window = [XGServer _windowWithTag: [[NSApp keyWindow] windowNumber]]; + eventLocation.x = xEvent->xbutton.x; + if (window) + { + eventLocation.y = window->siz_hints.height - xEvent->xbutton.y; + } + else + { + eventLocation.y = xEvent->xbutton.y; + } + + /* Process characters */ + keys = [context->inputServer lookupStringForEvent: (XKeyEvent *)xEvent + window: window + keysym: &keysym]; + + /* Process keycode */ + //ximKeyCode = XKeysymToKeycode([XGServer currentXDisplay],keysym); + + /* Add NSNumericPadKeyMask if the key is in the KeyPad */ + if (IsKeypadKey (keysym)) + eventFlags = eventFlags | NSNumericPadKeyMask; + + NSDebugLLog (@"NSKeyEvent", @"keysym=%d, keyCode=%d flags=%d (state=%d)", + keysym, keyCode, eventFlags, ((XKeyEvent *)xEvent)->state); + + /* Add NSFunctionKeyMask if the key is a function or a misc function key */ + /* We prefer not to do this and do it manually in process_char + because X's idea of what is a function key seems to be different + from OPENSTEP's one */ + /* if (IsFunctionKey (keysym) || IsMiscFunctionKey (keysym)) + eventFlags = eventFlags | NSFunctionKeyMask; */ + + /* First, check to see if the key event if a Shift, NumLock or + CapsLock or ShiftLock keypress/keyrelease. If it is, then use a + NSFlagsChanged event type. This will generate a NSFlagsChanged + event each time you press/release a shift key, even if the flags + haven't actually changed. I don't see this as a problem - if we + didn't, the shift keypress/keyrelease event would never be + notified to the application. + + NB - to know if shift was pressed, we need to check the X keysym + - it doesn't work to compare the X modifier flags of this + keypress X event with the ones of the previous one, because when + you press Shift, the X shift keypress event has the *same* X + modifiers flags as the X keypress event before it - only + keypresses coming *after* the shift keypress will get a different + X modifier mask. */ + if (keysym_is_X_modifier (keysym)) + { + eventType = NSFlagsChanged; + } + + /* Now we get the unicode character for the pressed key using + our internal table */ + unicode = process_char (keysym, &eventFlags); + + /* If that didn't work, we use what X gave us */ + if (unicode != 0) + { + keys = [NSString stringWithCharacters: &unicode length: 1]; + } + + // Now the same ignoring modifiers, except Shift, ShiftLock, NumLock. + xEvent->xkey.state = (xEvent->xkey.state & (ShiftMask | LockMask + | _num_lock_mask)); + ukeys = [context->inputServer lookupStringForEvent: (XKeyEvent *)xEvent + window: window + keysym: &keysym]; + unicode = process_char (keysym, &eventFlags); + if (unicode != 0) + { + ukeys = [NSString stringWithCharacters: &unicode length: 1]; + } + + event = [NSEvent keyEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval)xEvent->xkey.time + windowNumber: window->number + context: GSCurrentContext() + characters: keys + charactersIgnoringModifiers: ukeys + isARepeat: NO /* isARepeat can't be supported with X */ + keyCode: keyCode]; + + return event; +} + +static unichar +process_char (KeySym keysym, unsigned *eventModifierFlags) +{ + switch (keysym) + { + /* NB: Whatever is explicitly put in this conversion table takes + precedence over what is returned by XLookupString. Not sure + this is a good idea for latin-1 character input. */ + case XK_Return: return NSCarriageReturnCharacter; + case XK_KP_Enter: return NSEnterCharacter; + case XK_Linefeed: return NSFormFeedCharacter; + case XK_Tab: return NSTabCharacter; +#ifdef XK_XKB_KEYS + case XK_ISO_Left_Tab: return NSTabCharacter; +#endif + /* FIXME: The following line ? */ + case XK_Escape: return 0x1b; + case XK_BackSpace: return NSBackspaceKey; + + /* The following keys need to be reported as function keys */ +#define XGPS_FUNCTIONKEY \ +*eventModifierFlags = *eventModifierFlags | NSFunctionKeyMask; + + case XK_F1: XGPS_FUNCTIONKEY return NSF1FunctionKey; + case XK_F2: XGPS_FUNCTIONKEY return NSF2FunctionKey; + case XK_F3: XGPS_FUNCTIONKEY return NSF3FunctionKey; + case XK_F4: XGPS_FUNCTIONKEY return NSF4FunctionKey; + case XK_F5: XGPS_FUNCTIONKEY return NSF5FunctionKey; + case XK_F6: XGPS_FUNCTIONKEY return NSF6FunctionKey; + case XK_F7: XGPS_FUNCTIONKEY return NSF7FunctionKey; + case XK_F8: XGPS_FUNCTIONKEY return NSF8FunctionKey; + case XK_F9: XGPS_FUNCTIONKEY return NSF9FunctionKey; + case XK_F10: XGPS_FUNCTIONKEY return NSF10FunctionKey; + case XK_F11: XGPS_FUNCTIONKEY return NSF11FunctionKey; + case XK_F12: XGPS_FUNCTIONKEY return NSF12FunctionKey; + case XK_F13: XGPS_FUNCTIONKEY return NSF13FunctionKey; + case XK_F14: XGPS_FUNCTIONKEY return NSF14FunctionKey; + case XK_F15: XGPS_FUNCTIONKEY return NSF15FunctionKey; + case XK_F16: XGPS_FUNCTIONKEY return NSF16FunctionKey; + case XK_F17: XGPS_FUNCTIONKEY return NSF17FunctionKey; + case XK_F18: XGPS_FUNCTIONKEY return NSF18FunctionKey; + case XK_F19: XGPS_FUNCTIONKEY return NSF19FunctionKey; + case XK_F20: XGPS_FUNCTIONKEY return NSF20FunctionKey; + case XK_F21: XGPS_FUNCTIONKEY return NSF21FunctionKey; + case XK_F22: XGPS_FUNCTIONKEY return NSF22FunctionKey; + case XK_F23: XGPS_FUNCTIONKEY return NSF23FunctionKey; + case XK_F24: XGPS_FUNCTIONKEY return NSF24FunctionKey; + case XK_F25: XGPS_FUNCTIONKEY return NSF25FunctionKey; + case XK_F26: XGPS_FUNCTIONKEY return NSF26FunctionKey; + case XK_F27: XGPS_FUNCTIONKEY return NSF27FunctionKey; + case XK_F28: XGPS_FUNCTIONKEY return NSF28FunctionKey; + case XK_F29: XGPS_FUNCTIONKEY return NSF29FunctionKey; + case XK_F30: XGPS_FUNCTIONKEY return NSF30FunctionKey; + case XK_F31: XGPS_FUNCTIONKEY return NSF31FunctionKey; + case XK_F32: XGPS_FUNCTIONKEY return NSF32FunctionKey; + case XK_F33: XGPS_FUNCTIONKEY return NSF33FunctionKey; + case XK_F34: XGPS_FUNCTIONKEY return NSF34FunctionKey; + case XK_F35: XGPS_FUNCTIONKEY return NSF35FunctionKey; + case XK_Delete: XGPS_FUNCTIONKEY return NSDeleteFunctionKey; + case XK_Home: XGPS_FUNCTIONKEY return NSHomeFunctionKey; + case XK_Left: XGPS_FUNCTIONKEY return NSLeftArrowFunctionKey; + case XK_Right: XGPS_FUNCTIONKEY return NSRightArrowFunctionKey; + case XK_Up: XGPS_FUNCTIONKEY return NSUpArrowFunctionKey; + case XK_Down: XGPS_FUNCTIONKEY return NSDownArrowFunctionKey; +// case XK_Prior: XGPS_FUNCTIONKEY return NSPrevFunctionKey; +// case XK_Next: XGPS_FUNCTIONKEY return NSNextFunctionKey; + case XK_End: XGPS_FUNCTIONKEY return NSEndFunctionKey; + case XK_Begin: XGPS_FUNCTIONKEY return NSBeginFunctionKey; + case XK_Select: XGPS_FUNCTIONKEY return NSSelectFunctionKey; + case XK_Print: XGPS_FUNCTIONKEY return NSPrintFunctionKey; + case XK_Execute: XGPS_FUNCTIONKEY return NSExecuteFunctionKey; + case XK_Insert: XGPS_FUNCTIONKEY return NSInsertFunctionKey; + case XK_Undo: XGPS_FUNCTIONKEY return NSUndoFunctionKey; + case XK_Redo: XGPS_FUNCTIONKEY return NSRedoFunctionKey; + case XK_Menu: XGPS_FUNCTIONKEY return NSMenuFunctionKey; + case XK_Find: XGPS_FUNCTIONKEY return NSFindFunctionKey; + case XK_Help: XGPS_FUNCTIONKEY return NSHelpFunctionKey; + case XK_Break: XGPS_FUNCTIONKEY return NSBreakFunctionKey; + case XK_Mode_switch: XGPS_FUNCTIONKEY return NSModeSwitchFunctionKey; + case XK_Scroll_Lock: XGPS_FUNCTIONKEY return NSScrollLockFunctionKey; + case XK_Pause: XGPS_FUNCTIONKEY return NSPauseFunctionKey; + case XK_Clear: XGPS_FUNCTIONKEY return NSClearDisplayFunctionKey; +#ifndef NeXT + case XK_Page_Up: XGPS_FUNCTIONKEY return NSPageUpFunctionKey; + case XK_Page_Down: XGPS_FUNCTIONKEY return NSPageDownFunctionKey; + case XK_Sys_Req: XGPS_FUNCTIONKEY return NSSysReqFunctionKey; +#endif + case XK_KP_F1: XGPS_FUNCTIONKEY return NSF1FunctionKey; + case XK_KP_F2: XGPS_FUNCTIONKEY return NSF2FunctionKey; + case XK_KP_F3: XGPS_FUNCTIONKEY return NSF3FunctionKey; + case XK_KP_F4: XGPS_FUNCTIONKEY return NSF4FunctionKey; +#ifndef NeXT + case XK_KP_Home: XGPS_FUNCTIONKEY return NSHomeFunctionKey; + case XK_KP_Left: XGPS_FUNCTIONKEY return NSLeftArrowFunctionKey; + case XK_KP_Up: XGPS_FUNCTIONKEY return NSUpArrowFunctionKey; + case XK_KP_Right: XGPS_FUNCTIONKEY return NSRightArrowFunctionKey; + case XK_KP_Down: XGPS_FUNCTIONKEY return NSDownArrowFunctionKey; +// case XK_KP_Prior: return NSPrevFunctionKey; + case XK_KP_Page_Up: XGPS_FUNCTIONKEY return NSPageUpFunctionKey; +// case XK_KP_Next: return NSNextFunctionKey; + case XK_KP_Page_Down: XGPS_FUNCTIONKEY return NSPageDownFunctionKey; + case XK_KP_End: XGPS_FUNCTIONKEY return NSEndFunctionKey; + case XK_KP_Begin: XGPS_FUNCTIONKEY return NSBeginFunctionKey; + case XK_KP_Insert: XGPS_FUNCTIONKEY return NSInsertFunctionKey; + case XK_KP_Delete: XGPS_FUNCTIONKEY return NSDeleteFunctionKey; +#endif +#undef XGPS_FUNCTIONKEY + default: return 0; + } +} + +// process_modifier_flags() determines which modifier keys (Command, Control, +// Shift, and so forth) were held down while the event occured. +static unsigned int +process_modifier_flags(unsigned int state) +{ + unsigned int eventModifierFlags = 0; + + if (state & ShiftMask) + eventModifierFlags = eventModifierFlags | NSShiftKeyMask; + + if (state & LockMask) + eventModifierFlags = eventModifierFlags | NSShiftKeyMask; + + if (_control_pressed != 0) + eventModifierFlags = eventModifierFlags | NSControlKeyMask; + + if (_command_pressed != 0) + eventModifierFlags = eventModifierFlags | NSCommandKeyMask; + + if (_alt_pressed != 0) + eventModifierFlags = eventModifierFlags | NSAlternateKeyMask; + + // Other modifiers ignored for now. + + return eventModifierFlags; +} + +- (NSDate*) timedOutEvent: (void*)data + type: (RunLoopEventType)type + forMode: (NSString*)mode +{ + return nil; +} + +/* Drag and Drop */ +- (id )dragInfo +{ + return [XGDragView sharedDragView]; +} + +@end + +@implementation XGServer (XSync) +- (BOOL) xSyncMap: (void*)windowHandle +{ + gswindow_device_t *window = (gswindow_device_t*)windowHandle; + + /* + * if the window is not mapped, make sure we have sent all requests to the + * X-server, it may be that our mapping request was buffered. + */ + if (window->map_state != IsViewable) + { + XSync(XDPY, False); + [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; + } + /* + * If the window is still not mapped, it may be that the window-manager + * intercepted our mapping request, and hasn't dealt with it yet. + * Listen for input for up to a second, in the hope of getting the mapping. + */ + if (window->map_state != IsViewable) + { + NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 1.0]; + NSRunLoop *l = [NSRunLoop currentRunLoop]; + NSString *m = [l currentMode]; + + while (window->map_state != IsViewable && [d timeIntervalSinceNow] > 0) + { + [l runMode: m beforeDate: d]; + } + } + if (window->map_state != IsViewable) + { + NSLog(@"Window still not mapped a second after mapping request made"); + return NO; + } + return YES; +} +@end + +@implementation XGServer (X11Ops) + +/* + * Return mouse location in base coords ignoring the event loop + */ +- (NSPoint) mouselocation +{ + Window rootWin; + Window childWin; + int currentX; + int currentY; + int winX; + int winY; + unsigned mask; + BOOL ok; + NSPoint p; + + ok = XQueryPointer (XDPY, [self xDisplayRootWindow], + &rootWin, &childWin, ¤tX, ¤tY, &winX, &winY, &mask); + p = NSMakePoint(0,0); + if (ok) + { + p = NSMakePoint(currentX, DisplayHeight(XDPY, XSCR) - currentY); + } + return p; +} + +- (NSEvent*) getEventMatchingMask: (unsigned)mask + beforeDate: (NSDate*)limit + inMode: (NSString*)mode + dequeue: (BOOL)flag +{ + [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; + return [super getEventMatchingMask: mask + beforeDate: limit + inMode: mode + dequeue: flag]; +} + +- (void) discardEventsMatchingMask: (unsigned)mask + beforeEvent: (NSEvent*)limit +{ + [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; + [super discardEventsMatchingMask: mask + beforeEvent: limit]; +} + +@end + + diff --git a/Source/x11/XGServerWindow.m b/Source/x11/XGServerWindow.m new file mode 100644 index 0000000..32e2d03 --- /dev/null +++ b/Source/x11/XGServerWindow.m @@ -0,0 +1,2612 @@ +/* XGServerWindows - methods for window/screen handling + + Copyright (C) 1999 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1999 + + This file is part of GNUstep + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_WRASTER_H +#include "wraster.h" +#else +#include "x11/wraster.h" +#endif +#include + +#include "x11/XGDragView.h" +#include "x11/XGInputServer.h" + +#define MAX_SCREENS 100 +#define XDPY (((RContext *)context)->dpy) +#define XDRW (((RContext *)context)->drawable) +#define XSCR (((RContext *)context)->screen_number) + +#define ROOT generic.appRootWindow + +/* + * Name for application root window. + */ +static char *rootName = 0; + +#define WINDOW_WITH_TAG(windowNumber) (gswindow_device_t *)NSMapGet(windowtags, (void *)windowNumber) + +/* Current mouse grab window */ +static gswindow_device_t *grab_window = NULL; + +/* Keep track of windows */ +static NSMapTable *windowmaps = NULL; +static NSMapTable *windowtags = NULL; + +@interface NSCursor (BackendPrivate) +- (void *)_cid; +@end + +void __objc_xgcontextwindow_linking (void) +{ +} + +/* + * The next two functions derived from WindowMaker by Alfredo K. Kojima + */ +static unsigned char* +PropGetCheckProperty(Display *dpy, Window window, Atom hint, Atom type, + int format, int count, int *retCount) +{ + Atom type_ret; + int fmt_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + unsigned char *data; + int tmp; + + if (count <= 0) + tmp = 0xffffff; + else + tmp = count; + + if (XGetWindowProperty(dpy, window, hint, 0, tmp, False, type, + &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret, + (unsigned char **)&data)!=Success || !data) + return NULL; + + if ((type!=AnyPropertyType && type!=type_ret) + || (count > 0 && nitems_ret != count) + || (format != 0 && format != fmt_ret)) + { + XFree(data); + return NULL; + } + + if (retCount) + *retCount = nitems_ret; + + return data; +} + +static void +setNormalHints(Display *d, gswindow_device_t *w) +{ + if (w->siz_hints.flags & (USPosition | PPosition)) + NSDebugLLog(@"XGTrace", @"Hint posn %d: %d, %d", + w->number, w->siz_hints.x, w->siz_hints.y); + if (w->siz_hints.flags & (USSize | PSize)) + NSDebugLLog(@"XGTrace", @"Hint size %d: %d, %d", + w->number, w->siz_hints.width, w->siz_hints.height); + if (w->siz_hints.flags & PMinSize) + NSDebugLLog(@"XGTrace", @"Hint mins %d: %d, %d", + w->number, w->siz_hints.min_width, w->siz_hints.min_height); + if (w->siz_hints.flags & PMaxSize) + NSDebugLLog(@"XGTrace", @"Hint maxs %d: %d, %d", + w->number, w->siz_hints.max_width, w->siz_hints.max_height); + if (w->siz_hints.flags & PResizeInc) + NSDebugLLog(@"XGTrace", @"Hint incr %d: %d, %d", + w->number, w->siz_hints.width_inc, w->siz_hints.height_inc); + XSetNormalHints(d, w->ident, &w->siz_hints); +} + +/* + * Setting Motif Hints for Window Managers (Nicola Pero, July 2000) + */ + +/* + * Motif window hints to communicate to a window manager + * that we want a window to have a titlebar/resize button/etc. + */ + +/* Motif window hints struct */ +typedef struct { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; +} MwmHints; + +/* Number of entries in the struct */ +#define PROP_MWM_HINTS_ELEMENTS 5 + +/* Now for each field in the struct, meaningful stuff to put in: */ + +/* flags */ +#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_DECORATIONS (1L << 1) +#define MWM_HINTS_INPUT_MODE (1L << 2) +#define MWM_HINTS_STATUS (1L << 3) + +/* functions */ +#define MWM_FUNC_ALL (1L << 0) +#define MWM_FUNC_RESIZE (1L << 1) +#define MWM_FUNC_MOVE (1L << 2) +#define MWM_FUNC_MINIMIZE (1L << 3) +#define MWM_FUNC_MAXIMIZE (1L << 4) +#define MWM_FUNC_CLOSE (1L << 5) + +/* decorations */ +#define MWM_DECOR_ALL (1L << 0) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) + +/* We don't use the input_mode and status fields */ + +/* The atom */ +#define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS" + +/* Now the code */ + +/* Set the style `styleMask' for the XWindow `window' using motif + * window hints. This makes an X call, please make sure you do it + * only once. + */ +static void setWindowHintsForStyle (Display *dpy, Window window, + unsigned int styleMask) +{ + MwmHints *hints; + BOOL needToFreeHints = YES; + Atom type_ret; + int format_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + static Atom mwhints_atom = None; + + /* Initialize the atom if needed */ + if (mwhints_atom == None) + mwhints_atom = XInternAtom (dpy,_XA_MOTIF_WM_HINTS, False); + + /* Get the already-set window hints */ + XGetWindowProperty (dpy, window, mwhints_atom, 0, + sizeof (MwmHints) / sizeof (long), + False, AnyPropertyType, &type_ret, &format_ret, + &nitems_ret, &bytes_after_ret, + (unsigned char **)&hints); + + /* If no window hints were set, create new hints to 0 */ + if (type_ret == None) + { + needToFreeHints = NO; + hints = alloca (sizeof (MwmHints)); + memset (hints, 0, sizeof (MwmHints)); + } + + /* Remove the hints we want to change */ + hints->flags &= ~MWM_HINTS_DECORATIONS; + hints->flags &= ~MWM_HINTS_FUNCTIONS; + hints->decorations = 0; + hints->functions = 0; + + /* Now add to the hints from the styleMask */ + if (styleMask == NSBorderlessWindowMask) + { + hints->flags |= MWM_HINTS_DECORATIONS; + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->decorations = 0; + hints->functions = 0; + } + else + { + /* These need to be on all windows except mini and icon windows, + where they are specifically set to 0 (see below) */ + hints->flags |= MWM_HINTS_DECORATIONS; + hints->decorations |= (MWM_DECOR_TITLE | MWM_DECOR_BORDER); + if (styleMask & NSTitledWindowMask) + { + // Without this, iceWM does not let you move the window! + // [idem below] + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->functions |= MWM_FUNC_MOVE; + } + if (styleMask & NSClosableWindowMask) + { + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->functions |= MWM_FUNC_CLOSE; + hints->functions |= MWM_FUNC_MOVE; + } + if (styleMask & NSMiniaturizableWindowMask) + { + hints->flags |= MWM_HINTS_DECORATIONS; + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->decorations |= MWM_DECOR_MINIMIZE; + hints->functions |= MWM_FUNC_MINIMIZE; + hints->functions |= MWM_FUNC_MOVE; + } + if (styleMask & NSResizableWindowMask) + { + hints->flags |= MWM_HINTS_DECORATIONS; + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->decorations |= MWM_DECOR_RESIZEH; + hints->decorations |= MWM_DECOR_MAXIMIZE; + hints->functions |= MWM_FUNC_RESIZE; + hints->functions |= MWM_FUNC_MAXIMIZE; + hints->functions |= MWM_FUNC_MOVE; + } + if (styleMask & NSIconWindowMask) + { + // FIXME + hints->flags |= MWM_HINTS_DECORATIONS; + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->decorations = 0; + hints->functions = 0; + } + if (styleMask & NSMiniWindowMask) + { + // FIXME + hints->flags |= MWM_HINTS_DECORATIONS; + hints->flags |= MWM_HINTS_FUNCTIONS; + hints->decorations = 0; + hints->functions = 0; + } + } + + /* Set the hints */ + XChangeProperty (dpy, window, mwhints_atom, mwhints_atom, 32, + PropModeReplace, (unsigned char *)hints, + sizeof (MwmHints) / sizeof (long)); + + /* Free the hints if allocated by the X server for us */ + if (needToFreeHints == YES) + XFree (hints); +} + +/* + * End of motif hints for window manager code + */ + +@interface NSEvent (WindowHack) +- (void) _patchLocation: (NSPoint)loc; +@end + +@implementation NSEvent (WindowHack) +- (void) _patchLocation: (NSPoint)loc +{ + location_point = loc; +} +@end + +@implementation XGServer (DPSWindow) + +/* + * Where a window has been reparented by the wm, we use this method to + * locate the window given knowledge of its border window. + */ ++ (gswindow_device_t *) _windowForXParent: (Window)xWindow +{ + NSMapEnumerator enumerator; + Window x; + gswindow_device_t *d; + + enumerator = NSEnumerateMapTable(windowmaps); + while (NSNextMapEnumeratorPair(&enumerator, (void**)&x, (void**)&d) == YES) + { + if (d->root != d->parent && d->parent == xWindow) + { + return d; + } + } + return 0; +} + ++ (gswindow_device_t *) _windowForXWindow: (Window)xWindow +{ + return NSMapGet(windowmaps, (void *)xWindow); +} + ++ (gswindow_device_t *) _windowWithTag: (int)windowNumber +{ + return WINDOW_WITH_TAG(windowNumber); +} + +/* + * Convert a window frame in OpenStep absolute screen coordinates to + * a frame in X absolute screen coordinates by flipping an applying + * offsets to allow for the X window decorations. + */ +- (NSRect) _OSFrameToXFrame: (NSRect)o for: (void*)window +{ + gswindow_device_t *win = (gswindow_device_t*)window; + NSRect x; + float t, b, l, r; + + [self styleoffsets: &l : &r : &t : &b : win->win_attrs.window_style]; + + x.size.width = o.size.width - l - r; + x.size.height = o.size.height - t - b; + x.origin.x = o.origin.x + l; + x.origin.y = o.origin.y + o.size.height - t; + x.origin.y = DisplayHeight(XDPY, win->screen) - x.origin.y; +NSDebugLLog(@"Frame", @"O2X %d, %@, %@", win->number, + NSStringFromRect(o), NSStringFromRect(x)); + return x; +} + +/* + * Convert a window frame in OpenStep absolute screen coordinates to + * a frame suitable for setting X hints for a window manager. + */ +- (NSRect) _OSFrameToXHints: (NSRect)o for: (void*)window +{ + gswindow_device_t *win = (gswindow_device_t*)window; + NSRect x; + float t, b, l, r; + + [self styleoffsets: &l : &r : &t : &b : win->win_attrs.window_style]; + + x.size.width = o.size.width - l - r; + x.size.height = o.size.height - t - b; + x.origin.x = o.origin.x; + x.origin.y = o.origin.y + o.size.height; + x.origin.y = DisplayHeight(XDPY, win->screen) - x.origin.y; +NSDebugLLog(@"Frame", @"O2H %d, %@, %@", win->number, + NSStringFromRect(o), NSStringFromRect(x)); + return x; +} + +/* + * Convert a window frame in X absolute screen coordinates to a frame + * in OpenStep absolute screen coordinates by flipping an applying + * offsets to allow for the X window decorations. + */ +- (NSRect) _XFrameToOSFrame: (NSRect)x for: (void*)window +{ + gswindow_device_t *win = (gswindow_device_t*)window; + NSRect o; + float t, b, l, r; + + [self styleoffsets: &l : &r : &t : &b : win->win_attrs.window_style]; + o.size.width = x.size.width + l + r; + o.size.height = x.size.height + t + b; + o.origin.x = x.origin.x - l; + o.origin.y = DisplayHeight(XDPY, win->screen) - x.origin.y; + o.origin.y = o.origin.y - o.size.height + t; +NSDebugLLog(@"Frame", @"X2O %d, %@, %@", win->number, + NSStringFromRect(x), NSStringFromRect(o)); + return o; +} + +- (XGWMProtocols) _checkWindowManager +{ + int wmflags; + Window root; + Window *win; + Atom *data; + Atom atom; + int count; + + root = DefaultRootWindow(XDPY); + wmflags = XGWM_UNKNOWN; + + /* Check for WindowMaker */ + atom = XInternAtom(XDPY, "_WINDOWMAKER_WM_PROTOCOLS", False); + data = (Atom*)PropGetCheckProperty(XDPY, root, atom, XA_ATOM, 32, -1, &count); + if (data != 0) + { + Atom noticeboard; + int i = 0; + + noticeboard = XInternAtom(XDPY, "_WINDOWMAKER_NOTICEBOARD", False); + while (i < count && data[i] != noticeboard) + { + i++; + } + XFree(data); + + if (i < count) + { + Window *win; + void *d; + + win = (Window*)PropGetCheckProperty(XDPY, root, + noticeboard, XA_WINDOW, 32, -1, &count); + + if (win != 0) + { + d = PropGetCheckProperty(XDPY, *win, noticeboard, + XA_WINDOW, 32, 1, NULL); + if (d != 0) + { + XFree(d); + wmflags |= XGWM_WINDOWMAKER; + } + } + } + else + { + wmflags |= XGWM_WINDOWMAKER; + } + } + + /* Now check for Gnome */ + atom = XInternAtom(XDPY, "_WIN_SUPPORTING_WM_CHECK", False); + win = (Window*)PropGetCheckProperty(XDPY, root, atom, + XA_CARDINAL, 32, -1, &count); + if (win != 0) + { + Window *win1; + + win1 = (Window*)PropGetCheckProperty(XDPY, *win, atom, + XA_CARDINAL, 32, -1, &count); + // If the two are not identical, the flag on the root window, was + // a left over from an old window manager. + if (*win1 == *win) + { + wmflags |= XGWM_GNOME; + + generic.wintypes.win_type_atom = + XInternAtom(XDPY, "_WIN_LAYER", False); + } + } + + /* Now check for NET (EWMH) compliant window manager */ + atom = XInternAtom(XDPY, "_NET_SUPPORTING_WM_CHECK", False); + win = (Window*)PropGetCheckProperty(XDPY, root, atom, + XA_WINDOW, 32, -1, &count); + + if (win != 0) + { + Window *win1; + + win1 = (Window*)PropGetCheckProperty(XDPY, *win, atom, + XA_WINDOW, 32, -1, &count); + // If the two are not identical, the flag on the root window, was + // a left over from an old window manager. + if (*win1 == *win) + { + wmflags |= XGWM_EWMH; + + // Store window type Atoms for this WM + generic.wintypes.win_type_atom = + XInternAtom(XDPY, "_NET_WM_WINDOW_TYPE", False); + generic.wintypes.win_desktop_atom = + XInternAtom(XDPY, "_NET_WM_WINDOW_TYPE_DESKTOP", False); + generic.wintypes.win_dock_atom = + XInternAtom(XDPY, "_NET_WM_WINDOW_TYPE_DOCK", False); + generic.wintypes.win_floating_atom = + XInternAtom(XDPY, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); + generic.wintypes.win_menu_atom = + XInternAtom(XDPY, "_NET_WM_WINDOW_TYPE_MENU", False); + generic.wintypes.win_modal_atom = + XInternAtom(XDPY, "_NET_WM_WINDOW_TYPE_DIALOG", False); + generic.wintypes.win_normal_atom = + XInternAtom(XDPY, "_NET_WM_WINDOW_TYPE_NORMAL", False); + } + } + + NSDebugLLog(@"WM", + @"WM Protocols: WindowMaker=(%s) GNOME=(%s) KDE=(%s) EWMH=(%s)", + (wmflags & XGWM_WINDOWMAKER) ? "YES" : "NO", + (wmflags & XGWM_GNOME) ? "YES" : "NO", + (wmflags & XGWM_KDE) ? "YES" : "NO", + (wmflags & XGWM_EWMH) ? "YES" : "NO"); + + return wmflags; +} + +- (gswindow_device_t *)_rootWindowForScreen: (int)screen +{ + int x, y, width, height; + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(screen); + if (window) + return window; + + window = objc_malloc(sizeof(gswindow_device_t)); + memset(window, '\0', sizeof(gswindow_device_t)); + + window->display = XDPY; + window->screen = screen; + window->ident = RootWindow(XDPY, screen); + window->root = window->ident; + window->type = NSBackingStoreNonretained; + window->number = screen; + window->map_state = IsViewable; + window->visibility = -1; + if (window->ident) + XGetGeometry(XDPY, window->ident, &window->root, + &x, &y, &width, &height, + &window->border, &window->depth); + + window->xframe = NSMakeRect(x, y, width, height); + NSMapInsert (windowtags, (void*)window->number, window); + NSMapInsert (windowmaps, (void*)window->ident, window); + return window; +} + +/* Create the window and screen list if necessary, add the root window to + the window list as window 0 */ +- (void) _checkWindowlist +{ + if (windowmaps) + return; + + windowmaps = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 20); + windowtags = NSCreateMapTable(NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 20); +} + +- (void) _setupMouse +{ + int numButtons; + unsigned char mouseNumbers[5]; + unsigned char buttons[5] = { + Button1, + Button2, + Button3, + Button4, + Button5 + }; + int masks[5] = { + Button1Mask, + Button2Mask, + Button3Mask, + Button4Mask, + Button5Mask + }; + /* + * Get pointer information - so we know which mouse buttons we have. + * With a two button + */ + numButtons = XGetPointerMapping(XDPY, mouseNumbers, 5); + if (numButtons > 5) + { + NSLog(@"Warning - mouse/pointer seems to have more than 5 buttons" + @" - just using one to five"); + numButtons = 5; + } + generic.lMouse = buttons[0]; + generic.lMouseMask = masks[0]; + if (numButtons >= 5) + { + generic.upMouse = buttons[3]; + generic.downMouse = buttons[4]; + generic.rMouse = buttons[2]; + generic.rMouseMask = masks[2]; + generic.mMouse = buttons[1]; + generic.mMouseMask = masks[1]; + } + else if (numButtons == 3) + { +// FIXME: Button4 and Button5 are ScrollWheel up and ScrollWheel down +// generic.rMouse = buttons[numButtons-1]; +// generic.rMouseMask = masks[numButtons-1]; + generic.upMouse = 0; + generic.downMouse = 0; + generic.rMouse = buttons[2]; + generic.rMouseMask = masks[2]; + generic.mMouse = buttons[1]; + generic.mMouseMask = masks[1]; + } + else if (numButtons == 2) + { + generic.upMouse = 0; + generic.downMouse = 0; + generic.rMouse = buttons[1]; + generic.rMouseMask = masks[1]; + generic.mMouse = 0; + generic.mMouseMask = 0; + } + else if (numButtons == 1) + { + generic.upMouse = 0; + generic.downMouse = 0; + generic.rMouse = 0; + generic.rMouseMask = 0; + generic.mMouse = 0; + generic.mMouseMask = 0; + } + else + { + NSLog(@"Warning - mouse/pointer seems to have NO buttons"); + } +} + +- (void) _setupRootWindow +{ + NSProcessInfo *pInfo = [NSProcessInfo processInfo]; + NSArray *args; + unsigned i; + int argc; + char **argv; + XClassHint classhint; + XTextProperty windowName; + NSUserDefaults *defs; + const char *host_name = [[pInfo hostName] cString]; + + /* + * Initialize time of last events to be the start of time - not + * the current time! + */ + if (CurrentTime == 0) + { + generic.lastClick = 1; + generic.lastMotion = 1; + generic.lastTime = 1; + } + + /* + * Set up standard atoms. + */ + generic.protocols_atom = XInternAtom(XDPY, "WM_PROTOCOLS", False); + generic.take_focus_atom = XInternAtom(XDPY, "WM_TAKE_FOCUS", False); + generic.delete_win_atom = XInternAtom(XDPY, "WM_DELETE_WINDOW", False); + generic.miniaturize_atom + = XInternAtom(XDPY, "_GNUSTEP_WM_MINIATURIZE_WINDOW", False); + generic.win_decor_atom = XInternAtom(XDPY,"_GNUSTEP_WM_ATTR", False); + generic.titlebar_state_atom + = XInternAtom(XDPY, "_GNUSTEP_TITLEBAR_STATE", False); + + [self _setupMouse]; + [self _checkWindowlist]; + + /* + * determine window manager in use. + */ + generic.wm = [self _checkWindowManager]; + + /* + * Now check user defaults. + */ + defs = [NSUserDefaults standardUserDefaults]; + generic.flags.useWindowMakerIcons = NO; + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + generic.flags.useWindowMakerIcons = YES; + if ([defs stringForKey: @"UseWindowMakerIcons"] != nil + && [defs boolForKey: @"UseWindowMakerIcons"] == NO) + { + generic.flags.useWindowMakerIcons = NO; + } + } + generic.flags.doubleParentWindow = NO; + if ([defs stringForKey: @"GSDoubleParentWindows"] != nil + && [defs boolForKey: @"GSDoubleParentWindows"] == YES) + { + generic.flags.doubleParentWindow = YES; + } + + + /* + * make app root window + */ + ROOT = XCreateSimpleWindow(XDPY,RootWindow(XDPY,XSCR),0,0,1,1,0,0,0); + + /* + * set hints for root window + */ + { + XWMHints gen_hints; + + gen_hints.flags = WindowGroupHint | StateHint; + gen_hints.initial_state = WithdrawnState; + gen_hints.window_group = ROOT; + XSetWMHints(XDPY, ROOT, &gen_hints); + } + + /* + * Mark this as a GNUstep app with the current application name. + */ + if (rootName == 0) + { + NSString *str; + str = [pInfo processName]; + i = [str cStringLength]; + rootName = objc_malloc(i+1); + [str getCString: rootName]; + } + classhint.res_name = rootName; + classhint.res_class = "GNUstep"; + XSetClassHint(XDPY, ROOT, &classhint); + + /* + * Set app name as root window title - probably unused unless + * the window manager wants to keep us in a menu or something like that. + */ + XStringListToTextProperty((char**)&classhint.res_name, 1, &windowName); + XSetWMName(XDPY, ROOT, &windowName); + XSetWMIconName(XDPY, ROOT, &windowName); + + /* + * Record the information used to start this app. + * If we have a user default set up (eg. by the openapp script) use it. + * otherwise use the process arguments. + */ + args = [defs arrayForKey: @"GSLaunchCommand"]; + if (args == nil) + { + args = [pInfo arguments]; + } + argc = [args count]; + argv = (char**)objc_malloc(argc*sizeof(char*)); + for (i = 0; i < argc; i++) + { + argv[i] = (char*)[[args objectAtIndex: i] cString]; + } + XSetCommand(XDPY, ROOT, argv, argc); + objc_free(argv); + + // Store the host name of the machine we a running on + XStringListToTextProperty((char**)&host_name, 1, &windowName); + XSetWMClientMachine(XDPY, ROOT, &windowName); + + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + GNUstepWMAttributes win_attrs; + + /* + * Tell WindowMaker not to set up an app icon for us - we'll make our own. + */ + win_attrs.flags = GSExtraFlagsAttr; + win_attrs.extra_flags = GSNoApplicationIconFlag; + XChangeProperty(XDPY, ROOT, + generic.win_decor_atom, generic.win_decor_atom, + 32, PropModeReplace, (unsigned char *)&win_attrs, + sizeof(GNUstepWMAttributes)/sizeof(CARD32)); + } + + if ((generic.wm & XGWM_EWMH) != 0) + { + // Store the id of our process + Atom pid_atom = XInternAtom(XDPY, "_NET_WM_PID", False); + int pid = [pInfo processIdentifier]; + + XChangeProperty(XDPY, ROOT, + pid_atom, XA_CARDINAL, + 32, PropModeReplace, + (unsigned char*)&pid, 1); + + // We should store the GNUStepMenuImage in the root window + // and use that as our title bar icon + // pid_atom = XInternAtom(XDPY, "_NET_WM_ICON", False); + } +} + +/* Destroys all the windows and other window resources that belong to + this context */ +- (void) _destroyServerWindows +{ + int num; + gswindow_device_t *d; + NSMapEnumerator enumerator; + NSMapTable *mapcopy; + + /* Have to get a copy, since termwindow will remove them from + the map table */ + mapcopy = NSCopyMapTableWithZone(windowtags, [self zone]); + enumerator = NSEnumerateMapTable(mapcopy); + while (NSNextMapEnumeratorPair(&enumerator, (void**)&num, (void**)&d) == YES) + { + if (d->display == XDPY && d->ident != d->root) + [self termwindow: num]; + } + NSFreeMapTable(mapcopy); +} + +/* Sets up a backing pixmap when a window is created or resized. This is + only done if the Window is buffered or retained. */ +- (void) _createBuffer: (gswindow_device_t *)window +{ + if (window->type == NSBackingStoreNonretained) + return; + + if (window->depth == 0) + window->depth = DefaultDepth(XDPY, XSCR); + if (NSWidth(window->xframe) == 0 && NSHeight(window->xframe) == 0) + { + NSDebugLLog(@"NSWindow", @"Cannot create buffer for ZeroRect frame"); + return; + } + + window->buffer = XCreatePixmap(XDPY, window->root, + NSWidth(window->xframe), + NSHeight(window->xframe), + window->depth); + + if (!window->buffer) + { + NSLog(@"DPS Windows: Unable to create backing store\n"); + return; + } + + XFillRectangle(XDPY, + window->buffer, + window->gc, + 0, 0, + NSWidth(window->xframe), + NSHeight(window->xframe)); + + /* Set background pixmap to avoid redundant fills */ + XSetWindowBackgroundPixmap(XDPY, window->ident, window->buffer); +} + +- (int) window: (NSRect)frame : (NSBackingStoreType)type +{ + static int last_win_num = 0; + gswindow_device_t *window; + gswindow_device_t *root; + XGCValues values; + unsigned long valuemask; + XClassHint classhint; + + NSDebugLLog(@"XGTrace", @"DPSwindow: %@ %d", NSStringFromRect(frame), type); + root = [self _rootWindowForScreen: XSCR]; + + /* We're not allowed to create a zero rect window */ + if (NSWidth(frame) <= 0 || NSHeight(frame) <= 0) + { + frame.size.width = 2; + frame.size.height = 2; + } + /* Translate to X coordinates */ + frame.origin.y = DisplayHeight(XDPY, XSCR) - NSMaxY(frame); + + window = objc_malloc(sizeof(gswindow_device_t)); + memset(window, '\0', sizeof(gswindow_device_t)); + window->display = XDPY; + window->screen = XSCR; + window->xframe = frame; + window->type = type; + window->root = root->ident; + window->parent = root->ident; + window->depth = ((RContext *)context)->depth; + window->xwn_attrs.border_pixel = ((RContext *)context)->black; + window->xwn_attrs.background_pixel = ((RContext *)context)->white; + window->xwn_attrs.colormap = ((RContext *)context)->cmap; + + window->ident = XCreateWindow(XDPY, window->root, + NSMinX(frame), NSMinY(frame), + NSWidth(frame), NSHeight(frame), + 0, + ((RContext *)context)->depth, + CopyFromParent, + ((RContext *)context)->visual, + (CWColormap | CWBackPixel|CWBorderPixel), + &window->xwn_attrs); + + /* + * Mark this as a GNUstep app with the current application name. + */ + classhint.res_name = rootName; + classhint.res_class = "GNUstep"; + XSetClassHint(XDPY, window->ident, &classhint); + + window->xwn_attrs.save_under = False; + window->xwn_attrs.override_redirect = False; + window->map_state = IsUnmapped; + window->visibility = -1; + + // Create an X GC for the content view set it's colors + values.foreground = window->xwn_attrs.background_pixel; + values.background = window->xwn_attrs.background_pixel; + values.function = GXcopy; + valuemask = (GCForeground | GCBackground | GCFunction); + window->gc = XCreateGC(XDPY, window->ident, valuemask, &values); + + // Set the X event mask + XSelectInput(XDPY, window->ident, ExposureMask | KeyPressMask | + KeyReleaseMask | ButtonPressMask | + ButtonReleaseMask | ButtonMotionMask | + StructureNotifyMask | PointerMotionMask | + EnterWindowMask | LeaveWindowMask | + FocusChangeMask | PropertyChangeMask | + ColormapChangeMask | KeymapStateMask | + VisibilityChangeMask); + + /* + * Initial attributes for any GNUstep window tell Window Maker not to + * create an app icon for us. + */ + window->win_attrs.flags = GSExtraFlagsAttr; + window->win_attrs.extra_flags = GSNoApplicationIconFlag; + + /* + * Prepare size/position hints, but don't set them now - ordering + * the window in should automatically do it. + * Note: These hints are most likely wrong, but should be fixed up + * when DPSstylewindow is called. + */ + window->siz_hints.x = NSMinX(frame); + window->siz_hints.y = NSMinY(frame); + window->siz_hints.width = NSWidth(frame); + window->siz_hints.height = NSHeight(frame); + window->siz_hints.flags = USPosition|PPosition|USSize|PSize; + + // Use the globally active input mode + window->gen_hints.flags = InputHint; + window->gen_hints.input = False; + // All the windows of a GNUstep application belong to one group. + window->gen_hints.flags |= WindowGroupHint; + window->gen_hints.window_group = ROOT; + + /* + * Prepare the protocols supported by the window. + * These protocols should be set on the window when it is ordered in. + */ + window->numProtocols = 0; + window->protocols[window->numProtocols++] = generic.take_focus_atom; + window->protocols[window->numProtocols++] = generic.delete_win_atom; + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + window->protocols[window->numProtocols++] = generic.miniaturize_atom; + } + // FIXME Add ping protocol for EWMH + XSetWMProtocols(XDPY, window->ident, window->protocols, window->numProtocols); + + window->exposedRects = [NSMutableArray new]; + window->region = XCreateRegion(); + window->buffer = 0; + window->alpha_buffer = 0; + window->ic = 0; + + // make sure that new window has the correct cursor + [self _initializeCursorForXWindow: window->ident]; + + /* + * FIXME - should this be protected by a lock for thread safety? + * generate a unique tag for this new window. + */ + do + { + last_win_num++; + } + while (last_win_num == 0 || WINDOW_WITH_TAG(last_win_num) != 0); + window->number = last_win_num; + + // Insert window into the mapping + NSMapInsert(windowmaps, (void*)window->ident, window); + NSMapInsert(windowtags, (void*)window->number, window); + [self _setWindowOwnedByServer: window->number]; + return window->number; +} + +- (void) termwindow: (int)win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return; + + if (window->root == window->ident) + { + NSLog(@"DPStermwindow: Trying to destroy root window"); + return; + } + + NSDebugLLog(@"XGTrace", @"DPSwindow: %d", win); + if (window->ic) + { + [inputServer ximCloseIC: window->ic]; + } + if (window->ident) + { + XDestroyWindow(XDPY, window->ident); + if (window->gc) + XFreeGC (XDPY, window->gc); + NSMapRemove(windowmaps, (void*)window->ident); + } + + if (window->buffer) + XFreePixmap (XDPY, window->buffer); + if (window->alpha_buffer) + XFreePixmap (XDPY, window->alpha_buffer); + if (window->region) + XDestroyRegion (window->region); + RELEASE(window->exposedRects); + NSMapRemove(windowtags, (void*)win); + objc_free(window); +} + +/* + * Return the offsets between the window content-view and it's frame + * depending on the window style. + */ +- (void) styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b : (int) style +{ + /* First try to get the offset information that we have obtained from + the WM. This will only work if the application has already created + a window that has been reparented by the WM. Otherwise we have to + guess. + */ + if (generic.parent_offset.x || generic.parent_offset.y) + { + if (style == NSBorderlessWindowMask + || (style & NSIconWindowMask) || (style & NSMiniWindowMask)) + { + *l = *r = *t = *b = 0.0; + } + else + { + *l = *r = *t = *b = generic.parent_offset.x; + if (NSResizableWindowMask & style) + { + /* We just have to guess this. Usually it doesn't matter */ + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + *b = 9; + else if ((generic.wm & XGWM_EWMH) != 0) + *b = 7; + } + if ((style & NSTitledWindowMask) || (style & NSClosableWindowMask) + || (style & NSMiniaturizableWindowMask)) + { + *t = generic.parent_offset.y; + } + } + } + else if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + if (style == NSBorderlessWindowMask + || (style & NSIconWindowMask) || (style & NSMiniWindowMask)) + { + *l = *r = *t = *b = 0.0; + } + else + { + *l = *r = *t = *b = 0; + if (NSResizableWindowMask & style) + { + *b = 9; + } + if ((style & NSTitledWindowMask) || (style & NSClosableWindowMask) + || (style & NSMiniaturizableWindowMask)) + { + *t = 22; + } + } + } + else if ((generic.wm & XGWM_EWMH) != 0) + { + if (style == NSBorderlessWindowMask + || (style & NSIconWindowMask) || (style & NSMiniWindowMask)) + { + *l = *r = *t = *b = 0.0; + } + else + { + *l = *r = *t = *b = 4; + if (NSResizableWindowMask & style) + { + *b = 7; + } + if ((style & NSTitledWindowMask) || (style & NSClosableWindowMask) + || (style & NSMiniaturizableWindowMask)) + { + *t = 20; + } + } + } + else + { + /* No known WM protocols */ + /* + * FIXME + * This should make a good guess - at the moment use no offsets. + */ + *l = *r = *t = *b = 0.0; + } +} + +- (void) stylewindow: (int)style : (int) win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return; + + NSDebugLLog(@"XGTrace", @"DPSstylewindow: %d : %d", style, win); + if (window->win_attrs.window_style != style + || (window->win_attrs.flags & GSWindowStyleAttr) == 0) + { + NSRect h; + window->win_attrs.flags |= GSWindowStyleAttr; + window->win_attrs.window_style = style; + + /* Fix up hints */ + h = [self _XFrameToOSFrame: window->xframe for: window]; + h = [self _OSFrameToXHints: h for: window]; + window->siz_hints.x = NSMinX(h); + window->siz_hints.y = NSMinY(h); + window->siz_hints.width = NSWidth(h); + window->siz_hints.height = NSHeight(h); + + // send to the WM window style hints + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + XChangeProperty(XDPY, window->ident, generic.win_decor_atom, + generic.win_decor_atom, 32, PropModeReplace, + (unsigned char *)&window->win_attrs, + sizeof(GNUstepWMAttributes)/sizeof(CARD32)); + } + else + { + setWindowHintsForStyle (XDPY, window->ident, style); + } + } +} + +- (void) titlewindow: (NSString *)window_title : (int) win +{ + XTextProperty windowName; + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return; + + NSDebugLLog(@"XGTrace", @"DPStitlewindow: %@ : %d", window_title, win); + if (window_title && window->ident) + { + const char *title = [window_title lossyCString]; + XStringListToTextProperty((char**)&title, 1, &windowName); + XSetWMName(XDPY, window->ident, &windowName); + XSetWMIconName(XDPY, window->ident, &windowName); + } +} + +- (void) docedited: (int)edited : (int) win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return; + + NSDebugLLog(@"XGTrace", @"DPSdocedited: %d : %d", edited, win); + window->win_attrs.flags |= GSExtraFlagsAttr; + if (edited) + { + window->win_attrs.extra_flags |= GSDocumentEditedFlag; + } + else + { + window->win_attrs.extra_flags &= ~GSDocumentEditedFlag; + } + // send WindowMaker WM window style hints + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + XChangeProperty(XDPY, window->ident, + generic.win_decor_atom, generic.win_decor_atom, + 32, PropModeReplace, (unsigned char *)&window->win_attrs, + sizeof(GNUstepWMAttributes)/sizeof(CARD32)); + } +} + +- (void) miniwindow: (int) win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (window == 0 || (window->win_attrs.window_style & NSIconWindowMask) != 0) + { + return; + } + NSDebugLLog(@"XGTrace", @"DPSminiwindow: %d ", win); + // AT PRESENT - things seem to go wrong if we set an icon winiwindow - + // I think that the WindowManager prevents us getting most of the events + // in the miniwindow - so it doesn't know when it have been unmapped + // and we end up trying to perform draw operations on an unmapped window! +#if 1 + /* + * If we haven't already done so - set the icon window hint for this + * window so that the GNUstep miniwindow is displayed (if supported). + */ + if ((window->gen_hints.flags & IconWindowHint) == 0) + { + NSWindow *nswin; + + nswin = GSWindowWithNumber(window->number); + if (nswin != nil) + { + int iNum = [[nswin counterpart] windowNumber]; + gswindow_device_t *iconw = WINDOW_WITH_TAG(iNum); + + if (iconw != 0) + { + window->gen_hints.flags |= IconWindowHint; + window->gen_hints.icon_window = iconw->ident; + XSetWMHints(XDPY, window->ident, &window->gen_hints); + } + } + } +#endif + XIconifyWindow(XDPY, window->ident, XSCR); +} + +/** + Make sure we have the most up-to-date window information and then + make sure the current context has our new information +*/ +- (void) windowdevice: (int)win +{ + int x, y; + unsigned width, height; + unsigned old_width; + unsigned old_height; + XWindowAttributes winattr; + gswindow_device_t *window; + NSGraphicsContext *ctxt; + + NSDebugLLog(@"XGTrace", @"DPSwindowdevice: %d ", win); + window = WINDOW_WITH_TAG(win); + if (!window) + { + NSLog(@"Invalidparam: Invalid window number %d", win); + return; + } + + if (!window->ident) + return; + + old_width = NSWidth(window->xframe); + old_height = NSHeight(window->xframe); + + XFlush (XDPY); + + /* hack: + * wait until a resize of window is finished (especially for NSMenu) + * is there any way to wait until X finished it's stuff? + * XSync(), XFlush() doesn't do the job! + */ + { + int i = 0; + do + { + XGetGeometry(XDPY, window->ident, &window->root, + &x, &y, &width, &height, + &window->border, &window->depth); + } + while( i++<10 && height != window->siz_hints.height ); + } + window->xframe.size.width = width; + window->xframe.size.height = height; + + XGetWindowAttributes(XDPY, window->ident, &winattr); + window->map_state = winattr.map_state; + + NSDebugLLog (@"NSWindow", @"window geom device ((%f, %f), (%f, %f))", + window->xframe.origin.x, window->xframe.origin.y, + window->xframe.size.width, window->xframe.size.height); + + if (window->buffer && (old_width != width || old_height != height)) + { + [isa waitAllContexts]; + XFreePixmap(XDPY, window->buffer); + window->buffer = 0; + if (window->alpha_buffer) + XFreePixmap(XDPY, window->alpha_buffer); + window->alpha_buffer = 0; + } + + if (window->buffer == 0) + { + [self _createBuffer: window]; + } + + ctxt = GSCurrentContext(); + [ctxt contextDevice: window->number]; + DPSsetgcdrawable(ctxt, window->gc, + (window->buffer) + ? (void *)window->buffer : (void *)window->ident, + 0, NSHeight(window->xframe)); + DPSinitmatrix(ctxt); + DPSinitclip(ctxt); +} + +- (void) orderwindow: (int)op : (int)otherWin : (int)winNum +{ + gswindow_device_t *window; + gswindow_device_t *other; + int level; + + window = WINDOW_WITH_TAG(winNum); + if (winNum == 0 || window == NULL) + { + NSLog(@"Invalidparam: Ordering invalid window %d", winNum); + return; + } + + if (op != NSWindowOut) + { + /* + * Some window managers ignore any hints and properties until the + * window is actually mapped, so we need to set them all up + * immediately bofore mapping the window ... + */ + + setNormalHints(XDPY, window); + XSetWMHints(XDPY, window->ident, &window->gen_hints); + + /* + * If we are asked to set hints for the appicon and Window Maker is + * to control it, we must let Window maker know that this window is + * the icon window for the app root window. + */ + if ((window->win_attrs.window_style & NSIconWindowMask) != 0 + && generic.flags.useWindowMakerIcons == 1) + { + XWMHints gen_hints; + + gen_hints.flags = WindowGroupHint | StateHint | IconWindowHint; + gen_hints.initial_state = WithdrawnState; + gen_hints.window_group = ROOT; + gen_hints.icon_window = window->ident; + XSetWMHints(XDPY, ROOT, &gen_hints); + } + + /* + * Tell the window manager what protocols this window conforms to. + */ + XSetWMProtocols(XDPY, window->ident, window->protocols, + window->numProtocols); + } + + if (generic.flags.useWindowMakerIcons == 1) + { + /* + * Icon windows are mapped/unmapped by the window manager - so we + * mustn't do anything with them here - though we can raise the + * application root window to let Window Maker know it should use + * our appicon window. + */ + if ((window->win_attrs.window_style & NSIconWindowMask) != 0) + { + if (op != NSWindowOut) + { + XMapRaised(XDPY, ROOT); + } + return; + } + if ((window->win_attrs.window_style & NSMiniWindowMask) != 0) + { + return; + } + } + + NSDebugLLog(@"XGTrace", @"DPSorderwindow: %d : %d : %d",op,otherWin,winNum); + level = window->win_attrs.window_level; + if (otherWin != 0) + { + other = WINDOW_WITH_TAG(otherWin); + level = other->win_attrs.window_level; + } + else + { + other = NULL; + } + [self setwindowlevel: level : winNum]; + + /* + * When we are ordering a window in, we must ensure that the position + * and size hints are set for the window - the window could have been + * moved or resized by the window manager before it was ordered out, + * in which case, we will have been notified of the new position, but + * will not yet have updated the window hints, so if the window manager + * looks at the existing hints when re-mapping the window it will + * place the window in an old location. + * We also set other hints and protocols supported by the window. + */ + if (op != NSWindowOut && window->map_state != IsViewable) + { + XMoveWindow(XDPY, window->ident, window->siz_hints.x, + window->siz_hints.y); + setNormalHints(XDPY, window); + } + + switch (op) + { + case NSWindowBelow: + if (other != 0) + { + XWindowChanges chg; + chg.sibling = other->ident; + chg.stack_mode = Below; + XReconfigureWMWindow(XDPY, window->ident, window->screen, + CWSibling|CWStackMode, &chg); + } + else + { + XWindowChanges chg; + chg.stack_mode = Below; + XReconfigureWMWindow(XDPY, window->ident, window->screen, + CWStackMode, &chg); + } + XMapWindow(XDPY, window->ident); + break; + + case NSWindowAbove: + if (other != 0) + { + XWindowChanges chg; + chg.sibling = other->ident; + chg.stack_mode = Above; + XReconfigureWMWindow(XDPY, window->ident, window->screen, + CWSibling|CWStackMode, &chg); + } + else + { + XWindowChanges chg; + chg.stack_mode = Above; + XReconfigureWMWindow(XDPY, window->ident, window->screen, + CWStackMode, &chg); + } + XMapWindow(XDPY, window->ident); + break; + + case NSWindowOut: + XUnmapWindow(XDPY, window->ident); + break; + } + /* + * When we are ordering a window in, we must ensure that the position + * and size hints are set for the window - the window could have been + * moved or resized by the window manager before it was ordered out, + * in which case, we will have been notified of the new position, but + * will not yet have updated the window hints, so if the window manager + * looks at the existing hints when re-mapping the window it will + * place the window in an old location. + */ + if (op != NSWindowOut && window->map_state != IsViewable) + { + XMoveWindow(XDPY, window->ident, window->siz_hints.x, + window->siz_hints.y); + setNormalHints(XDPY, window); + /* + * Do we need to setup drag types when the window is mapped or will + * they work on the set up before mapping? + * + * [self _resetDragTypesForWindow: GSWindowWithNumber(window->number)]; + */ + } + XFlush(XDPY); +} + +- (void) movewindow: (NSPoint)loc : (int)win +{ +} + +- (void) placewindow: (NSRect)rect : (int)win +{ + NSAutoreleasePool *arp; + NSRect xVal; + NSRect last; + NSEvent *event; + NSDate *limit; + NSMutableArray *tmpQueue; + unsigned pos; + float xdiff; + float ydiff; + gswindow_device_t *window; + NSWindow *nswin; + NSRect frame; + BOOL resize = NO; + BOOL move = NO; + + window = WINDOW_WITH_TAG(win); + if (win == 0 || window == NULL) + { + NSLog(@"Invalidparam: Placing invalid window %d", win); + return; + } + + NSDebugLLog(@"XGTrace", @"DPSplacewindow: %@ : %d", NSStringFromRect(rect), + win); + nswin = GSWindowWithNumber(win); + frame = [nswin frame]; + if (NSEqualRects(rect, frame) == YES) + return; + if (NSEqualSizes(rect.size, frame.size) == NO) + { + resize = YES; + move = YES; + } + if (NSEqualPoints(rect.origin, frame.origin) == NO) + { + move = YES; + } + xdiff = rect.origin.x - frame.origin.x; + ydiff = rect.origin.y - frame.origin.y; + + xVal = [self _OSFrameToXHints: rect for: window]; + window->siz_hints.width = (int)xVal.size.width; + window->siz_hints.height = (int)xVal.size.height; + window->siz_hints.x = (int)xVal.origin.x; + window->siz_hints.y = (int)xVal.origin.y; + xVal = [self _OSFrameToXFrame: rect for: window]; + + last = window->xframe; + + NSDebugLLog(@"Moving", @"Place %d - o:%@, x:%@", window->number, + NSStringFromRect(rect), NSStringFromRect(xVal)); + + XMoveResizeWindow (XDPY, window->ident, + window->siz_hints.x, window->siz_hints.y, + window->siz_hints.width, window->siz_hints.height); + setNormalHints(XDPY, window); + + /* + * Now massage all the events currently in the queue to make sure + * mouse locations in our window are adjusted as necessary. + */ + arp = [NSAutoreleasePool new]; + limit = [NSDate distantPast]; /* Don't wait for new events. */ + tmpQueue = [NSMutableArray arrayWithCapacity: 8]; + for (;;) + { + NSEventType type; + + event = DPSGetEvent(self, NSAnyEventMask, limit, + NSEventTrackingRunLoopMode); + if (event == nil) + break; + type = [event type]; + if (type == NSAppKitDefined && [event windowNumber] == win) + { + GSAppKitSubtype sub = [event subtype]; + + /* + * Window movement or resize events for the window we are + * watching are posted immediately, so they can take effect + * before the placewindow returns. + */ + if (sub == GSAppKitWindowMoved || sub == GSAppKitWindowResized) + { + [nswin sendEvent: event]; + } + else + { + [tmpQueue addObject: event]; + } + } + else if (type != NSPeriodic && type != NSLeftMouseDragged + && type != NSOtherMouseDragged && type != NSRightMouseDragged + && type != NSMouseMoved) + { + /* + * Save any events that arrive before our window is moved - excepting + * periodic events (which we can assume will be outdated) and mouse + * movement events (which might flood us). + */ + [tmpQueue addObject: event]; + } + if (NSEqualRects(xVal, window->xframe) == YES || + NSEqualRects(rect, [nswin frame]) == YES) + { + break; + } + if (NSEqualRects(last, window->xframe) == NO) + { + NSDebugLLog(@"Moving", @"From: %@\nWant %@\nGot %@", + NSStringFromRect(last), + NSStringFromRect(xVal), + NSStringFromRect(window->xframe)); + last = window->xframe; + } + } + /* + * If we got any events while waiting for the window movement, we + * may need to adjust their locations to match the new window position. + */ + pos = [tmpQueue count]; + while (pos-- > 0) + { + event = [tmpQueue objectAtIndex: pos]; + if ([event windowNumber] == win) + { + NSPoint loc = [event locationInWindow]; + + loc.x -= xdiff; + loc.y -= ydiff; + [event _patchLocation: loc]; + } + DPSPostEvent(self, event, YES); + } + RELEASE(arp); + + /* + * Failsafe - if X hasn't told us it has moved/resized the window, we + * fake the notification and post them immediately, so they can take + * effect before the placewindow returns. + */ + if (NSEqualRects([nswin frame], rect) == NO) + { + NSEvent *e; + + if (resize == YES) + { + NSDebugLLog(@"Moving", @"Fake size %d - %@", window->number, + NSStringFromSize(rect.size)); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: rect.origin + modifierFlags: 0 + timestamp: 0 + windowNumber: win + context: GSCurrentContext() + subtype: GSAppKitWindowResized + data1: rect.size.width + data2: rect.size.height]; + [nswin sendEvent: e]; + } + if (move == YES) + { + NSDebugLLog(@"Moving", @"Fake move %d - %@", window->number, + NSStringFromPoint(rect.origin)); + e = [NSEvent otherEventWithType: NSAppKitDefined + location: NSZeroPoint + modifierFlags: 0 + timestamp: 0 + windowNumber: win + context: GSCurrentContext() + subtype: GSAppKitWindowMoved + data1: rect.origin.x + data2: rect.origin.y]; + [nswin sendEvent: e]; + } + } +} + +- (BOOL) findwindow: (NSPoint)loc : (int) op : (int) otherWin : (NSPoint *)floc +: (int*) winFound +{ + return NO; +} + +- (NSRect) windowbounds: (int)win +{ + gswindow_device_t *window; + int screenHeight; + NSRect rect; + + window = WINDOW_WITH_TAG(win); + if (!window && win < MAX_SCREENS) + window = [self _rootWindowForScreen: win]; + if (!window) + return NSZeroRect; + + NSDebugLLog(@"XGTrace", @"DPScurrentwindowbounds: %d", win); + screenHeight = DisplayHeight(XDPY, window->screen); + rect = window->xframe; + rect.origin.y = screenHeight - NSMaxY(window->xframe); + return rect; +} + +- (void) setwindowlevel: (int)level : (int)win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return; + + NSDebugLLog(@"XGTrace", @"DPSsetwindowlevel: %d : %d", level, win); + if (window->win_attrs.window_level != level + || (window->win_attrs.flags & GSWindowLevelAttr) == 0) + { + window->win_attrs.flags |= GSWindowLevelAttr; + window->win_attrs.window_level = level; + + // send WindowMaker WM window style hints + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + XEvent event; + + /* + * First change the window properties so that, if the window + * is not mapped, we have stored the required info for when + * the WM maps it. + */ + XChangeProperty(XDPY, window->ident, + generic.win_decor_atom, generic.win_decor_atom, + 32, PropModeReplace, (unsigned char *)&window->win_attrs, + sizeof(GNUstepWMAttributes)/sizeof(CARD32)); + /* + * Now send a message for rapid handling. + */ + event.xclient.type = ClientMessage; + event.xclient.message_type = generic.win_decor_atom; + event.xclient.format = 32; + event.xclient.display = XDPY; + event.xclient.window = window->ident; + event.xclient.data.l[0] = GSWindowLevelAttr; + event.xclient.data.l[1] = window->win_attrs.window_level; + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 0; + XSendEvent(XDPY, DefaultRootWindow(XDPY), False, + SubstructureRedirectMask, &event); + } + else if ((generic.wm & XGWM_EWMH) != 0) + { + Atom flag = generic.wintypes.win_normal_atom; + + if (level == NSModalPanelWindowLevel) + flag = generic.wintypes.win_modal_atom; + // For strang reasons this level does not work out for the main menu + else if (//level == NSMainMenuWindowLevel || + level == NSSubmenuWindowLevel || + level == NSFloatingWindowLevel || + level == NSTornOffMenuWindowLevel || + level == NSPopUpMenuWindowLevel) + flag = generic.wintypes.win_menu_atom; + else if (level == NSDockWindowLevel) + flag =generic.wintypes.win_dock_atom; + else if (level == NSStatusWindowLevel) + flag = generic.wintypes.win_floating_atom; + else if (level == NSDesktopWindowLevel) + flag = generic.wintypes.win_desktop_atom; + + XChangeProperty(XDPY, window->ident, generic.wintypes.win_type_atom, + XA_ATOM, 32, PropModeReplace, + (unsigned char *)&flag, 1); + } + else if ((generic.wm & XGWM_GNOME) != 0) + { + XEvent event; + int flag = WIN_LAYER_NORMAL; + + if (level == NSDesktopWindowLevel) + flag = WIN_LAYER_DESKTOP; + else if (level == NSSubmenuWindowLevel + || level == NSFloatingWindowLevel + || level == NSTornOffMenuWindowLevel) + flag = WIN_LAYER_ONTOP; + else if (level == NSMainMenuWindowLevel) + flag = WIN_LAYER_MENU; + else if (level == NSDockWindowLevel + || level == NSStatusWindowLevel) + flag = WIN_LAYER_DOCK; + else if (level == NSModalPanelWindowLevel + || level == NSPopUpMenuWindowLevel) + flag = WIN_LAYER_ONTOP; + else if (level == NSScreenSaverWindowLevel) + flag = WIN_LAYER_ABOVE_DOCK; + + XChangeProperty(XDPY, window->ident, generic.wintypes.win_type_atom, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&flag, 1); + + event.xclient.type = ClientMessage; + event.xclient.window = window->ident; + event.xclient.display = XDPY; + event.xclient.message_type = generic.wintypes.win_type_atom; + event.xclient.format = 32; + event.xclient.data.l[0] = flag; + XSendEvent(XDPY, window->root, False, + SubstructureNotifyMask, &event); + } + } +} + +- (int) windowlevel: (int)win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + /* + * If we have previously set a level for this window - return the value set. + */ + if (window != 0 && (window->win_attrs.flags & GSWindowLevelAttr)) + return window->win_attrs.window_level; + return 0; +} + +- (NSArray *) windowlist +{ + return nil; +} + +- (int) windowdepth: (int)win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window && win < MAX_SCREENS) + window = [self _rootWindowForScreen: win]; + if (!window) + return 0; + + return window->depth; +} + +- (void) setmaxsize: (NSSize)size : (int)win +{ + gswindow_device_t *window; + NSRect r; + + window = WINDOW_WITH_TAG(win); + if (window == 0) + { + return; + } + r = NSMakeRect(0, 0, size.width, size.height); + r = [self _OSFrameToXFrame: r for: window]; + window->siz_hints.flags |= PMaxSize; + window->siz_hints.max_width = r.size.width; + window->siz_hints.max_height = r.size.height; + setNormalHints(XDPY, window); +} + +- (void) setminsize: (NSSize)size : (int)win +{ + gswindow_device_t *window; + NSRect r; + + window = WINDOW_WITH_TAG(win); + if (window == 0) + { + return; + } + r = NSMakeRect(0, 0, size.width, size.height); + r = [self _OSFrameToXFrame: r for: window]; + window->siz_hints.flags |= PMinSize; + window->siz_hints.min_width = r.size.width; + window->siz_hints.min_height = r.size.height; + setNormalHints(XDPY, window); +} + +- (void) setresizeincrements: (NSSize)size : (int)win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (window == 0) + { + return; + } + window->siz_hints.flags |= PResizeInc; + window->siz_hints.width_inc = size.width; + window->siz_hints.height_inc = size.height; + setNormalHints(XDPY, window); +} + +// process expose event +- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return; + + if (window->type != NSBackingStoreNonretained) + { + XGCValues values; + unsigned long valuemask; + + // window has a backing store so just copy the exposed rect from the + // pixmap to the X window + + NSDebugLLog (@"NSWindow", @"copy exposed area ((%d, %d), (%d, %d))", + rectangle.x, rectangle.y, rectangle.width, rectangle.height); + + values.function = GXcopy; + values.plane_mask = AllPlanes; + values.clip_mask = None; + values.foreground = ((RContext *)context)->white; + valuemask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground); + XChangeGC(XDPY, window->gc, valuemask, &values); + [isa waitAllContexts]; + XCopyArea (XDPY, window->buffer, window->ident, window->gc, + rectangle.x, rectangle.y, rectangle.width, rectangle.height, + rectangle.x, rectangle.y); + } + else + { + NSRect rect; + + // no backing store, so keep a list of exposed rects to be + // processed in the _processExposedRectangles method + // Add the rectangle to the region used in -_processExposedRectangles + // to set the clipping path. + XUnionRectWithRegion (&rectangle, window->region, window->region); + + // Transform the rectangle's coordinates to PS coordinates and add + // this new rectangle to the list of exposed rectangles. + rect.origin = NSMakePoint((float)rectangle.x, rectangle.y); + rect.size = NSMakeSize(rectangle.width, rectangle.height); + [window->exposedRects addObject: [NSValue valueWithRect: rect]]; + } +} + +- (void) flushwindowrect: (NSRect)rect : (int)win +{ + int xi, yi, width, height; + XGCValues values; + unsigned long valuemask; + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (win == 0 || window == NULL) + { + NSLog(@"Invalidparam: Placing invalid window %d", win); + return; + } + + NSDebugLLog(@"XGTrace", @"DPSflushwindowrect: %@ : %d", + NSStringFromRect(rect), win); + if (window->type == NSBackingStoreNonretained) + { + XFlush(XDPY); + return; + } + + /* FIXME: Doesn't take into account any offset added to the window + (from PSsetXgcdrawable) or possible scaling (unlikely in X-windows, + but what about other devices?) */ + rect.origin.y = NSHeight(window->xframe) - NSMaxY(rect); + + values.function = GXcopy; + values.plane_mask = AllPlanes; + values.clip_mask = None; + valuemask = (GCFunction | GCPlaneMask | GCClipMask); + XChangeGC(XDPY, window->gc, valuemask, &values); + + xi = NSMinX(rect); // width/height seems + yi = NSMinY(rect); // to require +1 pixel + width = NSWidth(rect) + 1; // to copy out + height = NSHeight(rect) + 1; + + NSDebugLLog (@"NSWindow", + @"copy X rect ((%d, %d), (%d, %d))", xi, yi, width, height); + + if (width > 0 || height > 0) + { + [isa waitAllContexts]; + XCopyArea (XDPY, window->buffer, window->ident, window->gc, + xi, yi, width, height, xi, yi); + } + + XFlush(XDPY); +} + +// handle X expose events +- (void) _processExposedRectangles: (int)win +{ + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return; + + if (window->type != NSBackingStoreNonretained) + return; + + // Set the clipping path to the exposed rectangles + // so that further drawing will not affect the non-exposed region + XSetRegion (XDPY, window->gc, window->region); + + // We should determine the views that need to be redisplayed. Until we + // fully support scalation and rotation of views redisplay everything. + // FIXME: It seems wierd to trigger a front-end method from here... + [GSWindowWithNumber(win) display]; + + // Restore the exposed rectangles and the region + [window->exposedRects removeAllObjects]; + XDestroyRegion (window->region); + window->region = XCreateRegion(); + XSetClipMask (XDPY, window->gc, None); +} + +- (BOOL) capturemouse: (int)win +{ + int ret; + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (!window) + return NO; + + ret = XGrabPointer(XDPY, window->ident, False, + PointerMotionMask | ButtonReleaseMask | ButtonPressMask, + GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + + if (ret != GrabSuccess) + NSLog(@"Failed to grab pointer\n"); + else + { + grab_window = window; + NSDebugLLog(@"NSWindow", @"Grabbed pointer\n"); + } + return (ret == GrabSuccess) ? YES : NO; +} + +- (void) releasemouse +{ + XUngrabPointer(XDPY, CurrentTime); + grab_window = NULL; +} + +- (void) setinputfocus: (int)win +{ + gswindow_device_t *window = WINDOW_WITH_TAG(win); + + if (win == 0 || window == 0) + { + NSDebugLLog(@"Focus", @"Setting focus to unknown win %d", win); + return; + } + + NSDebugLLog(@"XGTrace", @"DPSsetinputfocus: %d", win); + /* + * If we have an outstanding request to set focus to this window, + * we don't want to do it again. + */ + if (win == generic.desiredFocusWindow && generic.focusRequestNumber != 0) + { + NSDebugLLog(@"Focus", @"Resetting focus to %d", window->number); + } + else + { + NSDebugLLog(@"Focus", @"Setting focus to %d", window->number); + } + generic.desiredFocusWindow = win; + generic.focusRequestNumber = XNextRequest(XDPY); + XSetInputFocus(XDPY, window->ident, RevertToParent, generic.lastTime); + [inputServer ximFocusICWindow: window]; +} + +/* + * Instruct window manager that the specified window is 'key', 'main', or + * just a normal window. + */ +- (void) setinputstate: (int)st : (int)win +{ + NSDebugLLog(@"XGTrace", @"DPSsetinputstate: %d : %d", win, st); + if ((generic.wm & XGWM_WINDOWMAKER) != 0) + { + gswindow_device_t *window = WINDOW_WITH_TAG(win); + XEvent event; + + event.xclient.type = ClientMessage; + event.xclient.message_type = generic.titlebar_state_atom; + event.xclient.format = 32; + event.xclient.display = XDPY; + event.xclient.window = window->ident; + event.xclient.data.l[0] = st; + event.xclient.data.l[1] = 0; + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 0; + XSendEvent(XDPY, DefaultRootWindow(XDPY), False, + SubstructureRedirectMask, &event); + } +} + +- (void *) serverDevice +{ + return XDPY; +} + +- (void *) windowDevice: (int)win +{ + static Window ptrloc; + gswindow_device_t *window; + + window = WINDOW_WITH_TAG(win); + if (window != NULL) + ptrloc = window->ident; + else + ptrloc = 0; + return &ptrloc; +} + +/* Cursor Ops */ +typedef struct _xgps_cursor_id_t { + Cursor c; +} xgps_cursor_id_t; + +static char xgps_blank_cursor_bits [] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static Cursor xgps_blank_cursor = None; +static BOOL cursor_hidden = NO; + +- (Cursor) _blankCursor +{ + if (xgps_blank_cursor == None) + { + Pixmap shape, mask; + XColor black, white; + + shape = XCreatePixmapFromBitmapData(XDPY, XDRW, + xgps_blank_cursor_bits, + 16, 16, 1, 0, 1); + mask = XCreatePixmapFromBitmapData(XDPY, XDRW, + xgps_blank_cursor_bits, + 16, 16, 1, 0, 1); + black.red = black.green = black.blue = 0; + black = [self xColorFromColor: black]; + white.red = white.green = white.blue = 65535; + white = [self xColorFromColor: white]; + + xgps_blank_cursor = XCreatePixmapCursor(XDPY, shape, mask, + &white, &black, 0, 0); + XFreePixmap(XDPY, shape); + XFreePixmap(XDPY, mask); + } + return xgps_blank_cursor; +} + +/* + set the cursor for a newly created window. +*/ + +- (void) _initializeCursorForXWindow: (Window) win +{ + if (cursor_hidden) + { + XDefineCursor (XDPY, win, [self _blankCursor]); + } + else + { + xgps_cursor_id_t *cid = [[NSCursor currentCursor] _cid]; + + XDefineCursor (XDPY, win, cid->c); + } +} + + +/* + set cursor on all XWindows we own. if `set' is NO + the cursor is unset on all windows. + Normally the cursor `c' correspond to the [NSCursor currentCursor] + The only exception should be when the cursor is hidden. + In that case `c' will be a blank cursor. +*/ + +- (void) _DPSsetcursor: (Cursor)c : (BOOL)set +{ + Window win; + NSMapEnumerator enumerator; + gswindow_device_t *d; + + NSDebugLLog (@"NSCursor", @"_DPSsetcursor: cursor = %p, set = %d", c, set); + + enumerator = NSEnumerateMapTable (windowmaps); + while (NSNextMapEnumeratorPair (&enumerator, (void**)&win, (void**)&d) == YES) + { + if (set) + XDefineCursor(XDPY, win, c); + else + XUndefineCursor(XDPY, win); + } +} + +#define ALPHA_THRESHOLD 158 + +Pixmap +xgps_cursor_mask(Display *xdpy, Drawable draw, const char *data, + int w, int h, int colors) +{ + int j, i; + unsigned char ialpha; + Pixmap pix; + int bitmapSize = ((w + 7) >> 3) * h; // (w/8) rounded up times height + char *aData = calloc(1, bitmapSize); + char *cData = aData; + + if (colors == 4) + { + int k; + for (j = 0; j < h; j++) + { + k = 0; + for (i = 0; i < w; i++, k++) + { + if (k > 7) + { + cData++; + k = 0; + } + data += 3; + ialpha = (unsigned short)((char)*data++); + if (ialpha > ALPHA_THRESHOLD) + { + *cData |= (0x01 << k); + } + } + cData++; + } + } + else + { + for (j = 0; j < bitmapSize; j++) + { + *cData++ = 0xff; + } + } + + pix = XCreatePixmapFromBitmapData(xdpy, draw, (char *)aData, w, h, + 1L, 0L, 1); + free(aData); + return pix; +} + +Pixmap +xgps_cursor_image(Display *xdpy, Drawable draw, const unsigned char *data, + int w, int h, int colors, XColor *fg, XColor *bg) +{ + int j, i, min, max; + Pixmap pix; + int bitmapSize = ((w + 7) >> 3) * h; // w/8 rounded up multiplied by h + char *aData = calloc(1, bitmapSize); + char *cData = aData; + + min = 1 << 16; + max = 0; + if (colors == 4 || colors == 3) + { + int k; + for (j = 0; j < h; j++) + { + k = 0; + for (i = 0; i < w; i++, k++) + { + /* colors is in the range 0..65535 + and value is the percieved brightness, obtained by + averaging 0.3 red + 0.59 green + 0.11 blue + */ + int color = ((77 * data[0]) + (151 * data[1]) + (28 * data[2])); + + if (k > 7) + { + cData++; + k = 0; + } + if (color > (1 << 15)) + { + *cData |= (0x01 << k); + } + if (color < min) + { + min = color; + bg->red = (int)data[0] * 256; + bg->green = (int)data[1] * 256; + bg->blue = (int)data[2] * 256; + } + else if (color > max) + { + max = color; + fg->red = (int)data[0] * 256; + fg->green = (int)data[1] * 256; + fg->blue = (int)data[2] * 256; + } + data += 3; + if (colors == 4) + { + data++; + } + } + cData++; + } + } + else + { + for (j = 0; j < bitmapSize; j++) + { + if ((unsigned short)((char)*data++) > 128) + { + *cData |= (0x01 << i); + } + cData++; + } + } + + pix = XCreatePixmapFromBitmapData(xdpy, draw, (char *)aData, w, h, + 1L, 0L, 1); + free(aData); + return pix; +} + +- (void) hidecursor +{ + if (cursor_hidden) + return; + + [self _DPSsetcursor: [self _blankCursor] : YES]; + cursor_hidden = YES; +} + +- (void) showcursor +{ + if (cursor_hidden) + { + /* This just resets the cursor to the parent window's cursor. + I'm not even sure it's needed */ + [self _DPSsetcursor: None : NO]; + /* Reset the current cursor */ + [[NSCursor currentCursor] set]; + } + cursor_hidden = NO; +} + +- (void) standardcursor: (int)style : (void **)cid +{ + xgps_cursor_id_t *cursor; + cursor = NSZoneMalloc([self zone], sizeof(xgps_cursor_id_t)); + switch (style) + { + case GSArrowCursor: + cursor->c = XCreateFontCursor(XDPY, XC_left_ptr); + break; + case GSIBeamCursor: + cursor->c = XCreateFontCursor(XDPY, XC_xterm); + break; + default: + cursor->c = XCreateFontCursor(XDPY, XC_left_ptr); + break; + } + if (cid) + *cid = (void *)cursor; +} + +- (void) imagecursor: (NSPoint)hotp : (int) w : (int) h : (int)colors : (const char *)image : (void **)cid +{ + xgps_cursor_id_t *cursor; + Pixmap source, mask; + unsigned int maxw, maxh; + XColor fg, bg; + + /* FIXME: We might create a blank cursor here? */ + if (image == NULL || w == 0 || h == 0) + { + *cid = NULL; + return; + } + + /* FIXME: Handle this better or return an error? */ + XQueryBestCursor(XDPY, ROOT, w, h, &maxw, &maxh); + if (w > maxw) + w = maxw; + if (h > maxh) + h = maxh; + + cursor = NSZoneMalloc([self zone], sizeof(xgps_cursor_id_t)); + source = xgps_cursor_image(XDPY, ROOT, image, w, h, colors, &fg, &bg); + mask = xgps_cursor_mask(XDPY, ROOT, image, w, h, colors); + bg = [self xColorFromColor: bg]; + fg = [self xColorFromColor: fg]; + + cursor->c = XCreatePixmapCursor(XDPY, source, mask, &fg, &bg, + (int)hotp.x, (int)(h - hotp.y)); + XFreePixmap(XDPY, source); + XFreePixmap(XDPY, mask); + if (cid) + *cid = (void *)cursor; +} + +- (void) setcursorcolor: (NSColor *)fg : (NSColor *)bg : (void*) cid +{ + XColor xf, xb; + xgps_cursor_id_t *cursor; + + cursor = (xgps_cursor_id_t *)cid; + if (cursor == NULL) + NSLog(@"Invalidparam: Invalid cursor"); + + [self _DPSsetcursor: cursor->c : YES]; + /* Special hack: Don't set the color when fg == nil. Used by NSCursor + to just set the cursor but not the color. */ + if (fg == nil) + { + return; + } + + fg = [fg colorUsingColorSpaceName: NSDeviceRGBColorSpace]; + bg = [bg colorUsingColorSpaceName: NSDeviceRGBColorSpace]; + xf.red = 65535 * [fg redComponent]; + xf.green = 65535 * [fg greenComponent]; + xf.blue = 65535 * [fg blueComponent]; + xb.red = 65535 * [bg redComponent]; + xb.green = 65535 * [bg greenComponent]; + xb.blue = 65535 * [bg blueComponent]; + xf = [self xColorFromColor: xf]; + xb = [self xColorFromColor: xb]; + + XRecolorCursor(XDPY, cursor->c, &xf, &xb); +} + +static NSWindowDepth +_computeDepth(int class, int bpp) +{ + int spp = 0; + int bitValue = 0; + int bps = 0; + NSWindowDepth depth = 0; + + switch (class) + { + case GrayScale: + case StaticGray: + bitValue = _GSGrayBitValue; + spp = 1; + break; + case PseudoColor: + case StaticColor: + bitValue = _GSCustomBitValue; + spp = 1; + break; + case DirectColor: + case TrueColor: + bitValue = _GSRGBBitValue; + spp = 3; + break; + default: + break; + } + + bps = (bpp/spp); + depth = (bitValue | bps); + + return depth; +} + +- (NSArray *)screenList +{ + /* I guess screen numbers are in order starting from zero, but we + put the main screen first */ + int i; + int count = ScreenCount(XDPY); + NSMutableArray *windows = [NSMutableArray arrayWithCapacity: count]; + if (count > 0) + [windows addObject: [NSNumber numberWithInt: XSCR]]; + for (i = 0; i < count; i++) + { + if (i != XSCR) + [windows addObject: [NSNumber numberWithInt: i]]; + } + return windows; +} + +- (NSWindowDepth) windowDepthForScreen: (int) screen_num +{ + Display *display; + Screen *screen; + int class = 0, bpp = 0; + + display = XDPY; + if (display == NULL) + { + return 0; + } + + screen = XScreenOfDisplay(display, screen_num); + if (screen == NULL) + { + return 0; + } + + bpp = screen->root_depth; + class = screen->root_visual->class; + + return _computeDepth(class, bpp); +} + +- (const NSWindowDepth *) availableDepthsForScreen: (int) screen_num +{ + Display *display; + Screen *screen; + int class = 0; + int index = 0; + int ndepths = 0; + NSZone *defaultZone = NSDefaultMallocZone(); + NSWindowDepth *depths = 0; + + display = XDPY; + if (display == NULL) + { + return NULL; + } + + screen = XScreenOfDisplay(display, screen_num); + if (screen == NULL) + { + return NULL; + } + + // Allocate the memory for the array and fill it in. + ndepths = screen->ndepths; + class = screen->root_visual->class; + depths = NSZoneMalloc(defaultZone, sizeof(NSWindowDepth)*(ndepths + 1)); + for (index = 0; index < ndepths; index++) + { + int depth = screen->depths[index].depth; + depths[index] = _computeDepth(class, depth); + } + depths[index] = 0; // terminate with a zero. + + return depths; +} + +- (NSSize) resolutionForScreen: (int)screen_num +{ + Display *display; + int res_x, res_y; + + if (screen_num < 0 || screen_num >= ScreenCount(XDPY)) + { + NSLog(@"Invalidparam: no screen %d", screen_num); + return NSMakeSize(0,0); + } + // This does not take virtual displays into account!! + res_x = DisplayWidth(display, screen_num) / + (DisplayWidthMM(display, screen_num) / 25.4); + res_y = DisplayHeight(display, screen_num) / + (DisplayHeightMM(display, screen_num) / 25.4); + + return NSMakeSize(res_x, res_y); +} + +- (NSRect) boundsForScreen: (int)screen +{ + if (screen < 0 || screen >= ScreenCount(XDPY)) + { + NSLog(@"Invalidparam: no screen %d", screen); + return NSZeroRect; + } + return NSMakeRect(0, 0, DisplayWidth(XDPY, screen), + DisplayHeight(XDPY, screen)); +} + +@end + + +#include "x11/XGSlideView.h" + +@implementation XGServer (Sliding) +- (BOOL) _slideImage: (NSImage*)image from: (NSPoint)from to: (NSPoint)to +{ + return [XGSlideView _slideImage: image from: from to: to]; +} +@end + diff --git a/Source/x11/XGSlideView.m b/Source/x11/XGSlideView.m new file mode 100644 index 0000000..ff0df30 --- /dev/null +++ b/Source/x11/XGSlideView.m @@ -0,0 +1,238 @@ +/* + XGSlideView + + Copyright (C) 2002 Free Software Foundation, Inc. + + Created by: Enrico Sersale + Date: Jan 2002 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "x11/XGServer.h" +#include "x11/XGServerWindow.h" +#include "x11/XGSlideView.h" +#include +#include + +#define DWZ 48 +#define ALPHA_THRESHOLD 158 + +#define XDPY [XGServer currentXDisplay] + +#ifndef max +#define max(a,b) ((a) > (b) ? (a): (b)) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a): (b)) +#endif + +#define DMAX 1800 +#define MAXSTEPS 100 + +@interface XGSlideRawWindow : NSWindow +@end + +@interface NSImage (BackEnd) +- (Pixmap) xPixmapMask; +@end + +@interface XGSlideView (Private) +- (void) _setupWindow: (NSPoint)slideStart; +- (BOOL) _slideFrom: (NSPoint)fromPoint to: (NSPoint)toPoint; +@end + +@implementation XGSlideView (Private) + +- (void) _setupWindow: (NSPoint)slideStart +{ + NSSize imageSize = [[slideCell image] size]; + Pixmap pixmap = 0; + + [_window setFrame: NSMakeRect (slideStart.x, slideStart.y, + imageSize.width, imageSize.height) display: NO]; + + if ([[[slideCell image] backgroundColor] alphaComponent] * 256 + <= ALPHA_THRESHOLD) + { + [self lockFocus]; + pixmap = [[slideCell image] xPixmapMask]; + [self unlockFocus]; + } + + if (pixmap) + { + XShapeCombineMask(XDPY, slideWindev->ident, ShapeBounding, 0, 0, + pixmap, ShapeSet); + XFreePixmap(XDPY, pixmap); + } + else + { + XShapeCombineMask(XDPY, slideWindev->ident, ShapeBounding, + 0, 0, 0, ShapeSet); + } + + [_window orderFrontRegardless]; +} + +- (BOOL) _slideFrom: (NSPoint)fromPoint to: (NSPoint)toPoint +{ + float sheight = [[NSScreen mainScreen] frame].size.height; + float iheight = [[slideCell image] size].height; + NSPoint fPoint = NSMakePoint(fromPoint.x, sheight - fromPoint.y - iheight); + NSPoint tPoint = NSMakePoint(toPoint.x, sheight - toPoint.y - iheight); + float distx = max(fPoint.x, tPoint.x) - min(fPoint.x, tPoint.x); + float disty = max(fPoint.y, tPoint.y) - min(fPoint.y, tPoint.y); + float dist = sqrt((distx * distx) + (disty * disty)); + float r = DMAX / dist; + int steps = (int)(MAXSTEPS / r); + float unitx = distx / steps; + float unity = disty / steps; + float xp = fPoint.x; + float yp = fPoint.y; + float *xpositions + = NSZoneMalloc (NSDefaultMallocZone(), sizeof(float) * steps); + float *ypositions + = NSZoneMalloc (NSDefaultMallocZone(), sizeof(float) * steps); + NSEvent *theEvent; + int i; + + unitx = (tPoint.x > fPoint.x) ? unitx : -unitx; + unity = (tPoint.y > fPoint.y) ? unity : -unity; + + for (i = 0; i < steps; i++) + { + xp += unitx; + yp += unity; + xpositions[i] = xp; + ypositions[i] = yp; + } + + XFlush(XDPY); + [NSEvent startPeriodicEventsAfterDelay: 0.02 withPeriod: 0.02]; + for (i = 0; i < steps; i++) + { + theEvent = [NSApp nextEventMatchingMask: NSPeriodicMask + untilDate: [NSDate distantFuture] + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + XMoveWindow (XDPY, slideWindev->ident, xpositions[i], ypositions[i]); + } + [NSEvent stopPeriodicEvents]; + + NSZoneFree (NSDefaultMallocZone(), xpositions); + NSZoneFree (NSDefaultMallocZone(), ypositions); + + [[self window] orderOut: nil]; + + return YES; +} + +@end + +@implementation XGSlideView + ++ (BOOL) _slideImage: (NSImage *)image + from: (NSPoint)fromPoint + to: (NSPoint)toPoint +{ + static XGSlideView *v = nil; + BOOL result = NO; + + if (image != nil) + { + if (v == nil) + { + v = [[self alloc] init]; + } + [NSApp preventWindowOrdering]; + [v->slideCell setImage: image]; + [v _setupWindow: fromPoint]; + result = [v _slideFrom: fromPoint to: toPoint]; + } + return result; +} + +- (id) init +{ + self = [super init]; + if (self != nil) + { + NSRect winRect = {{0, 0}, {DWZ, DWZ}}; + XGSlideRawWindow *slideWindow = [XGSlideRawWindow alloc]; + + slideCell = [[NSCell alloc] initImageCell: nil]; + [slideCell setBordered: NO]; + + slideWindow = [slideWindow initWithContentRect: winRect + styleMask: NSBorderlessWindowMask + backing: NSBackingStoreNonretained + defer: NO]; + [slideWindow setContentView: self]; + RELEASE (self); + + slideWindev + = [XGServer _windowWithTag: [slideWindow windowNumber]]; + } + + return self; +} + +- (void) dealloc +{ + RELEASE (slideCell); + [super dealloc]; +} + +- (void) drawRect: (NSRect)rect +{ + [slideCell drawWithFrame: rect inView: self]; +} + + +@end + +@implementation XGSlideRawWindow + +- (BOOL) canBecomeMainWindow +{ + return NO; +} + +- (BOOL) canBecomeKeyWindow +{ + return NO; +} + +- (void) _initDefaults +{ + [super _initDefaults]; + [self setReleasedWhenClosed: YES]; + [self setExcludedFromWindowsMenu: YES]; +} + +@end diff --git a/Source/x11/XIMInputServer.m b/Source/x11/XIMInputServer.m new file mode 100644 index 0000000..ecde8cf --- /dev/null +++ b/Source/x11/XIMInputServer.m @@ -0,0 +1,336 @@ +/* XIMInputServer - XIM Keyboard input handling + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Christian Gillot + Date: Nov 2001 + Author: Adam Fedor + Date: Jan 2002 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "config.h" + +#include +#include +#include +#include + +#include "x11/XGInputServer.h" +#include + +@interface XIMInputServer (XIMPrivate) +- (BOOL) ximInit: (Display *)dpy; +- (void) ximClose; +- (int) ximStyleInit; +- (XIC) ximCreateIC: (Window)w; +- (unsigned long) ximXicGetMask: (XIC)xic; +@end + +#define BUF_LEN 255 + +@implementation XIMInputServer + +- (id) initWithDelegate: (id)aDelegate + name: (NSString *)name +{ + Display *dpy = [XGServer currentXDisplay]; + return [self initWithDelegate: aDelegate display: dpy name: name]; +} + +- (id) initWithDelegate: (id)aDelegate + display: (Display *)dpy + name: (NSString *)name +{ + char *locale; + NSString *localeEncoding; + delegate = aDelegate; + ASSIGN(server_name, name); + dbuf = RETAIN([NSMutableData dataWithCapacity: BUF_LEN]); + + /* Use X11 version of setlocale since many people just set the locale + for X. Also just get CTYPE locale (which is typically the one that + deals with character handling */ + locale = setlocale(LC_CTYPE, ""); + localeEncoding = [NSString stringWithCString: locale]; + if (XSupportsLocale() != True) + { + NSLog(@"Xlib does not support locale setting %@", localeEncoding); + /* FIXME: Should we reset the locale or just hope that X + can deal with it? */ + } + localeEncoding = [[[localeEncoding componentsSeparatedByString: @"."] + lastObject] lowercaseString]; + NSDebugLLog(@"XIM", @"XIM locale encoding is %@", localeEncoding); + // FIXME: Use [GSFontInfo +encodingForRegistry:encoding:]? + if ([localeEncoding isEqualToString:@"big5"]) + { + encoding = NSBIG5StringEncoding; + } +#ifdef X_HAVE_UTF8_STRING + else if ([localeEncoding isEqualToString:@"utf8"] + || [localeEncoding isEqualToString:@"utf-8"] ) + { + encoding = NSUTF8StringEncoding; + } +#endif + else + { + encoding = NSISOLatin1StringEncoding; + } + +#if USE_XIM + if ([self ximInit: dpy] == NO) + { + NSLog(@"Unable to initialize XIM, using standard keyboard events"); + } +#endif + return self; +} + +- (void) dealloc +{ + DESTROY(server_name); + DESTROY(dbuf); + [self ximClose]; +} + +/* ---------------------------------------------------------------------- + XInputFiltering protocol methods +*/ +- (BOOL) filterEvent: (XEvent *)event +{ + if (XFilterEvent(event, None)) + { + NSDebugLLog(@"NSKeyEvent", @"Event filtered by XIM\n"); + return YES; + } + return NO; +} + +- (NSString *) lookupStringForEvent: (XKeyEvent *)event + window: (gswindow_device_t *)windev + keysym: (KeySym *)keysymptr +{ + int count; + Status status; + NSString *keys; + KeySym keysym; + XComposeStatus compose; + char *buf = [dbuf mutableBytes]; + + /* Process characters */ + keys = nil; + if (windev->ic && event->type == KeyPress) + { + [dbuf setLength: BUF_LEN]; +#ifdef X_HAVE_UTF8_STRING + if (encoding == NSUTF8StringEncoding) + count = Xutf8LookupString(windev->ic, event, buf, BUF_LEN, + &keysym, &status); + else +#endif + count = XmbLookupString(windev->ic, event, buf, BUF_LEN, + &keysym, &status); + + if (status==XBufferOverflow) + NSDebugLLog(@"NSKeyEvent",@"XmbLookupString buffer overflow\n"); + if (count) + { + [dbuf setLength: count]; + keys = [[NSString alloc] initWithData: dbuf encoding: encoding]; + } + } + else + { + count = XLookupString (event, buf, BUF_LEN, &keysym, &compose); + /* Make sure that the string is properly terminated */ + if (count > BUF_LEN) + buf[BUF_LEN] = '\0'; + else + { + if (count < 1) + buf[0] = '\0'; + else + buf[count] = '\0'; + } + if (count) + keys = [NSString stringWithCString: buf]; + } + + if (keysymptr) + *keysymptr = keysym; + + return keys; +} + +/* ---------------------------------------------------------------------- + NSInputServiceProvider protocol methods +*/ +- (void) activeConversationChanged: (id)sender + toNewConversation: (long)newConversation +{ + NSWindow *window; + gswindow_device_t *windev; + + [super activeConversationChanged: sender + toNewConversation: newConversation]; + + if ([sender respondsToSelector: @selector(window)] == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"NSTextInput sender does not respond to window"]; + } + window = [sender window]; + windev = [XGServer _windowWithTag: [window windowNumber]]; + if (windev == NULL) + { + [NSException raise: NSInvalidArgumentException + format: @"NSTextInput sender has invalid window"]; + } + + [self ximFocusICWindow: windev]; +} + +- (void) activeConversationWillChange: (id)sender + fromOldConversation: (long)oldConversation +{ + [super activeConversationWillChange: sender + fromOldConversation: oldConversation]; +} + +/* ---------------------------------------------------------------------- + XIM private methods +*/ +- (BOOL) ximInit: (Display *)dpy +{ + XClassHint class_hints; + + if (!XSetLocaleModifiers ("")) + NSDebugLLog(@"XIM", @"can not set locale modifiers\n"); + + /* FIXME: Get these */ + class_hints.res_name = class_hints.res_class = NULL; + xim = XOpenIM(dpy, NULL, class_hints.res_name, class_hints.res_class); + if (xim == NULL) + { + NSDebugLLog(@"XIM", @"Can't open XIM.\n"); + return NO; + } + + if (![self ximStyleInit]) + { + [self ximClose]; + return NO; + } + + NSDebugLLog(@"XIM", @"Initialized XIM\n"); + return YES; +} + +- (int) ximStyleInit +{ + /* FIXME: Right now we only support this style *but* + this is only temporary */ + XIMStyle xim_supported_style=XIMPreeditNothing|XIMStatusNothing; + XIMStyles *styles; + char *failed_arg; + int i; + + failed_arg = XGetIMValues(xim,XNQueryInputStyle,&styles,NULL); + if (failed_arg!=NULL) + { + NSDebugLLog(@"XIM", @"Can't getting the following IM value :%s", + failed_arg); + return 0; + } + + for (i=0;icount_styles;i++) + { + if (styles->supported_styles[i]==xim_supported_style) + { + xim_style=xim_supported_style; + XFree(styles); + return 1; + } + } + + XFree(styles); + return 0; +} + +- (void) ximClose +{ + NSDebugLLog(@"XIM", @"Closed XIM\n"); + if (xim) + XCloseIM(xim); + xim=NULL; +} + +- (void) ximFocusICWindow: (gswindow_device_t *)windev +{ + if (xim == NULL) + return; + + /* Make sure we have an ic for this window */ +#if USE_XIM + if (windev->ic == NULL) + { + windev->ic = [self ximCreateIC: windev->ident]; + if (windev->ic == NULL) + { + [self ximClose]; + } + } +#endif + + /* Now set focus to this window */ + if (windev->ic) + { + NSDebugLLog(@"XIM", @"XSetICFocus to window %p", + windev->ident); + XSetICFocus(windev->ic); + } +} + +- (XIC) ximCreateIC: (Window)w +{ + XIC xic; + xic = XCreateIC(xim, XNClientWindow, w, XNInputStyle, + xim_style, XNFocusWindow, w, NULL); + if (xic==NULL) + NSDebugLLog(@"XIM", @"Can't create the input context.\n"); + return xic; +} + +- (unsigned long) ximXicGetMask: (XIC)xic +{ + unsigned long xic_xmask = 0; + if (XGetICValues(xic,XNFilterEvents,&xic_xmask,NULL)!=NULL) + NSDebugLLog(@"XIM", @"Can't get the event mask for that input context"); + + return xic_xmask; +} + +- (void) ximCloseIC: (XIC)xic +{ + XDestroyIC(xic); +} + +@end diff --git a/Source/x11/context.c b/Source/x11/context.c new file mode 100644 index 0000000..86d1fc9 --- /dev/null +++ b/Source/x11/context.c @@ -0,0 +1,800 @@ +/* context.c - X context management + * + * Raster graphics library + * + * Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "StdCmap.h" + +#include "xrtools.h" + + +extern void _wraster_change_filter(int type); + + +static Bool bestContext(Display *dpy, int screen_number, RContext *context); + +static RContextAttributes DEFAULT_CONTEXT_ATTRIBS = { + RC_UseSharedMemory|RC_RenderMode|RC_ColorsPerChannel, /* flags */ + RDitheredRendering, /* render_mode */ + 4, /* colors_per_channel */ + 0, + 0, + 0, + 0, + True, /* use_shared_memory */ + RMitchellFilter, + RUseStdColormap +}; + + + +/* + * + * Colormap allocation for PseudoColor visuals: + * + * + * switch standardColormap: + * none: + * allocate colors according to colors_per_channel + * + * best/default: + * if there's a std colormap defined then use it + * + * else + * create a std colormap and set it + */ + + + + +/* + *---------------------------------------------------------------------- + * allocateStandardPseudoColor + * Creates the internal colormap for PseudoColor, setting the + * color values according to the supplied standard colormap. + * + * Returns: - + * + * Side effects: - + * + * Notes: - + *---------------------------------------------------------------------- + */ +static Bool +allocateStandardPseudoColor(RContext *ctx, XStandardColormap *stdcmap) +{ + int i; + + ctx->ncolors = stdcmap->red_max * stdcmap->red_mult + + stdcmap->green_max * stdcmap->green_mult + + stdcmap->blue_max * stdcmap->blue_mult + 1; + + if (ctx->ncolors <= 1) { + RErrorCode = RERR_INTERNAL; + puts("wraster: bad standard colormap"); + + return False; + } + + ctx->colors = malloc(sizeof(XColor)*ctx->ncolors); + if (!ctx->colors) { + RErrorCode = RERR_NOMEMORY; + + return False; + } + + ctx->pixels = malloc(sizeof(unsigned long)*ctx->ncolors); + if (!ctx->pixels) { + + free(ctx->colors); + ctx->colors = NULL; + + RErrorCode = RERR_NOMEMORY; + + return False; + } + + +#define calc(max,mult) (((i / stdcmap->mult) % \ + (stdcmap->max + 1)) * 65535) / stdcmap->max + + for (i = 0; i < ctx->ncolors; i++) { + ctx->colors[i].pixel = i + stdcmap->base_pixel; + ctx->colors[i].red = calc(red_max, red_mult); + ctx->colors[i].green = calc(green_max, green_mult); + ctx->colors[i].blue = calc(blue_max, blue_mult); + + ctx->pixels[i] = ctx->colors[i].pixel; + } + +#undef calc + + return True; +} + + +static Bool +setupStandardColormap(RContext *ctx, Atom property) +{ + if (!XmuLookupStandardColormap(ctx->dpy, ctx->screen_number, + ctx->visual->visualid, + ctx->depth, property, + True, True)) { + RErrorCode = RERR_STDCMAPFAIL; + + return False; + } + return True; +} + + + + + + + + + +static Bool +allocatePseudoColor(RContext *ctx) +{ + XColor *colors; + XColor avcolors[256]; + int avncolors; + int i, ncolors, r, g, b; + int retries; + int cpc = ctx->attribs->colors_per_channel; + + ncolors = cpc * cpc * cpc; + + if (ncolors > (1<depth)) { + /* reduce colormap size */ + cpc = ctx->attribs->colors_per_channel = 1<<((int)ctx->depth/3); + ncolors = cpc * cpc * cpc; + } + + assert(cpc >= 2 && ncolors <= (1<depth)); + + colors = malloc(sizeof(XColor)*ncolors); + if (!colors) { + RErrorCode = RERR_NOMEMORY; + return False; + } + + ctx->pixels = malloc(sizeof(unsigned long)*ncolors); + if (!ctx->pixels) { + free(colors); + RErrorCode = RERR_NOMEMORY; + return False; + } + + i=0; + + if ((ctx->attribs->flags & RC_GammaCorrection) && ctx->attribs->rgamma > 0 + && ctx->attribs->ggamma > 0 && ctx->attribs->bgamma > 0) { + double rg, gg, bg; + double tmp; + + /* do gamma correction */ + rg = 1.0/ctx->attribs->rgamma; + gg = 1.0/ctx->attribs->ggamma; + bg = 1.0/ctx->attribs->bgamma; + for (r=0; rdpy, ctx->cmap, &(colors[i]))) { + colors[i].flags = 0; /* failed */ + } else { + colors[i].flags = DoRed|DoGreen|DoBlue; + } + } + /* try to allocate close values for the colors that couldn't + * be allocated before */ + avncolors = (1<depth>256 ? 256 : 1<depth); + for (i=0; idpy, ctx->cmap, avcolors, avncolors); + + for (i=0; i>8; + g = (colors[i].green - avcolors[i].green)>>8; + b = (colors[i].blue - avcolors[i].blue)>>8; + diff = r*r + g*g + b*b; + if (diffdpy, ctx->cmap, &colors[i])) { + colors[i].flags = DoRed|DoGreen|DoBlue; + break; /* succeeded, don't need to retry */ + } +#ifdef DEBUG + printf("close color allocation failed. Retrying...\n"); +#endif + } + } + } + + ctx->colors = colors; + ctx->ncolors = ncolors; + + /* fill the pixels shortcut array */ + for (i = 0; i < ncolors; i++) { + ctx->pixels[i] = ctx->colors[i].pixel; + } + + return True; +} + + +static XColor* +allocateGrayScale(RContext *ctx) +{ + XColor *colors; + XColor avcolors[256]; + int avncolors; + int i, ncolors, r, g, b; + int retries; + int cpc = ctx->attribs->colors_per_channel; + + ncolors = cpc * cpc * cpc; + + if (ctx->vclass == StaticGray) { + /* we might as well use all grays */ + ncolors = 1<depth; + } else { + if ( ncolors > (1<depth) ) { + /* reduce colormap size */ + cpc = ctx->attribs->colors_per_channel = 1<<((int)ctx->depth/3); + ncolors = cpc * cpc * cpc; + } + + assert(cpc >= 2 && ncolors <= (1<depth)); + } + + if (ncolors>=256 && ctx->vclass==StaticGray) { + /* don't need dithering for 256 levels of gray in StaticGray visual */ + ctx->attribs->render_mode = RBestMatchRendering; + } + + colors = malloc(sizeof(XColor)*ncolors); + if (!colors) { + RErrorCode = RERR_NOMEMORY; + return False; + } + for (i=0; idpy, ctx->cmap, &(colors[i]))) { + colors[i].flags = 0; /* failed */ +#ifdef DEBUG + printf("failed:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue); +#endif + } else { + colors[i].flags = DoRed|DoGreen|DoBlue; +#ifdef DEBUG + printf("success:%x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue); +#endif + } + } + /* try to allocate close values for the colors that couldn't + * be allocated before */ + avncolors = (1<depth>256 ? 256 : 1<depth); + for (i=0; idpy, ctx->cmap, avcolors, avncolors); + + for (i=0; i>8; + g = (colors[i].green - avcolors[i].green)>>8; + b = (colors[i].blue - avcolors[i].blue)>>8; + diff = r*r + g*g + b*b; + if (diff %x,%x,%x\n",colors[i].red,colors[i].green,colors[i].blue,avcolors[closest].red,avcolors[closest].green,avcolors[closest].blue); +#endif + colors[i].red = avcolors[closest].red; + colors[i].green = avcolors[closest].green; + colors[i].blue = avcolors[closest].blue; + if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) { + colors[i].flags = DoRed|DoGreen|DoBlue; + break; /* succeeded, don't need to retry */ + } +#ifdef DEBUG + printf("close color allocation failed. Retrying...\n"); +#endif + } + } + } + return colors; +} + + +static Bool +setupPseudoColorColormap(RContext *context) +{ + Atom property = 0; + + if (context->attribs->standard_colormap_mode == RCreateStdColormap) { + property = XInternAtom(context->dpy, "RGB_DEFAULT_MAP", False); + + if (!setupStandardColormap(context, property)) { + return False; + } + } + + if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) { + XStandardColormap *maps; + int count, i; + + if (!property) { + property = XInternAtom(context->dpy, "RGB_BEST_MAP", False); + if (!XGetRGBColormaps(context->dpy, + DefaultRootWindow(context->dpy), + &maps, &count, property)) { + maps = NULL; + } + + if (!maps) { + property = XInternAtom(context->dpy, "RGB_DEFAULT_MAP", False); + if (!XGetRGBColormaps(context->dpy, + DefaultRootWindow(context->dpy), + &maps, &count, property)) { + maps = NULL; + } + } + } else { + if (!XGetRGBColormaps(context->dpy, + DefaultRootWindow(context->dpy), + &maps, &count, property)) { + maps = NULL; + } + } + + if (maps) { + int theMap = -1; + + for (i = 0; i < count; i++) { + if (maps[i].visualid == context->visual->visualid) { + theMap = i; + break; + } + } + + if (theMap < 0) { + puts("wrlib: no std cmap found"); + } + + if (theMap >= 0 + && allocateStandardPseudoColor(context, &maps[theMap])) { + + context->std_rgb_map = XAllocStandardColormap(); + + *context->std_rgb_map = maps[theMap]; + + context->cmap = context->std_rgb_map->colormap; + + XFree(maps); + + return True; + } + + XFree(maps); + } + } + + context->attribs->standard_colormap_mode = RIgnoreStdColormap; + + /* RIgnoreStdColormap and fallback */ + return allocatePseudoColor(context); +} + + + + +static char* +mygetenv(char *var, int scr) +{ + char *p; + char varname[64]; + + sprintf(varname, "%s%i", var, scr); + p = getenv(varname); + if (!p) { + p = getenv(var); + } + return p; +} + + +static void +gatherconfig(RContext *context, int screen_n) +{ + char *ptr; + + ptr = mygetenv("WRASTER_GAMMA", screen_n); + if (ptr) { + float g1,g2,g3; + if (sscanf(ptr, "%f/%f/%f", &g1, &g2, &g3)!=3 + || g1<=0.0 || g2<=0.0 || g3<=0.0) { + printf("wrlib: invalid value(s) for gamma correction \"%s\"\n", + ptr); + } else { + context->attribs->flags |= RC_GammaCorrection; + context->attribs->rgamma = g1; + context->attribs->ggamma = g2; + context->attribs->bgamma = g3; + } + } + ptr = mygetenv("WRASTER_COLOR_RESOLUTION", screen_n); + if (ptr) { + int i; + if (sscanf(ptr, "%d", &i)!=1 || i<2 || i>6) { + printf("wrlib: invalid value for color resolution \"%s\"\n",ptr); + } else { + context->attribs->flags |= RC_ColorsPerChannel; + context->attribs->colors_per_channel = i; + } + } + + ptr = mygetenv("WRASTER_OPTIMIZE_FOR_SPEED", screen_n); + if (ptr) { + context->flags.optimize_for_speed = 1; + } else { + context->flags.optimize_for_speed = 0; + } + +} + + +static void +getColormap(RContext *context, int screen_number) +{ + Colormap cmap = None; + XStandardColormap *cmaps; + int ncmaps, i; + + if (XGetRGBColormaps(context->dpy, + RootWindow(context->dpy, screen_number), + &cmaps, &ncmaps, XA_RGB_DEFAULT_MAP)) { + for (i=0; ivisual->visualid) { + puts("ACHOU"); + cmap = cmaps[i].colormap; + break; + } + } + XFree(cmaps); + } + if (cmap == None) { + XColor color; + + cmap = XCreateColormap(context->dpy, + RootWindow(context->dpy, screen_number), + context->visual, AllocNone); + + color.red = color.green = color.blue = 0; + XAllocColor(context->dpy, cmap, &color); + context->black = color.pixel; + + color.red = color.green = color.blue = 0xffff; + XAllocColor(context->dpy, cmap, &color); + context->white = color.pixel; + + } + context->cmap = cmap; +} + + +static int +count_offset(unsigned long mask) +{ + int i; + + i=0; + while ((mask & 1)==0) { + i++; + mask = mask >> 1; + } + return i; +} + + +RContext* +RCreateContext(Display *dpy, int screen_number, RContextAttributes *attribs) +{ + RContext *context; + XGCValues gcv; + + + context = malloc(sizeof(RContext)); + if (!context) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + memset(context, 0, sizeof(RContext)); + + context->dpy = dpy; + + context->screen_number = screen_number; + + context->attribs = malloc(sizeof(RContextAttributes)); + if (!context->attribs) { + free(context); + RErrorCode = RERR_NOMEMORY; + return NULL; + } + if (!attribs) + *context->attribs = DEFAULT_CONTEXT_ATTRIBS; + else + *context->attribs = *attribs; + + if (!(context->attribs->flags & RC_StandardColormap)) { + context->attribs->standard_colormap_mode = RUseStdColormap; + } + + /* get configuration from environment variables */ + gatherconfig(context, screen_number); +#ifndef BENCH + _wraster_change_filter(context->attribs->scaling_filter); +#endif + if ((context->attribs->flags & RC_VisualID)) { + XVisualInfo *vinfo, templ; + int nret; + + templ.screen = screen_number; + templ.visualid = context->attribs->visualid; + vinfo = XGetVisualInfo(context->dpy, VisualIDMask|VisualScreenMask, + &templ, &nret); + if (!vinfo || nret==0) { + free(context); + RErrorCode = RERR_BADVISUALID; + return NULL; + } + + if (vinfo[0].visual == DefaultVisual(dpy, screen_number)) { + context->attribs->flags |= RC_DefaultVisual; + } else { + XSetWindowAttributes attr; + unsigned long mask; + + context->visual = vinfo[0].visual; + context->depth = vinfo[0].depth; + context->vclass = vinfo[0].class; + getColormap(context, screen_number); + attr.colormap = context->cmap; + attr.override_redirect = True; + attr.border_pixel = 0; + attr.background_pixel = 0; + mask = CWBorderPixel|CWColormap|CWOverrideRedirect|CWBackPixel; + context->drawable = + XCreateWindow(dpy, RootWindow(dpy, screen_number), 1, 1, + 1, 1, 0, context->depth, CopyFromParent, + context->visual, mask, &attr); + /* XSetWindowColormap(dpy, context->drawable, attr.colormap);*/ + } + XFree(vinfo); + } + + /* use default */ + if (!context->visual) { + if ((context->attribs->flags & RC_DefaultVisual) + || !bestContext(dpy, screen_number, context)) { + context->visual = DefaultVisual(dpy, screen_number); + context->depth = DefaultDepth(dpy, screen_number); + context->cmap = DefaultColormap(dpy, screen_number); + context->drawable = RootWindow(dpy, screen_number); + context->black = BlackPixel(dpy, screen_number); + context->white = WhitePixel(dpy, screen_number); + context->vclass = context->visual->class; + } + } + + gcv.function = GXcopy; + gcv.graphics_exposures = False; + context->copy_gc = XCreateGC(dpy, context->drawable, GCFunction + |GCGraphicsExposures, &gcv); + + if (context->vclass == PseudoColor || context->vclass == StaticColor) { + + if (!setupPseudoColorColormap(context)) { + return NULL; + } + + } else if (context->vclass == GrayScale || context->vclass == StaticGray) { + context->colors = allocateGrayScale(context); + if (!context->colors) { + return NULL; + } + } else if (context->vclass == TrueColor) { + /* calc offsets to create a TrueColor pixel */ + context->red_offset = count_offset(context->visual->red_mask); + context->green_offset = count_offset(context->visual->green_mask); + context->blue_offset = count_offset(context->visual->blue_mask); + /* disable dithering on 24 bits visuals */ + if (context->depth >= 24) + context->attribs->render_mode = RBestMatchRendering; + } + + /* check avaiability of MIT-SHM */ +#ifdef XSHM + if (!(context->attribs->flags & RC_UseSharedMemory)) { + context->attribs->flags |= RC_UseSharedMemory; + context->attribs->use_shared_memory = True; + } + + if (context->attribs->use_shared_memory) { + int major, minor; + Bool sharedPixmaps; + + context->flags.use_shared_pixmap = 0; + + if (!XShmQueryVersion(context->dpy, &major, &minor, &sharedPixmaps)) { + context->attribs->use_shared_memory = False; + } else { + if (XShmPixmapFormat(context->dpy)==ZPixmap) + context->flags.use_shared_pixmap = sharedPixmaps; + } + } +#endif + + return context; +} + + +static Bool +bestContext(Display *dpy, int screen_number, RContext *context) +{ + XVisualInfo *vinfo=NULL, rvinfo; + int best = -1, numvis, i; + long flags; + XSetWindowAttributes attr; + + rvinfo.class = TrueColor; + rvinfo.screen = screen_number; + flags = VisualClassMask | VisualScreenMask; + + vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis); + if (vinfo) { /* look for a TrueColor, 24-bit or more (pref 24) */ + for (i=numvis-1, best = -1; i>=0; i--) { + if (vinfo[i].depth == 24) best = i; + else if (vinfo[i].depth>24 && best<0) best = i; + } + } + +#if 0 + if (best == -1) { /* look for a DirectColor, 24-bit or more (pref 24) */ + rvinfo.class = DirectColor; + if (vinfo) XFree((char *) vinfo); + vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis); + if (vinfo) { + for (i=0, best = -1; i24 && best<0) best = i; + } + } + } +#endif + if (best > -1) { + context->visual = vinfo[best].visual; + context->depth = vinfo[best].depth; + context->vclass = vinfo[best].class; + getColormap(context, screen_number); + attr.colormap = context->cmap; + attr.override_redirect = True; + attr.border_pixel = 0; + context->drawable = + XCreateWindow(dpy, RootWindow(dpy, screen_number), + 1, 1, 1, 1, 0, context->depth, + CopyFromParent, context->visual, + CWBorderPixel|CWColormap|CWOverrideRedirect, &attr); +/* XSetWindowColormap(dpy, context->drawable, context->cmap);*/ + } + if (vinfo) XFree((char *) vinfo); + + if (best < 0) + return False; + else + return True; +} diff --git a/Source/x11/convert.c b/Source/x11/convert.c new file mode 100644 index 0000000..12d61a6 --- /dev/null +++ b/Source/x11/convert.c @@ -0,0 +1,1065 @@ +/* convert.c - convert RImage to Pixmap + * + * Raster graphics library + * + * Copyright (c) 1997-2000 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + + +#include +#include +#include +#include +#include + +#include + +#ifdef BENCH +#include "bench.h" +#endif + +#include "xrtools.h" + +#ifdef XSHM +extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage); + +#endif + + +#ifdef ASM_X86 +extern void x86_PseudoColor_32_to_8(unsigned char *image, + unsigned char *ximage, + char *err, char *nerr, + short *ctable, + int dr, int dg, int db, + unsigned long *pixels, + int cpc, + int width, int height, + int bytesPerPixel, + int line_offset); +#endif /* ASM_X86 */ + +#ifdef ASM_X86_MMX + +extern int x86_check_mmx(); + +extern void x86_mmx_TrueColor_32_to_16(unsigned char *image, + unsigned short *ximage, + short *err, short *nerr, + short *rtable, short *gtable, + short *btable, + int dr, int dg, int db, + unsigned int roffs, + unsigned int goffs, + unsigned int boffs, + int width, int height, + int line_offset); + + + +#endif /* ASM_X86_MMX */ + + + +typedef struct RConversionTable { + unsigned short table[256]; + unsigned short index; + + struct RConversionTable *next; +} RConversionTable; + + +typedef struct RStdConversionTable { + unsigned int table[256]; + + unsigned short mult; + unsigned short max; + + struct RStdConversionTable *next; +} RStdConversionTable; + + + +static RConversionTable *conversionTable = NULL; +static RStdConversionTable *stdConversionTable = NULL; + + +static unsigned short* +computeTable(unsigned short mask) +{ + RConversionTable *tmp = conversionTable; + int i; + + while (tmp) { + if (tmp->index == mask) + break; + tmp = tmp->next; + } + + if (tmp) + return tmp->table; + + tmp = (RConversionTable *)malloc(sizeof(RConversionTable)); + if (tmp == NULL) + return NULL; + + for (i=0;i<256;i++) + tmp->table[i] = (i*mask + 0x7f)/0xff; + + tmp->index = mask; + tmp->next = conversionTable; + conversionTable = tmp; + return tmp->table; +} + + +static unsigned int* +computeStdTable(unsigned int mult, unsigned int max) +{ + RStdConversionTable *tmp = stdConversionTable; + unsigned int i; + + while (tmp) { + if (tmp->mult == mult && tmp->max == max) + break; + tmp = tmp->next; + } + + if (tmp) + return tmp->table; + + tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable)); + if (tmp == NULL) + return NULL; + + for (i=0; i<256; i++) { + tmp->table[i] = (i*max)/0xff * mult; + } + tmp->mult = mult; + tmp->max = max; + + tmp->next = stdConversionTable; + stdConversionTable = tmp; + + return tmp->table; +} + +/***************************************************************************/ + + +static void +convertTrueColor_generic(RXImage *ximg, RImage *image, + char *err, char *nerr, + const short *rtable, + const short *gtable, + const short *btable, + const int dr, const int dg, const int db, + const unsigned short roffs, + const unsigned short goffs, + const unsigned short boffs) +{ + char *terr; + int x, y, r, g, b; + int pixel; + int rer, ger, ber; + unsigned char *ptr = image->data; + int channels = image->format == RRGBAFormat ? 4 : 3; + + /* convert and dither the image to XImage */ + for (y=0; yheight; y++) { + nerr[0] = 0; + nerr[1] = 0; + nerr[2] = 0; + for (x=0; xwidth; x++, ptr+=channels) { + + /* reduce pixel */ + pixel = *ptr + err[x]; + if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff; + r = rtable[pixel]; + /* calc error */ + rer = pixel - r*dr; + + /* reduce pixel */ + pixel = *(ptr+1) + err[x+1]; + if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff; + g = gtable[pixel]; + /* calc error */ + ger = pixel - g*dg; + + /* reduce pixel */ + pixel = *(ptr+2) + err[x+2]; + if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff; + b = btable[pixel]; + /* calc error */ + ber = pixel - b*db; + + + pixel = (r<image, x, y, pixel); + + /* distribute error */ + r = (rer*3)/8; + g = (ger*3)/8; + b = (ber*3)/8; + /* x+1, y */ + err[x+3*1]+=r; + err[x+1+3*1]+=g; + err[x+2+3*1]+=b; + /* x, y+1 */ + nerr[x]+=r; + nerr[x+1]+=g; + nerr[x+2]+=b; + /* x+1, y+1 */ + nerr[x+3*1]=rer-2*r; + nerr[x+1+3*1]=ger-2*g; + nerr[x+2+3*1]=ber-2*b; + } + /* skip to next line */ + terr = err; + err = nerr; + nerr = terr; + } +} + + + + +static RXImage* +image2TrueColor(RContext *ctx, RImage *image) +{ + RXImage *ximg; + unsigned short rmask, gmask, bmask; + unsigned short roffs, goffs, boffs; + unsigned short *rtable, *gtable, *btable; + int channels = (image->format == RRGBAFormat ? 4 : 3); + + ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height); + if (!ximg) { + return NULL; + } + + roffs = ctx->red_offset; + goffs = ctx->green_offset; + boffs = ctx->blue_offset; + + rmask = ctx->visual->red_mask >> roffs; + gmask = ctx->visual->green_mask >> goffs; + bmask = ctx->visual->blue_mask >> boffs; + + rtable = computeTable(rmask); + gtable = computeTable(gmask); + btable = computeTable(bmask); + + if (rtable==NULL || gtable==NULL || btable==NULL) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + + +#ifdef BENCH + cycle_bench(1); +#endif + + if (ctx->attribs->render_mode==RBestMatchRendering) { + int ofs, r, g, b; + int x, y; + unsigned long pixel; + unsigned char *ptr = image->data; + + /* fake match */ +#ifdef DEBUG + puts("true color match"); +#endif + for (y=0, ofs=0; y < image->height; y++) { + for (x=0; x < image->width; x++, ofs+=channels-3) { + /* reduce pixel */ + r = rtable[ptr[ofs++]]; + g = gtable[ptr[ofs++]]; + b = btable[ptr[ofs++]]; + pixel = (r<image, x, y, pixel); + } + } + } else { + /* dither */ + const int dr=0xff/rmask; + const int dg=0xff/gmask; + const int db=0xff/bmask; + +#ifdef DEBUG + puts("true color dither"); +#endif + +#ifdef ASM_X86_MMX + if (ctx->depth == 16 && image->format == RRGBAFormat + && x86_check_mmx()) { + short *err; + short *nerr; + + err = malloc(8*(image->width+3)); + nerr = malloc(8*(image->width+3)); + if (!err || !nerr) { + if (nerr) + free(nerr); + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + memset(err, 0, 8*(image->width+3)); + memset(nerr, 0, 8*(image->width+3)); + + x86_mmx_TrueColor_32_to_16(image->data, + (unsigned short*)ximg->image->data, + err+8, nerr+8, + rtable, gtable, btable, + dr, dg, db, + roffs, goffs, boffs, + image->width, image->height, + ximg->image->bytes_per_line - 2*image->width); + + free(err); + free(nerr); + } else +#endif /* ASM_X86_MMX */ + { + char *err; + char *nerr; + int ch = image->format == RRGBAFormat ? 4 : 3; + + err = malloc(ch*(image->width+2)); + nerr = malloc(ch*(image->width+2)); + if (!err || !nerr) { + if (nerr) + free(nerr); + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + + memset(err, 0, ch*(image->width+2)); + memset(nerr, 0, ch*(image->width+2)); + + convertTrueColor_generic(ximg, image, err, nerr, + rtable, gtable, btable, + dr, dg, db, roffs, goffs, boffs); + free(err); + free(nerr); + } + + } + +#ifdef BENCH + cycle_bench(0); +#endif + + return ximg; +} + + +/***************************************************************************/ + +static void +convertPseudoColor_to_8(RXImage *ximg, RImage *image, + char *err, char *nerr, + const short *rtable, + const short *gtable, + const short *btable, + const int dr, const int dg, const int db, + unsigned long *pixels, + int cpc) +{ + char *terr; + int x, y, r, g, b; + int pixel; + int rer, ger, ber; + unsigned char *ptr = image->data; + unsigned char *optr = ximg->image->data; + int channels = image->format == RRGBAFormat ? 4 : 3; + int cpcpc = cpc*cpc; + + /* convert and dither the image to XImage */ + for (y=0; yheight; y++) { + nerr[0] = 0; + nerr[1] = 0; + nerr[2] = 0; + for (x=0; xwidth*3; x+=3, ptr+=channels) { + + /* reduce pixel */ + pixel = *ptr + err[x]; + if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff; + r = rtable[pixel]; + /* calc error */ + rer = pixel - r*dr; + + /* reduce pixel */ + pixel = *(ptr+1) + err[x+1]; + if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff; + g = gtable[pixel]; + /* calc error */ + ger = pixel - g*dg; + + /* reduce pixel */ + pixel = *(ptr+2) + err[x+2]; + if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff; + b = btable[pixel]; + /* calc error */ + ber = pixel - b*db; + + *optr++ = pixels[r*cpcpc + g*cpc + b]; + + /* distribute error */ + r = (rer*3)/8; + g = (ger*3)/8; + b = (ber*3)/8; + + /* x+1, y */ + err[x+3*1]+=r; + err[x+1+3*1]+=g; + err[x+2+3*1]+=b; + /* x, y+1 */ + nerr[x]+=r; + nerr[x+1]+=g; + nerr[x+2]+=b; + /* x+1, y+1 */ + nerr[x+3*1]=rer-2*r; + nerr[x+1+3*1]=ger-2*g; + nerr[x+2+3*1]=ber-2*b; + } + /* skip to next line */ + terr = err; + err = nerr; + nerr = terr; + + optr += ximg->image->bytes_per_line - image->width; + } +} + + + +static RXImage* +image2PseudoColor(RContext *ctx, RImage *image) +{ + RXImage *ximg; + register int x, y, r, g, b; + unsigned char *ptr; + unsigned long pixel; + const int cpc=ctx->attribs->colors_per_channel; + const unsigned short rmask = cpc-1; /* different sizes could be used */ + const unsigned short gmask = rmask; /* for r,g,b */ + const unsigned short bmask = rmask; + unsigned short *rtable, *gtable, *btable; + const int cpccpc = cpc*cpc; + int channels = image->format == RRGBAFormat ? 4 : 3; + + ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height); + if (!ximg) { + return NULL; + } + + ptr = image->data; + + /* Tables are same at the moment because rmask==gmask==bmask. */ + rtable = computeTable(rmask); + gtable = computeTable(gmask); + btable = computeTable(bmask); + + if (rtable==NULL || gtable==NULL || btable==NULL) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + + if (ctx->attribs->render_mode == RBestMatchRendering) { + /* fake match */ +#ifdef DEBUG + printf("pseudo color match with %d colors per channel\n", cpc); +#endif + for (y=0; yheight; y++) { + for (x=0; xwidth; x++, ptr+=channels-1) { + /* reduce pixel */ + r = rtable[*ptr++]; + g = gtable[*ptr++]; + b = btable[*ptr++]; + pixel = r*cpccpc + g*cpc + b; + /*data[ofs] = ctx->colors[pixel].pixel;*/ + XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel); + } + } + } else { + /* dither */ + char *err; + char *nerr; + const int dr=0xff/rmask; + const int dg=0xff/gmask; + const int db=0xff/bmask; + + +#ifdef DEBUG + printf("pseudo color dithering with %d colors per channel\n", cpc); +#endif + err = malloc(4*(image->width+3)); + nerr = malloc(4*(image->width+3)); + if (!err || !nerr) { + if (nerr) + free(nerr); + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + memset(err, 0, 4*(image->width+3)); + memset(nerr, 0, 4*(image->width+3)); + +#ifdef ASM_X86 + x86_PseudoColor_32_to_8(image->data, ximg->image->data, + err+4, nerr+4, + rtable, + dr, dg, db, ctx->pixels, cpc, + image->width, image->height, + channels, + ximg->image->bytes_per_line - image->width); +#else + convertPseudoColor_to_8(ximg, image, err+4, nerr+4, + rtable, gtable, btable, + dr, dg, db, ctx->pixels, cpc); +#endif + + free(err); + free(nerr); + } + + return ximg; +} + + +/* + * For standard colormap + */ +static RXImage* +image2StandardPseudoColor(RContext *ctx, RImage *image) +{ + RXImage *ximg; + register int x, y, r, g, b; + unsigned char *ptr; + unsigned long pixel; + unsigned char *data; + unsigned int *rtable, *gtable, *btable; + unsigned int base_pixel = ctx->std_rgb_map->base_pixel; + int channels = image->format == RRGBAFormat ? 4 : 3; + /*register unsigned char maxrgb = 0xff;*/ + + ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height); + if (!ximg) { + return NULL; + } + + ptr = image->data; + + data = (unsigned char *)ximg->image->data; + + + rtable = computeStdTable(ctx->std_rgb_map->red_mult, + ctx->std_rgb_map->red_max); + + gtable = computeStdTable(ctx->std_rgb_map->green_mult, + ctx->std_rgb_map->green_max); + + btable = computeStdTable(ctx->std_rgb_map->blue_mult, + ctx->std_rgb_map->blue_max); + + if (rtable==NULL || gtable==NULL || btable==NULL) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + + + if (ctx->attribs->render_mode == RBestMatchRendering) { + for (y=0; yheight; y++) { + for (x=0; xwidth; x++, ptr+=channels-3) { + /* reduce pixel */ + pixel = (rtable[*ptr++] + gtable[*ptr++] + + btable[*ptr++] + base_pixel) & 0xffffffff; + + XPutPixel(ximg->image, x, y, pixel); + } + } + } else { + /* dither */ + short *err, *nerr; + short *terr; + int rer, ger, ber; + int x1, ofs; + + err = (short*)malloc(3*(image->width+2)*sizeof(short)); + nerr = (short*)malloc(3*(image->width+2)*sizeof(short)); + if (!err || !nerr) { + if (nerr) + free(nerr); + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + for (x=0, x1=0; xwidth*3; x1+=channels-3) { + err[x++] = ptr[x1++]; + err[x++] = ptr[x1++]; + err[x++] = ptr[x1++]; + } + err[x++] = err[x++] = err[x++] = 0; + /* convert and dither the image to XImage */ + for (y=0, ofs=0; yheight; y++) { + if (yheight-1) { + int x1; + for (x=0, x1=(y+1)*image->width*channels; + xwidth*3; + x1+=channels-3) { + nerr[x++] = ptr[x1++]; + nerr[x++] = ptr[x1++]; + nerr[x++] = ptr[x1++]; + } + /* last column */ + x1-=channels; + nerr[x++] = ptr[x1++]; + nerr[x++] = ptr[x1++]; + nerr[x++] = ptr[x1++]; + } + for (x=0; xwidth*3; x+=3, ofs++) { + /* reduce pixel */ + if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0; + if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0; + if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0; + + r = rtable[err[x]]; + g = gtable[err[x+1]]; + b = btable[err[x+2]]; + + pixel = r + g + b; + + data[ofs] = base_pixel + pixel; + + /* calc error */ + rer = err[x] - (ctx->colors[pixel].red>>8); + ger = err[x+1] - (ctx->colors[pixel].green>>8); + ber = err[x+2] - (ctx->colors[pixel].blue>>8); + + /* distribute error */ + err[x+3*1]+=(rer*7)/16; + err[x+1+3*1]+=(ger*7)/16; + err[x+2+3*1]+=(ber*7)/16; + + nerr[x]+=(rer*5)/16; + nerr[x+1]+=(ger*5)/16; + nerr[x+2]+=(ber*5)/16; + + if (x>0) { + nerr[x-3*1]+=(rer*3)/16; + nerr[x-3*1+1]+=(ger*3)/16; + nerr[x-3*1+2]+=(ber*3)/16; + } + + nerr[x+3*1]+=rer/16; + nerr[x+1+3*1]+=ger/16; + nerr[x+2+3*1]+=ber/16; + } + /* skip to next line */ + terr = err; + err = nerr; + nerr = terr; + + ofs += ximg->image->bytes_per_line - image->width; + } + free(err); + free(nerr); + } + ximg->image->data = (char*)data; + + return ximg; +} + + + +static RXImage* +image2GrayScale(RContext *ctx, RImage *image) +{ + RXImage *ximg; + register int x, y, g; + unsigned char *ptr; + const int cpc=ctx->attribs->colors_per_channel; + unsigned short gmask; + unsigned short *table; + unsigned char *data; + int channels = image->format == RRGBAFormat ? 4 : 3; + + /*register unsigned char maxrgb = 0xff;*/ + + ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height); + if (!ximg) { + return NULL; + } + + ptr = image->data; + + data = (unsigned char *)ximg->image->data; + + if (ctx->vclass == StaticGray) + gmask = (1<depth) - 1; /* use all grays */ + else + gmask = cpc*cpc*cpc-1; + + table = computeTable(gmask); + + if (table==NULL) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + + if (ctx->attribs->render_mode == RBestMatchRendering) { + /* fake match */ +#ifdef DEBUG + printf("grayscale match with %d colors per channel\n", cpc); +#endif + for (y=0; yheight; y++) { + for (x=0; xwidth; x++) { + /* reduce pixel */ + g = table[(*ptr++ * 30 + *ptr++ * 59 + *ptr++ * 11)/100]; + + /*data[ofs] = ctx->colors[g].pixel;*/ + XPutPixel(ximg->image, x, y, ctx->colors[g].pixel); + } + } + } else { + /* dither */ + short *gerr; + short *ngerr; + short *terr; + int ger; + const int dg=0xff/gmask; + +#ifdef DEBUG + printf("grayscale dither with %d colors per channel\n", cpc); +#endif + gerr = (short*)malloc((image->width+2)*sizeof(short)); + ngerr = (short*)malloc((image->width+2)*sizeof(short)); + if (!gerr || !ngerr) { + if (ngerr) + free(ngerr); + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + for (x=0; xwidth; x++) { + gerr[x] = (ptr[x*3]*30 + ptr[x*3+1]*59 + ptr[x*3+2]*11)/100; + } + gerr[x] = 0; + /* convert and dither the image to XImage */ + for (y=0; yheight; y++) { + if (yheight-1) { + int x1; + for (x=0, x1=(y+1)*image->width*3; + xwidth; + x1+=channels-3) { + ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100; + } + /* last column */ + x1-=channels; + ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100; + } + for (x=0; xwidth; x++) { + /* reduce pixel */ + if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0; + + g = table[gerr[x]]; + + /*data[ofs] = ctx->colors[g].pixel;*/ + XPutPixel(ximg->image, x, y, ctx->colors[g].pixel); + /* calc error */ + ger = gerr[x] - g*dg; + + /* distribute error */ + g = (ger*3)/8; + /* x+1, y */ + gerr[x+1]+=g; + /* x, y+1 */ + ngerr[x]+=g; + /* x+1, y+1 */ + ngerr[x+1]+=ger-2*g; + } + /* skip to next line */ + terr = gerr; + gerr = ngerr; + ngerr = terr; + } + free(gerr); + free(ngerr); + } + ximg->image->data = (char*)data; + + return ximg; +} + + +static RXImage* +image2Bitmap(RContext *ctx, RImage *image, int threshold) +{ + RXImage *ximg; + unsigned char *alpha; + int x, y; + + ximg = RCreateXImage(ctx, 1, image->width, image->height); + if (!ximg) { + return NULL; + } + alpha = image->data+3; + + for (y = 0; y < image->height; y++) { + for (x = 0; x < image->width; x++) { + XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1)); + alpha+=4; + } + } + + return ximg; +} + + + +int +RConvertImage(RContext *context, RImage *image, Pixmap *pixmap) +{ + RXImage *ximg=NULL; +#ifdef XSHM + Pixmap tmp; +#endif + + assert(context!=NULL); + assert(image!=NULL); + assert(pixmap!=NULL); + + /* clear error message */ + if (context->vclass == TrueColor) { + + ximg = image2TrueColor(context, image); + + } else if (context->vclass == PseudoColor + || context->vclass == StaticColor) { + +#ifdef BENCH + cycle_bench(1); +#endif + if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) + ximg = image2StandardPseudoColor(context, image); + else + ximg = image2PseudoColor(context, image); +#ifdef BENCH + cycle_bench(0); +#endif + } else if (context->vclass == GrayScale || context->vclass == StaticGray) { + + ximg = image2GrayScale(context, image); + } + + if (!ximg) { + return False; + } + + + *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, + image->height, context->depth); + +#ifdef XSHM + if (context->flags.use_shared_pixmap && ximg->is_shared) + tmp = R_CreateXImageMappedPixmap(context, ximg); + else + tmp = None; + if (tmp) { + /* + * We have to copy the shm Pixmap into a normal Pixmap because + * otherwise, we would have to control when Pixmaps are freed so + * that we can detach their shm segments. This is a problem if the + * program crash, leaving stale shared memory segments in the + * system (lots of them). But with some work, we can optimize + * things and remove this XCopyArea. This will require + * explicitly freeing all pixmaps when exiting or restarting + * wmaker. + */ + XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, + image->width, image->height, 0, 0); + XFreePixmap(context->dpy, tmp); + } else { + RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, + image->width, image->height); + } +#else /* !XSHM */ + RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, + image->width, image->height); +#endif /* !XSHM */ + + RDestroyXImage(context, ximg); + + return True; +} + + +int +RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap, + Pixmap *mask, int threshold) +{ + GC gc; + XGCValues gcv; + RXImage *ximg=NULL; + + assert(context!=NULL); + assert(image!=NULL); + assert(pixmap!=NULL); + assert(mask!=NULL); + + if (!RConvertImage(context, image, pixmap)) + return False; + + if (image->format==RRGBFormat) { + *mask = None; + return True; + } + + ximg = image2Bitmap(context, image, threshold); + + if (!ximg) { + return False; + } + *mask = XCreatePixmap(context->dpy, context->drawable, image->width, + image->height, 1); + gcv.foreground = context->black; + gcv.background = context->white; + gcv.graphics_exposures = False; + gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground + |GCGraphicsExposures, &gcv); + RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, + image->width, image->height); + RDestroyXImage(context, ximg); + + return True; +} + + +Bool +RGetClosestXColor(RContext *context, RColor *color, XColor *retColor) +{ + if (context->vclass == TrueColor) { + unsigned short rmask, gmask, bmask; + unsigned short roffs, goffs, boffs; + unsigned short *rtable, *gtable, *btable; + + roffs = context->red_offset; + goffs = context->green_offset; + boffs = context->blue_offset; + + rmask = context->visual->red_mask >> roffs; + gmask = context->visual->green_mask >> goffs; + bmask = context->visual->blue_mask >> boffs; + + rtable = computeTable(rmask); + gtable = computeTable(gmask); + btable = computeTable(bmask); + + retColor->pixel = (rtable[color->red]<green]<blue]<red = color->red << 8; + retColor->green = color->green << 8; + retColor->blue = color->blue << 8; + retColor->flags = DoRed|DoGreen|DoBlue; + + } else if (context->vclass == PseudoColor + || context->vclass == StaticColor) { + + if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) { + unsigned int *rtable, *gtable, *btable; + + rtable = computeStdTable(context->std_rgb_map->red_mult, + context->std_rgb_map->red_max); + + gtable = computeStdTable(context->std_rgb_map->green_mult, + context->std_rgb_map->green_max); + + btable = computeStdTable(context->std_rgb_map->blue_mult, + context->std_rgb_map->blue_max); + + if (rtable==NULL || gtable==NULL || btable==NULL) { + RErrorCode = RERR_NOMEMORY; + return False; + } + + retColor->pixel = (rtable[color->red] + + gtable[color->green] + + btable[color->blue] + + context->std_rgb_map->base_pixel) & 0xffffffff; + retColor->red = color->red<<8; + retColor->green = color->green<<8; + retColor->blue = color->blue<<8; + retColor->flags = DoRed|DoGreen|DoBlue; + + } else { + const int cpc=context->attribs->colors_per_channel; + const unsigned short rmask = cpc-1; /* different sizes could be used */ + const unsigned short gmask = rmask; /* for r,g,b */ + const unsigned short bmask = rmask; + unsigned short *rtable, *gtable, *btable; + const int cpccpc = cpc*cpc; + int index; + + rtable = computeTable(rmask); + gtable = computeTable(gmask); + btable = computeTable(bmask); + + if (rtable==NULL || gtable==NULL || btable==NULL) { + RErrorCode = RERR_NOMEMORY; + return False; + } + index = rtable[color->red]*cpccpc + gtable[color->green]*cpc + + btable[color->blue]; + *retColor = context->colors[index]; + } + + } else if (context->vclass == GrayScale || context->vclass == StaticGray) { + + const int cpc = context->attribs->colors_per_channel; + unsigned short gmask; + unsigned short *table; + int index; + + if (context->vclass == StaticGray) + gmask = (1<depth) - 1; /* use all grays */ + else + gmask = cpc*cpc*cpc-1; + + table = computeTable(gmask); + if (!table) + return False; + + index = table[(color->red*30 + color->green*59 + color->blue*11)/100]; + + *retColor = context->colors[index]; + } else { + RErrorCode = RERR_INTERNAL; + return False; + } + + return True; +} + diff --git a/Source/x11/draw.c b/Source/x11/draw.c new file mode 100644 index 0000000..246b9c2 --- /dev/null +++ b/Source/x11/draw.c @@ -0,0 +1,605 @@ +/* draw.c - pixel plotting, line drawing + * + * Raster graphics library + * + * Copyright (c) 1998 Dan Pascu + * Copyright (c) 2000 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include + +#include "xrtools.h" + + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + + + +/* + * Returns the color of the pixel at coordinates (x, y) in "color". + */ +Bool +RGetPixel(RImage *image, int x, int y, RColor *color) +{ + int ofs; + + assert(image!=NULL); + if (x < 0 || x >= image->width + || y < 0 || y >= image->height) + return False; + + if (image->format == RRGBAFormat) { + ofs = (y*image->width + x) * 4; + color->red = image->data[ofs]; + color->green = image->data[ofs++]; + color->blue = image->data[ofs++]; + color->alpha = image->data[ofs]; + } else { + ofs = (y*image->width + x) * 3; + color->red = image->data[ofs++]; + color->green = image->data[ofs++]; + color->blue = image->data[ofs++]; + /* If the image does not have alpha channel, we consider alpha 255 */ + color->alpha = 255; + } + + return True; +} + + +void +RPutPixel(RImage *image, int x, int y, RColor *color) +{ + unsigned char *ptr; + + assert(image!=NULL); + assert(color!=NULL); + if (x < 0 || x >= image->width || y < 0 || y >= image->height) + return; + + if (image->format == RRGBAFormat) { + ptr = image->data + (y*image->width + x) * 4; + } else { + ptr = image->data + (y*image->width + x) * 3; + } + + if (color->alpha==255) { + *ptr++ = color->red; + *ptr++ = color->green; + *ptr++ = color->blue; + if (image->format == RRGBAFormat) { + *ptr = 255; + } + } else { + register int alpha, nalpha, r, g, b; + + r = color->red; + g = color->green; + b = color->blue; + alpha = color->alpha; + nalpha = 255 - alpha; + + *ptr++ = (((int)*ptr * nalpha) + (r * alpha))/256; + *ptr++ = (((int)*ptr * nalpha) + (g * alpha))/256; + *ptr++ = (((int)*ptr * nalpha) + (b * alpha))/256; + if (image->format == RRGBAFormat) { + *ptr = alpha + ((int)*ptr * nalpha)/256; + } + } +} + + +static void +operatePixel(RImage *image, int ofs, int operation, RColor *color) +{ + unsigned char *sr, *sg, *sb, *sa; + register int alpha, nalpha, tmp; + int hasAlpha = image->format == RRGBAFormat; + + alpha = color->alpha; + nalpha = 255 - alpha; + + sr = image->data + ofs*(hasAlpha ? 4 : 3); + sg = image->data + ofs*(hasAlpha ? 4 : 3) + 1; + sb = image->data + ofs*(hasAlpha ? 4 : 3) + 2; + sa = image->data + ofs*(hasAlpha ? 4 : 3) + 3; + + switch (operation) { + case RClearOperation: + *sr = 0; + *sg = 0; + *sb = 0; + if (hasAlpha) + *sa = 0; + break; + case RCopyOperation: + *sr = color->red; + *sg = color->green; + *sb = color->blue; + if (hasAlpha) + *sa = color->alpha; + break; + case RNormalOperation: + if (color->alpha==255) { + *sr = color->red; + *sg = color->green; + *sb = color->blue; + if (hasAlpha) + *sa = 255; + } else { + *sr = (((int)*sr * nalpha) + ((int)color->red * alpha))/256; + *sg = (((int)*sg * nalpha) + ((int)color->green * alpha))/256; + *sb = (((int)*sb * nalpha) + ((int)color->blue * alpha))/256; + } + break; + case RAddOperation: + tmp = color->red + *sr; + *sr = MIN(255, tmp); + tmp = color->green + *sg; + *sg = MIN(255, tmp); + tmp = color->blue + *sb; + *sb = MIN(255, tmp); + if (hasAlpha) + *sa = MIN(*sa, color->alpha); + break; + case RSubtractOperation: + tmp = *sr - color->red; + *sr = MAX(0, tmp); + tmp = *sg - color->green; + *sg = MAX(0, tmp); + tmp = *sb - color->blue; + *sb = MAX(0, tmp); + if (hasAlpha) + *sa = MIN(*sa, color->alpha); + break; + } +} + + + +void +ROperatePixel(RImage *image, int operation, int x, int y, RColor *color) +{ + int ofs; + + assert(image!=NULL); + assert(color!=NULL); + assert(x >= 0 && x < image->width); + assert(y >= 0 && y < image->height); + + ofs = y*image->width + x; + + operatePixel(image, ofs, operation, color); +} + + +void +RPutPixels(RImage *image, RPoint *points, int npoints, int mode, RColor *color) +{ + register int x, y, i; + + assert(image!=NULL); + assert(points!=NULL); + + x = y = 0; + + for (i=0; i ymax ? TOP : ((Y) < ymin ? BOT : 0))\ + | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0))) + + int ocode1, ocode2, ocode; + int accept = 0; + int x, y; + + ocode1 = CHECK_OUT(*x1, *y1); + ocode2 = CHECK_OUT(*x2, *y2); + + for(;;) { + if (!ocode1 && !ocode2) { /* completely inside */ + accept = 1; + break; + } else if (ocode1 & ocode2) { + break; + } + + if (ocode1) + ocode = ocode1; + else + ocode = ocode2; + + if (ocode & TOP) { + x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1); + y = ymax; + } else if (ocode & BOT) { + x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1); + y = ymin; + } else if (ocode & RIG) { + y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1); + x = xmax; + } else if (ocode & LEF) { + y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1); + x = xmin; + } + + if (ocode == ocode1) { + *x1 = x; + *y1 = y; + ocode1 = CHECK_OUT(x, y); + } else { + *x2 = x; + *y2 = y; + ocode2 = CHECK_OUT(x, y); + } + } + + return accept; +} + + +/* + * This routine is a generic drawing routine, based on Bresenham's line + * drawing algorithm. + */ +static int +genericLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color, + int operation, int polyline) +{ + int i, err, du, dv, du2, dv2, uofs, vofs, last; + + assert(image!=NULL); + + if (!clipLineInRectangle(0, 0, image->width-1, image->height-1, + &x0, &y0, &x1, &y1)) + return True; + + if (x0 < x1) { + du = x1 - x0; + uofs = 1; + } else { + du = x0 - x1; + uofs = -1; + } + if (y0 < y1) { + dv = y1 -y0; + vofs = image->width; + } else { + dv = y0 - y1; + vofs = -image->width; + } + + if (du < dv) { + /* Swap coordinates between them, so that always du>dv */ + i = du; du = dv; dv = i; + i = uofs; uofs = vofs; vofs = i; + } + + err = 0; + du2 = du<<1; + dv2 = dv<<1; + last = (polyline) ? du-1 : du; + + if (color->alpha==255 || operation==RCopyOperation) { + unsigned char *ptr; + + if (image->format == RRGBAFormat) + i = (y0*image->width + x0) * 4; + else + i = (y0*image->width + x0) * 3; + ptr = image->data + i; + + for (i=0; i<=last; i++) { + /* Draw the pixel */ + *ptr = color->red; + *(ptr+1) = color->green; + *(ptr+2) = color->blue; + if (image->format == RRGBAFormat) + *(ptr+3) = 255; + + /* Compute error for NeXT Step */ + err += dv2; + if (err >= du) { + if (image->format == RRGBAFormat) + ptr += vofs*4; + else + ptr += vofs*3; + err -= du2; + } + if (image->format == RRGBAFormat) + ptr += uofs*4; + else + ptr += uofs*3; + } + } else { + register int ofs = y0*image->width + x0; + + for (i=0; i<=last; i++) { + /* Draw the pixel */ + operatePixel(image, ofs, operation, color); + + /* Compute error for NeXT Step */ + err += dv2; + if (err >= du) { + ofs += vofs; + err -= du2; + } + ofs += uofs; + } + } + +#if 0 + if (mode == RALTER_PIXELS) { + RColorOffset *cdelta = (RColorOffset*)cdata; + register short r, g, b, a; + + for (i=0; i<=last; i++) { + /* Change the pixel with offset */ + r = (short)*sr + cdelta->red; + g = (short)*sg + cdelta->green; + b = (short)*sb + cdelta->blue; + if (r>255) r = 255; else if (r<0) r = 0; + if (g>255) g = 255; else if (g<0) g = 0; + if (b>255) b = 255; else if (b<0) b = 0; + *sr = (unsigned char) r; + *sg = (unsigned char) g; + *sb = (unsigned char) b; + if (image->data[3]) { + a = (short)*sa + cdelta->alpha; + if (a>255) a = 255; else if (a<0) a = 0; + *sa = (unsigned char) a; + } + + /* Compute error for NeXT Step */ + err += dv2; + if (err >= du) { + sr += vofs; sg += vofs; + sb += vofs; sa += vofs; + err -= du2; + } + sr += uofs; sg += uofs; + sb += uofs; sa += uofs; + } + } else { + RColor *color = (RColor*)cdata; + + if (color->alpha==255) { + for (i=0; i<=last; i++) { + /* Draw the pixel */ + *sr = color->red; + *sg = color->green; + *sb = color->blue; + if (image->data[3]) + *sa = 255; + + /* Compute error for NeXT Step */ + err += dv2; + if (err >= du) { + sr += vofs; sg += vofs; + sb += vofs; sa += vofs; + err -= du2; + } + sr += uofs; sg += uofs; + sb += uofs; sa += uofs; + } + } else { + register short alpha, nalpha, r, g ,b; + + alpha = color->alpha; + nalpha = 255 - alpha; + r = color->red; + g = color->green; + b = color->blue; + + for (i=0; i<=last; i++) { + /* Draw the pixel */ + *sr = (((int)*sr * nalpha) + (r * alpha))/256; + *sg = (((int)*sg * nalpha) + (g * alpha))/256; + *sb = (((int)*sb * nalpha) + (b * alpha))/256; + if (image->data[3]) + *sa = alpha + ((int)*sa * nalpha)/256; + + /* Compute error for NeXT Step */ + err += dv2; + if (err >= du) { + sr += vofs; sg += vofs; + sb += vofs; sa += vofs; + err -= du2; + } + sr += uofs; sg += uofs; + sb += uofs; sa += uofs; + } + } + } +#endif + return True; +} + + +int +RDrawLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color) +{ + return genericLine(image, x0, y0, x1, y1, color, RNormalOperation, False); +} + + +int +ROperateLine(RImage *image, int operation, int x0, int y0, int x1, + int y1, RColor *color) +{ + return genericLine(image, x0, y0, x1, y1, color, operation, False); +} + + +void +RDrawLines(RImage *image, RPoint *points, int npoints, int mode, RColor *color) +{ + register int x1, y1, x2, y2, i; + + assert(points!=NULL); + + if (npoints==0) + return; + + x1 = points[0].x; + y1 = points[0].y; + x2 = y2 = 0; + + for (i=1; i1); + genericLine(image, x1, y1, x2, y2, color, RNormalOperation, i); +} + + +void +ROperateLines(RImage *image, int operation, RPoint *points, + int npoints, int mode, RColor *color) +{ + register int x1, y1, x2, y2, i; + + assert(points!=NULL); + + if (npoints==0) + return; + + x1 = points[0].x; + y1 = points[0].y; + x2 = y2 = 0; + + for (i=1; i1); + genericLine(image, x1, y1, x2, y2, color, operation, i); +} + + +void +RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color) +{ + register int i; + + assert(segs!=NULL); + + for (i=0; ix1, segs->y1, segs->x2, segs->y2, color, + RNormalOperation, False); + segs++; + } +} + + +void +ROperateSegments(RImage *image, int operation, RSegment *segs, + int nsegs, RColor *color) +{ + register int i; + + assert(segs!=NULL); + + for (i=0; ix1, segs->y1, segs->x2, segs->y2, color, + operation, False); + segs++; + } +} + diff --git a/Source/x11/gradient.c b/Source/x11/gradient.c new file mode 100644 index 0000000..9d46688 --- /dev/null +++ b/Source/x11/gradient.c @@ -0,0 +1,488 @@ +/* gradient.c - renders gradients + * + * Raster graphics library + * + * Copyright (c) 1997-2000 Alfredo K. Kojima + * Copyright (c) 1998-2000 Dan Pascu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include + +#include + +#include "xrtools.h" + + +static RImage *renderHGradient(unsigned width, unsigned height, + int r0, int g0, int b0, + int rf, int gf, int bf); +static RImage *renderVGradient(unsigned width, unsigned height, + int r0, int g0, int b0, + int rf, int gf, int bf); +static RImage *renderDGradient(unsigned width, unsigned height, + int r0, int g0, int b0, + int rf, int gf, int bf); + +static RImage *renderMHGradient(unsigned width, unsigned height, + RColor **colors, int count); +static RImage *renderMVGradient(unsigned width, unsigned height, + RColor **colors, int count); +static RImage *renderMDGradient(unsigned width, unsigned height, + RColor **colors, int count); + +RImage* +RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, int style) +{ + int count; + + count = 0; + while (colors[count]!=NULL) count++; + + if (count > 2) { + switch (style) { + case RHorizontalGradient: + return renderMHGradient(width, height, colors, count); + case RVerticalGradient: + return renderMVGradient(width, height, colors, count); + case RDiagonalGradient: + return renderMDGradient(width, height, colors, count); + } + } else if (count > 1) { + return RRenderGradient(width, height, colors[0], colors[1], style); + } else if (count > 0) { + return RRenderGradient(width, height, colors[0], colors[0], style); + } + assert(0); + return NULL; +} + + + +RImage* +RRenderGradient(unsigned width, unsigned height, RColor *from, RColor *to, + int style) +{ + switch (style) { + case RHorizontalGradient: + return renderHGradient(width, height, from->red, from->green, + from->blue, to->red, to->green, to->blue); + case RVerticalGradient: + return renderVGradient(width, height, from->red, from->green, + from->blue, to->red, to->green, to->blue); + + case RDiagonalGradient: + return renderDGradient(width, height, from->red, from->green, + from->blue, to->red, to->green, to->blue); + } + assert(0); + return NULL; +} + + +/* + *---------------------------------------------------------------------- + * renderHGradient-- + * Renders a horizontal linear gradient of the specified size in the + * RImage format with a border of the specified type. + * + * Returns: + * A 24bit RImage with the gradient (no alpha channel). + * + * Side effects: + * None + *---------------------------------------------------------------------- + */ +static RImage* +renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, + int rf, int gf, int bf) +{ + int i; + unsigned long r, g, b, dr, dg, db; + RImage *image; + unsigned char *ptr; + + image = RCreateImage(width, height, False); + if (!image) { + return NULL; + } + ptr = image->data; + + r = r0 << 16; + g = g0 << 16; + b = b0 << 16; + + dr = ((rf-r0)<<16)/(int)width; + dg = ((gf-g0)<<16)/(int)width; + db = ((bf-b0)<<16)/(int)width; + /* render the first line */ + for (i=0; i>16); + *(ptr++) = (unsigned char)(g>>16); + *(ptr++) = (unsigned char)(b>>16); + r += dr; + g += dg; + b += db; + } + + /* copy the first line to the other lines */ + for (i=1; idata[i*width*3]), image->data, width*3); + } + return image; +} + + + +/* + *---------------------------------------------------------------------- + * renderVGradient-- + * Renders a vertical linear gradient of the specified size in the + * RImage format with a border of the specified type. + * + * Returns: + * A 24bit RImage with the gradient (no alpha channel). + * + * Side effects: + * None + *---------------------------------------------------------------------- + */ +static RImage* +renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, + int rf, int gf, int bf) +{ + int i, j; + unsigned long r, g, b, dr, dg, db; + RImage *image; + unsigned char *ptr; + unsigned int *iptr; + unsigned char rr, gg, bb; + + image = RCreateImage(width, height, False); + if (!image) { + return NULL; + } + iptr = (unsigned int*)ptr = image->data; + + r = r0<<16; + g = g0<<16; + b = b0<<16; + + dr = ((rf-r0)<<16)/(int)height; + dg = ((gf-g0)<<16)/(int)height; + db = ((bf-b0)<<16)/(int)height; + + for (i=0; i>16; + gg = g>>16; + bb = b>>16; + for (j=0; jdata; + + a = ((float)(width - 1))/((float)(height - 1)); + width = width * 3; + + /* copy the first line to the other lines with corresponding offset */ + for (j=0, offset=0.0; jdata[j]), &ptr[3*(int)offset], width); + offset += a; + } + + RDestroyImage(tmp); + return image; +} + + +static RImage* +renderMHGradient(unsigned width, unsigned height, RColor **colors, int count) +{ + int i, j, k; + unsigned long r, g, b, dr, dg, db; + RImage *image; + unsigned char *ptr; + unsigned width2; + + + assert(count > 2); + + image = RCreateImage(width, height, False); + if (!image) { + return NULL; + } + ptr = image->data; + + if (count > width) + count = width; + + if (count > 1) + width2 = width/(count-1); + else + width2 = width; + + k = 0; + + r = colors[0]->red << 16; + g = colors[0]->green << 16; + b = colors[0]->blue << 16; + + /* render the first line */ + for (i=1; ired - colors[i-1]->red) <<16)/(int)width2; + dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2; + db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2; + for (j=0; j>16); + *ptr++ = (unsigned char)(g>>16); + *ptr++ = (unsigned char)(b>>16); + r += dr; + g += dg; + b += db; + k++; + } + r = colors[i]->red << 16; + g = colors[i]->green << 16; + b = colors[i]->blue << 16; + } + for (j=k; j>16); + *ptr++ = (unsigned char)(g>>16); + *ptr++ = (unsigned char)(b>>16); + } + + /* copy the first line to the other lines */ + for (i=1; idata[i*width*3]), image->data, width*3); + } + return image; +} + + + + +static RImage* +renderMVGradient(unsigned width, unsigned height, RColor **colors, int count) +{ + int i, j, k; + unsigned long r, g, b, dr, dg, db; + RImage *image; + unsigned char *ptr, *tmp; + unsigned height2; + int x; + unsigned char rr, gg, bb; + + + assert(count > 2); + + image = RCreateImage(width, height, False); + if (!image) { + return NULL; + } + ptr = image->data; + + if (count > height) + count = height; + + if (count > 1) + height2 = height/(count-1); + else + height2 = height; + + k = 0; + + r = colors[0]->red << 16; + g = colors[0]->green << 16; + b = colors[0]->blue << 16; + + for (i=1; ired - colors[i-1]->red) <<16)/(int)height2; + dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2; + db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2; + + for (j=0; j>16; + gg = g>>16; + bb = b>>16; + + for (x=0; xred << 16; + g = colors[i]->green << 16; + b = colors[i]->blue << 16; + } + + rr = r>>16; + gg = g>>16; + bb = b>>16; + + if (k 2); + + if (width == 1) + return renderMVGradient(width, height, colors, count); + else if (height == 1) + return renderMHGradient(width, height, colors, count); + + image = RCreateImage(width, height, False); + if (!image) { + return NULL; + } + + if (count > width) + count = width; + if (count > height) + count = height; + + if (count > 2) + tmp = renderMHGradient(2*width-1, 1, colors, count); + else + tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8, + colors[0]->green<<8, colors[0]->blue<<8, + colors[1]->red<<8, colors[1]->green<<8, + colors[1]->blue<<8); + + if (!tmp) { + RDestroyImage(image); + return NULL; + } + ptr = tmp->data; + + a = ((float)(width - 1))/((float)(height - 1)); + width = width * 3; + + /* copy the first line to the other lines with corresponding offset */ + for (j=0, offset=0; jdata[j]), &ptr[3*(int)offset], width); + offset += a; + } + RDestroyImage(tmp); + return image; +} diff --git a/Source/x11/misc.c b/Source/x11/misc.c new file mode 100644 index 0000000..3a6e9c5 --- /dev/null +++ b/Source/x11/misc.c @@ -0,0 +1,221 @@ +/* + * Raster graphics library + * + * Copyright (c) 1997-2000 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include + +#include +#include +#include +#include + +#include "xrtools.h" + + +void +RBevelImage(RImage *image, int bevel_type) +{ + RColor color; + RColor cdelta; + int w, h; + + if (image->width<3 || image->height<3) + return; + + w = image->width; + h = image->height; + if (bevel_type>0) { /* raised */ + /* top */ + cdelta.alpha = 0; + cdelta.red = cdelta.green = cdelta.blue = 80; + ROperateLine(image, RAddOperation, 0, 0, w-1, 0, &cdelta); + if (bevel_type==RBEV_RAISED3 && w>3) + ROperateLine(image, RAddOperation, 1, 1, w-3, 1,&cdelta); + + /* left */ + ROperateLine(image, RAddOperation, 0, 1, 0, h-1, &cdelta); + if (bevel_type==RBEV_RAISED3 && h>3) + ROperateLine(image, RAddOperation, 1, 2, 1, h-3, &cdelta); + + /* bottom */ + color.alpha = 255; + color.red = color.green = color.blue = 0; + cdelta.red = cdelta.green = cdelta.blue = 40; + if (bevel_type==RBEV_RAISED2 || bevel_type==RBEV_RAISED3) { + ROperateLine(image, RSubtractOperation, 0, h-2, w-3, + h-2, &cdelta); + RDrawLine(image, 0, h-1, w-1, h-1, &color); + } else { + ROperateLine(image, RSubtractOperation, 0, h-1, w-1, h-1, + &cdelta); + } + + /* right */ + if (bevel_type==RBEV_RAISED2 || bevel_type==RBEV_RAISED3) { + ROperateLine(image, RSubtractOperation, w-2, 0, w-2, h-2, + &cdelta); + RDrawLine(image, w-1, 0, w-1, h-2, &color); + } else { + ROperateLine(image, RSubtractOperation, w-1, 0, w-1, h-2, + &cdelta); + } + } else { /* sunken */ + cdelta.alpha = 0; + cdelta.red = cdelta.green = cdelta.blue = 40; + ROperateLine(image, RSubtractOperation, 0, 0, w-1, 0, + &cdelta); /* top */ + ROperateLine(image, RSubtractOperation, 0, 1, 0, h-1, + &cdelta); /* left */ + cdelta.red = cdelta.green = cdelta.blue = 80; + ROperateLine(image, RAddOperation, 0, h-1, w-1, h-1, &cdelta); /* bottom */ + ROperateLine(image, RAddOperation, w-1, 0, w-1, h-2, &cdelta); /* right */ + } +} + + +void +RClearImage(RImage *image, RColor *color) +{ + if (image->format == RRGBAFormat) { + unsigned char *d = image->data; + int i; + + for (i = 0; i < image->width; i++) { + *d++ = color->red; + *d++ = color->green; + *d++ = color->blue; + *d++ = color->alpha; + } + for (i = 1; i < image->height; i++, d += image->width*4) { + memcpy(d, image->data, image->width*4); + } + } else { + unsigned char *d = image->data; + int i; + + for (i = 0; i < image->width; i++) { + *d++ = color->red; + *d++ = color->green; + *d++ = color->blue; + } + for (i = 1; i < image->height; i++, d += image->width*3) { + memcpy(d, image->data, image->width*3); + } + } +#if 0 + if (color->alpha==255) { + if (image->format == RRGBAFormat) { + unsigned char *d = image->data; + int i; + + for (i = 0; i < image->width; i++) { + *d++ = color->red; + *d++ = color->green; + *d++ = color->blue; + *d++ = 0xff; + } + for (i = 1; i < image->height; i++, d += image->width*4) { + memcpy(d, image->data, image->width*4); + } + } else { + unsigned char *d = image->data; + int i; + + for (i = 0; i < image->width; i++) { + *d++ = color->red; + *d++ = color->green; + *d++ = color->blue; + } + for (i = 1; i < image->height; i++, d += image->width*3) { + memcpy(d, image->data, image->width*3); + } + } + } else { + int bytes = image->width*image->height; + int i; + unsigned char *d; + int alpha, nalpha, r, g, b; + + d = image->data; + + alpha = color->alpha; + r = color->red * alpha; + g = color->green * alpha; + b = color->blue * alpha; + nalpha = 255 - alpha; + + for (i=0; iformat == RRGBAFormat) { + d++; + } + } + } +#endif +} + +const char* +RMessageForError(int errorCode) +{ + switch (errorCode) { + case RERR_NONE: + return "no error"; + + case RERR_OPEN: + return "could not open file"; + + case RERR_READ: + return "error reading from file"; + + case RERR_WRITE: + return "error writing to file"; + + case RERR_NOMEMORY: + return "out of memory"; + + case RERR_NOCOLOR: + return "out of color cells"; + + case RERR_BADIMAGEFILE: + return "invalid or corrupted image file"; + + case RERR_BADFORMAT: + return "the image format in the file is not supported and can't be loaded"; + + case RERR_BADINDEX: + return "image file does not contain requested image index"; + + case RERR_BADVISUALID: + return "request for an invalid visual ID"; + + case RERR_STDCMAPFAIL: + return "failed to create standard colormap"; + + case RERR_XERROR: + return "internal X error"; + + default: + case RERR_INTERNAL: + return "internal error"; + } +} diff --git a/Source/x11/raster.c b/Source/x11/raster.c new file mode 100644 index 0000000..85cd70a --- /dev/null +++ b/Source/x11/raster.c @@ -0,0 +1,554 @@ +/* raster.c - main and other misc stuff + * + * Raster graphics library + * + * Copyright (c) 1997-2000 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include "xrtools.h" + +#include + + +char *WRasterLibVersion="0.9"; + +int RErrorCode=RERR_NONE; + + +#define HAS_ALPHA(I) ((I)->format == RRGBAFormat) + + +RImage* +RCreateImage(unsigned width, unsigned height, int alpha) +{ + RImage *image=NULL; + + assert(width>0 && height>0); + + image = malloc(sizeof(RImage)); + if (!image) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + + memset(image, 0, sizeof(RImage)); + image->width = width; + image->height = height; + if (alpha) { + image->format = RRGBAFormat; + } else { + image->format = RRGBFormat; + } + /* the +4 is to give extra bytes at the end of the buffer, + * so that we can optimize image conversion for MMX(tm).. see convert.c + */ + image->data = malloc(width * height * (alpha ? 4 : 3) + 4); + if (!image->data) { + RErrorCode = RERR_NOMEMORY; + free(image); + image = NULL; + } + + return image; +} + + + +RImage* +RCloneImage(RImage *image) +{ + RImage *new_image; + + assert(image!=NULL); + + new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image)); + if (!new_image) + return NULL; + + new_image->background = image->background; + memcpy(new_image->data, image->data, + image->width*image->height*(HAS_ALPHA(image) ? 4 : 3)); + + return new_image; +} + + +RImage* +RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height) +{ + int i, ofs; + RImage *new_image; + unsigned total_line_size, line_size; + + assert(image!=NULL); + assert(x>=0 && y>=0); + assert(xwidth && yheight); + assert(width>0 && height>0); + + if (x+width > image->width) + width = image->width-x; + if (y+height > image->height) + height = image->height-y; + + new_image = RCreateImage(width, height, HAS_ALPHA(image)); + + if (!new_image) + return NULL; + new_image->background = image->background; + + total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3); + line_size = width * (HAS_ALPHA(image) ? 4 : 3); + + ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;; + + for (i=0; idata[i*line_size], + &image->data[i*total_line_size+ofs], line_size); + } + return new_image; +} + + +void +RDestroyImage(RImage *image) +{ + assert(image!=NULL); + + free(image->data); + free(image); +} + + +/* + *---------------------------------------------------------------------- + * RCombineImages- + * Combines two equal sized images with alpha image. The second + * image will be placed on top of the first one. + *---------------------------------------------------------------------- + */ +void +RCombineImages(RImage *image, RImage *src) +{ + assert(image->width == src->width); + assert(image->height == src->height); + + if (!HAS_ALPHA(src)) { + if (!HAS_ALPHA(image)) { + memcpy(image->data, src->data, image->height*image->width*3); + } else { + int x, y; + unsigned char *d, *s; + + d = image->data; + s = src->data; + for (y = 0; y < image->height; y++) { + for (x = 0; x < image->width; x++) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + d++; + } + } + } + } else { + register int i; + unsigned char *d; + unsigned char *s; + int alpha, calpha; + + d = image->data; + s = src->data; + + if (!HAS_ALPHA(image)) { + for (i=0; iheight*image->width; i++) { + alpha = *(s+3); + calpha = 255 - alpha; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + d++; s++; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + d++; s++; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + d++; s++; + s++; + } + } else { + for (i=0; iheight*image->width; i++) { + alpha = *(s+3); + calpha = 255 - alpha; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + d++; s++; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + d++; s++; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + d++; s++; + *d++ |= *s++; + } + } + } +} + + + + +void +RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness) +{ + register int i; + unsigned char *d; + unsigned char *s; + int c_opaqueness; + + assert(image->width == src->width); + assert(image->height == src->height); + + d = image->data; + s = src->data; + + c_opaqueness = 255 - opaqueness; +#define OP opaqueness + if (!HAS_ALPHA(src)) { + int dalpha = HAS_ALPHA(image); +#define COP c_opaqueness + for (i=0; i < image->width*image->height; i++) { + *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; + d++; s++; + *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; + d++; s++; + *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; + d++; s++; + if (dalpha) { + d++; + } + } +#undef COP + } else { + int tmp; + + if (!HAS_ALPHA(image)) { + for (i=0; iwidth*image->height; i++) { + tmp = (*(s+3) * opaqueness)/256; + *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; + d++; s++; + *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; + d++; s++; + *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; + d++; s++; + s++; + } + } else { + for (i=0; iwidth*image->height; i++) { + tmp = (*(s+3) * opaqueness)/256; + *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; + d++; s++; + *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; + d++; s++; + *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256; + d++; s++; + *d |= tmp; + d++; s++; + } + } + } +#undef OP +} + + +void +RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width, + unsigned height, int dx, int dy) +{ + int x, y, dwi, swi; + unsigned char *d; + unsigned char *s; + int alpha, calpha; + + + assert(dy < image->height); + assert(dx < image->width); + + assert(sy + height <= src->height); + assert(sx + width <= src->width); + + if (width > image->width - dx) + width = image->width - dx; + + if (height > image->height - dy) + height = image->height - dy; + + if (!HAS_ALPHA(src)) { + if (!HAS_ALPHA(image)) { + swi = src->width * 3; + dwi = image->width * 3; + + s = src->data + (sy*(int)src->width + sx) * 3; + d = image->data + (dy*(int)image->width + dx) * 3; + + for (y=0; y < height; y++) { + memcpy(d, s, width*3); + d += dwi; + s += swi; + } + } else { + swi = (src->width - width) * 3; + dwi = (image->width - width) * 4; + + s = src->data + (sy*(int)src->width + sx) * 3; + d = image->data + (dy*(int)image->width + dx) * 4; + + for (y=0; y < height; y++) { + for (x=0; x < width; x++) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + d++; + } + d += dwi; + s += swi; + } + } + } else { + int dalpha = HAS_ALPHA(image); + + swi = (src->width - width) * 4; + s = src->data + (sy*(int)src->width + sx) * 4; + if (dalpha) { + dwi = (image->width - width) * 4; + d = image->data + (dy*(int)image->width + dx) * 4; + } else { + dwi = (image->width - width) * 3; + d = image->data + (dy*(int)image->width + dx) * 3; + } + + for (y=0; y < height; y++) { + for (x=0; x < width; x++) { + alpha = *(s+3); + calpha = 255 - alpha; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + s++; d++; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + s++; d++; + *d = (((int)*d * calpha) + ((int)*s * alpha))/256; + s++; d++; + s++; + if (dalpha) + d++; + } + d += dwi; + s += swi; + } + } +} + + +void +RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy, + unsigned width, unsigned height, int dx, int dy, + int opaqueness) +{ + int x, y, dwi, swi; + int c_opaqueness; + unsigned char *d; + unsigned char *s; + int dalpha = HAS_ALPHA(image); + int dch = (dalpha ? 4 : 3); + + assert(dy <= image->height); + assert(dx <= image->width); + + assert(sy <= height); + assert(sx <= width); + + + /* clip */ + width -= sx; + height -= sy; + + if (height > image->height - dy) + height = image->height - dy; + + d = image->data + dy*image->width*dch + dx; + dwi = (image->width - width)*dch; + + c_opaqueness = 255 - opaqueness; +#define OP opaqueness + if (!HAS_ALPHA(src)) { +#define COP c_opaqueness + + s = src->data + sy*src->width*3; + swi = (src->width - width) * 3; + + for (y=0; y < height; y++) { + for (x=0; x < width; x++) { + *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; + s++; d++; + *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; + s++; d++; + *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256; + s++; d++; + if (dalpha) + d++; + } + d += dwi; s += swi; + } +#undef COP + } else { + int tmp; + + s = src->data + sy*src->width*4; + swi = (src->width - width) * 4; + + for (y=0; y < height; y++) { + for (x=0; x < width; x++) { + tmp= (*(s+3) * opaqueness)/256; + *d = (((int)*d *(int)(255-tmp)) + ((int)*s *(int)tmp))/256; + d++; s++; + *d = (((int)*d *(int)(255-tmp)) + ((int)*s *(int)tmp))/256; + d++; s++; + *d = (((int)*d *(int)(255-tmp)) + ((int)*s *(int)tmp))/256; + d++; s++; + s++; + if (dalpha) + d++; + } + d += dwi; s += swi; + } + } +#undef OP +} + + + +void +RCombineImageWithColor(RImage *image, RColor *color) +{ + register int i; + unsigned char *d; + int alpha, nalpha, r, g, b; + + d = image->data; + + if (!HAS_ALPHA(image)) { + /* Image has no alpha channel, so we consider it to be all 255. + * Thus there are no transparent parts to be filled. */ + return; + } + r = color->red; + g = color->green; + b = color->blue; + + for (i=0; i < image->width*image->height; i++) { + alpha = *(d+3); + nalpha = 255 - alpha; + + *d = (((int)*d * alpha) + (r * nalpha))/256; + d++; + *d = (((int)*d * alpha) + (g * nalpha))/256; + d++; + *d = (((int)*d * alpha) + (b * nalpha))/256; + d++; + d++; + } +} + + + + +RImage* +RMakeTiledImage(RImage *tile, unsigned width, unsigned height) +{ + int x, y; + unsigned w; + unsigned long tile_size = tile->width * tile->height; + unsigned long tx = 0; + RImage *image; + unsigned char *s, *d; + + if (width == tile->width && height == tile->height) + image = RCloneImage(tile); + else if (width <= tile->width && height <= tile->height) + image = RGetSubImage(tile, 0, 0, width, height); + else { + int has_alpha = HAS_ALPHA(tile); + + image = RCreateImage(width, height, has_alpha); + + d = image->data; + s = tile->data; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x += tile->width) { + + w = (width - x < tile->width) ? width - x : tile->width; + + if (has_alpha) { + w *= 4; + memcpy(d, s+tx*4, w); + } else { + w *= 3; + memcpy(d, s+tx*3, w); + } + d += w; + } + + tx = (tx + tile->width) % tile_size; + } + } + return image; +} + + +RImage* +RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color) +{ + int x, y, w, h, sx, sy; + RImage *tmp; + + tmp = RCreateImage(width, height, False); + if (!tmp) { + return NULL; + } + + RClearImage(tmp, color); + + if (image->height < height) { + h = image->height; + y = (height - h)/2; + sy = 0; + } else { + sy = (image->height - height)/2; + y = 0; + h = height; + } + if (image->width < width) { + w = image->width; + x = (width - w)/2; + sx = 0; + } else { + sx = (image->width - width)/2; + x = 0; + w = width; + } + RCombineArea(tmp, image, sx, sy, w, h, x, y); + + return tmp; +} diff --git a/Source/x11/scale.c b/Source/x11/scale.c new file mode 100644 index 0000000..a536afb --- /dev/null +++ b/Source/x11/scale.c @@ -0,0 +1,623 @@ +/* scale.c - image scaling + * + * Raster graphics library + * + * Copyright (c) 1997, 1988, 1999 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + + +#include +#include +#include +#include +#include + +#ifndef PI +#define PI 3.141592 +#endif + +#include + +#include "xrtools.h" + + +/* + *---------------------------------------------------------------------- + * RScaleImage-- + * Creates a scaled copy of an image. + * + * Returns: + * The new scaled image. + * + *---------------------------------------------------------------------- + */ +#ifndef broken_code +RImage* +RScaleImage(RImage *image, unsigned new_width, unsigned new_height) +{ + int ox; + int px, py; + register int x, y, t; + int dx, dy; + unsigned char *s; + unsigned char *d; + RImage *img; + + assert(new_width >= 0 && new_height >= 0); + + if (new_width == image->width && new_height == image->height) + return RCloneImage(image); + + img = RCreateImage(new_width, new_height, image->format==RRGBAFormat); + + if (!img) + return NULL; + + /* fixed point math idea taken from Imlib by + * Carsten Haitzler (Rasterman) */ + dx = (image->width<<16)/new_width; + dy = (image->height<<16)/new_height; + + py = 0; + + d = img->data; + + if (image->format == RRGBAFormat) { + for (y=0; ywidth*(py>>16); + + s = image->data+(t<<2); /* image->data+t*4 */ + + ox = 0; + px = 0; + for (x=0; x>16; + ox += t<<16; + + s += t<<2; /* t*4 */ + } + py += dy; + } + } else { + for (y=0; ywidth*(py>>16); + + s = image->data+(t<<1)+t; /* image->data+t*3 */ + + ox = 0; + px = 0; + for (x=0; x>16; + ox += t<<16; + + s += (t<<1)+t; /* t*3 */ + } + py += dy; + } + } + + return img; +} + +#else +RImage* +RScaleImage(RImage *src, unsigned new_width, unsigned new_height) +{ + int ddy, ee; + int h2; + int yd; + int xd, xs; + RImage *dst; + int e, xd2; + unsigned char *sr, *sg, *sb, *sa; + unsigned char *dr, *dg, *db, *da; + int ys = 0; + + + + dst = RCreateImage(new_width, new_height, src->data[3]!=NULL); + + ddy = src->height/2; + ee = (ddy/2) - dst->height; + h2 = new_height/2; + + xd = dst->width; + xs = src->width/2; + e = (src->width/2)-xd; + xd2 = xd/2; + + sr = src->data[0]; + sg = src->data[1]; + sb = src->data[2]; + sa = src->data[3]; + + dr = dst->data[0]; + dg = dst->data[1]; + db = dst->data[2]; + da = dst->data[3]; + + if (sa == NULL) { + for (yd = 0; yd < new_height; yd++) { + int x; + + sr = src->data[0] + ys * src->width; + sg = src->data[1] + ys * src->width; + sb = src->data[2] + ys * src->width; + + for (x = 0; x < xd; x++) { + *(dr++) = *sr; + *(dg++) = *sg; + *(db++) = *sb; + + while (e >= 0) { + sr++; + sg++; + sb++; + e -= xd2; + } + e += xs; + } + while (ee >= 0) { + ys++; + ee -= h2; + } + ee += ddy; + } + } else { + for (yd = 0; yd < new_height; yd++) { + int x; + + sr = src->data[0] + ys * src->width; + sg = src->data[1] + ys * src->width; + sb = src->data[2] + ys * src->width; + sa = src->data[3] + ys * src->width; + + for (x = 0; x < xd; x++) { + *(dr++) = *sr; + *(dg++) = *sg; + *(db++) = *sb; + *(da++) = *sa; + + while (e >= 0) { + sr++; + sg++; + sb++; + sa++; + e -= xd2; + } + e += xs; + } + while (ee >= 0) { + ys++; + ee -= h2; + } + ee += ddy; + } + } + + return dst; +} +#endif + + + +/* + * Filtered Image Rescaling code copy/pasted from + * Graphics Gems III + * Public Domain 1991 by Dale Schumacher + */ + + +/* + * filter function definitions + */ +#if 0 +#define filter_support (1.0) + +static double +filter(t) +double t; +{ + /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ + if(t < 0.0) t = -t; + if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0); + return(0.0); +} +#endif +#define box_support (0.5) + +static double +box_filter(t) +double t; +{ + if((t > -0.5) && (t <= 0.5)) return(1.0); + return(0.0); +} + +#define triangle_support (1.0) + +static double +triangle_filter(t) +double t; +{ + if(t < 0.0) t = -t; + if(t < 1.0) return(1.0 - t); + return(0.0); +} + +#define bell_support (1.5) + +static double +bell_filter(t) /* box (*) box (*) box */ +double t; +{ + if(t < 0) t = -t; + if(t < .5) return(.75 - (t * t)); + if(t < 1.5) { + t = (t - 1.5); + return(.5 * (t * t)); + } + return(0.0); +} + +#define B_spline_support (2.0) + +static double +B_spline_filter(t) /* box (*) box (*) box (*) box */ +double t; +{ + double tt; + + if(t < 0) t = -t; + if(t < 1) { + tt = t * t; + return((.5 * tt * t) - tt + (2.0 / 3.0)); + } else if(t < 2) { + t = 2 - t; + return((1.0 / 6.0) * (t * t * t)); + } + return(0.0); +} + +static double +sinc(x) +double x; +{ + x *= PI; + if(x != 0) return(sin(x) / x); + return(1.0); +} + +#define Lanczos3_support (3.0) + +static double +Lanczos3_filter(t) +double t; +{ + if(t < 0) t = -t; + if(t < 3.0) return(sinc(t) * sinc(t/3.0)); + return(0.0); +} + +#define Mitchell_support (2.0) + +#define B (1.0 / 3.0) +#define C (1.0 / 3.0) + +static double +Mitchell_filter(t) +double t; +{ + double tt; + + tt = t * t; + if(t < 0) t = -t; + if(t < 1.0) { + t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + + (6.0 - 2 * B)); + return(t / 6.0); + } else if(t < 2.0) { + t = (((-1.0 * B - 6.0 * C) * (t * tt)) + + ((6.0 * B + 30.0 * C) * tt) + + ((-12.0 * B - 48.0 * C) * t) + + (8.0 * B + 24 * C)); + return(t / 6.0); + } + return(0.0); +} + +static double (*filterf)() = Mitchell_filter; +static double fwidth = Mitchell_support; + +void +_wraster_change_filter(int type) +{ + switch (type) { + case RBoxFilter: + filterf = box_filter; + fwidth = box_support; + break; + case RTriangleFilter: + filterf = triangle_filter; + fwidth = triangle_support; + break; + case RBellFilter: + filterf = bell_filter; + fwidth = bell_support; + break; + case RBSplineFilter: + filterf = B_spline_filter; + fwidth = B_spline_support; + break; + case RLanczos3Filter: + filterf = Lanczos3_filter; + fwidth = Lanczos3_support; + break; + default: + case RMitchellFilter: + filterf = Mitchell_filter; + fwidth = Mitchell_support; + break; + } +} + + +/* + * image rescaling routine + */ + +typedef struct { + int pixel; + double weight; +} CONTRIB; + +typedef struct { + int n; /* number of contributors */ + CONTRIB *p; /* pointer to list of contributions */ +} CLIST; + +CLIST *contrib; /* array of contribution lists */ + +/* clamp the input to the specified range */ +#define CLAMP(v,l,h) ((v)<(l) ? (l) : (v) > (h) ? (h) : v) + + +RImage* +RSmoothScaleImage(RImage *src, unsigned new_width, unsigned new_height) +{ + RImage *tmp; /* intermediate image */ + double xscale, yscale; /* zoom scale factors */ + int i, j, k; /* loop variables */ + int n; /* pixel number */ + double center, left, right; /* filter calculation variables */ + double width, fscale; /* filter calculation variables */ + double rweight, gweight, bweight; + RImage *dst; + unsigned char *p; + unsigned char *sp; + int sch = src->format == RRGBAFormat ? 4 : 3; + + + dst = RCreateImage(new_width, new_height, False); + + /* create intermediate image to hold horizontal zoom */ + tmp = RCreateImage(dst->width, src->height, False); + xscale = (double)new_width / (double)src->width; + yscale = (double)new_height / (double)src->height; + + /* pre-calculate filter contributions for a row */ + contrib = (CLIST *)calloc(new_width, sizeof(CLIST)); + if (xscale < 1.0) { + width = fwidth / xscale; + fscale = 1.0 / xscale; + for (i = 0; i < new_width; ++i) { + contrib[i].n = 0; + contrib[i].p = (CONTRIB *)calloc((int)(width * 2 + 1), + sizeof(CONTRIB)); + center = (double) i / xscale; + left = ceil(center - width); + right = floor(center + width); + for(j = left; j <= right; ++j) { + rweight = center - (double) j; + rweight = (*filterf)(rweight / fscale) / fscale; + if(j < 0) { + n = -j; + } else if(j >= src->width) { + n = (src->width - j) + src->width - 1; + } else { + n = j; + } + k = contrib[i].n++; + contrib[i].p[k].pixel = n*sch; + contrib[i].p[k].weight = rweight; + } + } + } else { + + for(i = 0; i < new_width; ++i) { + contrib[i].n = 0; + contrib[i].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), + sizeof(CONTRIB)); + center = (double) i / xscale; + left = ceil(center - fwidth); + right = floor(center + fwidth); + for(j = left; j <= right; ++j) { + rweight = center - (double) j; + rweight = (*filterf)(rweight); + if(j < 0) { + n = -j; + } else if(j >= src->width) { + n = (src->width - j) + src->width - 1; + } else { + n = j; + } + k = contrib[i].n++; + contrib[i].p[k].pixel = n*sch; + contrib[i].p[k].weight = rweight; + } + } + } + + /* apply filter to zoom horizontally from src to tmp */ + p = tmp->data; + + + for(k = 0; k < tmp->height; ++k) { + CONTRIB *pp; + + sp = src->data + src->width*k*sch; + + for(i = 0; i < tmp->width; ++i) { + rweight = gweight = bweight = 0.0; + + pp = contrib[i].p; + + for(j = 0; j < contrib[i].n; ++j) { + rweight += sp[pp[j].pixel] * pp[j].weight; + gweight += sp[pp[j].pixel+1] * pp[j].weight; + bweight += sp[pp[j].pixel+2] * pp[j].weight; + } + *p++ = CLAMP(rweight, 0, 255); + *p++ = CLAMP(gweight, 0, 255); + *p++ = CLAMP(bweight, 0, 255); + } + } + + /* free the memory allocated for horizontal filter weights */ + for(i = 0; i < tmp->width; ++i) { + free(contrib[i].p); + } + free(contrib); + + /* pre-calculate filter contributions for a column */ + contrib = (CLIST *)calloc(dst->height, sizeof(CLIST)); + if(yscale < 1.0) { + width = fwidth / yscale; + fscale = 1.0 / yscale; + for(i = 0; i < dst->height; ++i) { + contrib[i].n = 0; + contrib[i].p = (CONTRIB *)calloc((int) (width * 2 + 1), + sizeof(CONTRIB)); + center = (double) i / yscale; + left = ceil(center - width); + right = floor(center + width); + for(j = left; j <= right; ++j) { + rweight = center - (double) j; + rweight = (*filterf)(rweight / fscale) / fscale; + if(j < 0) { + n = -j; + } else if(j >= tmp->height) { + n = (tmp->height - j) + tmp->height - 1; + } else { + n = j; + } + k = contrib[i].n++; + contrib[i].p[k].pixel = n*3; + contrib[i].p[k].weight = rweight; + } + } + } else { + for(i = 0; i < dst->height; ++i) { + contrib[i].n = 0; + contrib[i].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), + sizeof(CONTRIB)); + center = (double) i / yscale; + left = ceil(center - fwidth); + right = floor(center + fwidth); + for(j = left; j <= right; ++j) { + rweight = center - (double) j; + rweight = (*filterf)(rweight); + if(j < 0) { + n = -j; + } else if(j >= tmp->height) { + n = (tmp->height - j) + tmp->height - 1; + } else { + n = j; + } + k = contrib[i].n++; + contrib[i].p[k].pixel = n*3; + contrib[i].p[k].weight = rweight; + } + } + } + + /* apply filter to zoom vertically from tmp to dst */ + sp = malloc(tmp->height*3); + + for(k = 0; k < new_width; ++k) { + CONTRIB *pp; + + p = dst->data + k*3; + + /* copy a column into a row */ + { + int i; + unsigned char *p, *d; + + d = sp; + for(i = tmp->height, p = tmp->data + k*3; i-- > 0; + p += tmp->width*3) { + *d++ = *p; + *d++ = *(p+1); + *d++ = *(p+2); + } + } + for(i = 0; i < new_height; ++i) { + rweight = gweight = bweight = 0.0; + + pp = contrib[i].p; + + for(j = 0; j < contrib[i].n; ++j) { + rweight += sp[pp[j].pixel] * pp[j].weight; + gweight += sp[pp[j].pixel+1] * pp[j].weight; + bweight += sp[pp[j].pixel+2] * pp[j].weight; + } + *p = CLAMP(rweight, 0, 255); + *(p+1) = CLAMP(gweight, 0, 255); + *(p+2) = CLAMP(bweight, 0, 255); + p += new_width*3; + } + } + free(sp); + + /* free the memory allocated for vertical filter weights */ + for(i = 0; i < dst->height; ++i) { + free(contrib[i].p); + } + free(contrib); + + RDestroyImage(tmp); + + return dst; +} + diff --git a/Source/x11/xdnd.c b/Source/x11/xdnd.c new file mode 100644 index 0000000..62d5543 --- /dev/null +++ b/Source/x11/xdnd.c @@ -0,0 +1,395 @@ +/* + xdnd.c, xdnd.h - C program library for handling the Xdnd protocol + + Copyright (C) 1998 Paul Sheer + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + + http://www.cco.caltech.edu/~jafl/xdnd/ + + Further info can also be obtained by emailing the author at, + psheer@obsidian.co.za + + Released 1998-08-07 +*/ + +#include +#include +#include +#include +#include +#include +#include "x11/xdnd.h" + + +// #define DND_DEBUG +#define dnd_version_at_least(a,b) ((a) <= (b)) + +#ifdef DND_DEBUG +#define dnd_debug(a,b...) printf("%s: %d: " a "\n", __FILE__, __LINE__ , ## b) +#else + +#ifdef NeXT_RUNTIME +#define dnd_debug // +#else /* !NeXT_RUNTIME */ +#define dnd_debug(a,b...) +#endif /* NeXT_RUNTIME */ + +#endif + + + +void +xdnd_reset(DndClass * dnd) +{ + dnd->stage = XDND_DROP_STAGE_IDLE; + dnd->dragging_version = 0; + dnd->internal_drag = 0; + dnd->want_position = 0; + dnd->ready_to_drop = 0; + dnd->will_accept = 0; + dnd->rectangle.x = dnd->rectangle.y = 0; + dnd->rectangle.width = dnd->rectangle.height = 0; + dnd->dropper_window = 0; + dnd->dragger_window = 0; + dnd->dragger_typelist = 0; + dnd->desired_type = 0; + dnd->time = 0; +} + +void +xdnd_init(DndClass * dnd, Display * display) +{ + memset (dnd, 0, sizeof (*dnd)); + + dnd->display = display; + dnd->root_window = DefaultRootWindow (display); + dnd->version = XDND_VERSION; + dnd->XdndAware = XInternAtom (dnd->display, "XdndAware", False); + dnd->XdndSelection = XInternAtom (dnd->display, "XdndSelection", False); + dnd->XdndEnter = XInternAtom (dnd->display, "XdndEnter", False); + dnd->XdndLeave = XInternAtom (dnd->display, "XdndLeave", False); + dnd->XdndPosition = XInternAtom (dnd->display, "XdndPosition", False); + dnd->XdndDrop = XInternAtom (dnd->display, "XdndDrop", False); + dnd->XdndFinished = XInternAtom (dnd->display, "XdndFinished", False); + dnd->XdndStatus = XInternAtom (dnd->display, "XdndStatus", False); + dnd->XdndActionCopy = XInternAtom (dnd->display, "XdndActionCopy", False); + dnd->XdndActionMove = XInternAtom (dnd->display, "XdndActionMove", False); + dnd->XdndActionLink = XInternAtom (dnd->display, "XdndActionLink", False); + dnd->XdndActionAsk = XInternAtom (dnd->display, "XdndActionAsk", False); + dnd->XdndActionPrivate=XInternAtom(dnd->display,"XdndActionPrivate",False); + dnd->XdndTypeList = XInternAtom (dnd->display, "XdndTypeList", False); + dnd->XdndActionList = XInternAtom (dnd->display, "XdndActionList", False); + dnd->XdndActionDescription = XInternAtom(dnd->display, + "XdndActionDescription", False); + xdnd_reset(dnd); +} + +static int +array_length(Atom * a) +{ // typelist is a null terminated array + int n = 0; + + while (a[n]) + n++; + return n; +} + +void +xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist) +{ + XChangeProperty (dnd->display, window, dnd->XdndAware, XA_ATOM, 32, + PropModeReplace, (unsigned char *) &dnd->version, 1); + if (typelist) + { + int n = array_length (typelist); + if (n) + XChangeProperty (dnd->display, window, dnd->XdndAware, XA_ATOM, 32, + PropModeAppend, (unsigned char *) typelist, n); + } +} + +int +xdnd_is_dnd_aware(DndClass *dnd, Window window, int *version, Atom *typelist) +{ + Atom actual; + int format; + unsigned long count, remaining; + unsigned char *data = 0; + Atom *types, *t; + int result = 1; + + *version = 0; + XGetWindowProperty (dnd->display, window, dnd->XdndAware, + 0, 0x8000000L, False, XA_ATOM, &actual, &format, + &count, &remaining, &data); + + if (actual != XA_ATOM || format != 32 || count == 0 || !data) + { + dnd_debug("XGetWindowProperty failed in xdnd_is_dnd_aware - XdndAware = %ld", dnd->XdndAware); + if (data) + XFree(data); + return 0; + } + + types = (Atom *) data; + *version = dnd->version < types[0] ? dnd->version : types[0]; // minimum + dnd_debug ("Using XDND version %d", *version); + if (count > 1) + { + result = 0; + for (t = typelist; *t; t++) + { + int j; + for (j = 1; j < count; j++) + { + if (types[j] == *t) + { + result = 1; + break; + } + } + if (result) + break; + } + } + XFree(data); + return result; +} + +void +xdnd_send_enter(DndClass *dnd, Window window, Window from, Atom *typelist) +{ + XEvent xevent; + int n, i; + + n = array_length (typelist); + + memset(&xevent, 0, sizeof (xevent)); + + xevent.xany.type = ClientMessage; + xevent.xany.display = dnd->display; + xevent.xclient.window = window; + xevent.xclient.message_type = dnd->XdndEnter; + xevent.xclient.format = 32; + + XDND_ENTER_SOURCE_WIN (&xevent) = from; + XDND_ENTER_THREE_TYPES_SET (&xevent, n > XDND_THREE); + XDND_ENTER_VERSION_SET (&xevent, dnd->version); + for (i = 0; i < n && i < XDND_THREE; i++) + { + XDND_ENTER_TYPE (&xevent, i) = typelist[i]; + } + + XSendEvent (dnd->display, window, 0, 0, &xevent); +} + +void +xdnd_send_position(DndClass *dnd, Window window, Window from, Atom action, + int x, int y, unsigned long time) +{ + XEvent xevent; + + memset (&xevent, 0, sizeof (xevent)); + + xevent.xany.type = ClientMessage; + xevent.xany.display = dnd->display; + xevent.xclient.window = window; + xevent.xclient.message_type = dnd->XdndPosition; + xevent.xclient.format = 32; + + XDND_POSITION_SOURCE_WIN (&xevent) = from; + XDND_POSITION_ROOT_SET (&xevent, x, y); + if (dnd_version_at_least (dnd->dragging_version, 1)) + XDND_POSITION_TIME (&xevent) = time; + if (dnd_version_at_least (dnd->dragging_version, 2)) + XDND_POSITION_ACTION (&xevent) = action; + + XSendEvent (dnd->display, window, 0, 0, &xevent); +} + +void +xdnd_send_status(DndClass *dnd, Window window, Window from, int will_accept, + int want_position, int x, int y, int w, int h, Atom action) +{ + XEvent xevent; + + memset (&xevent, 0, sizeof (xevent)); + + xevent.xany.type = ClientMessage; + xevent.xany.display = dnd->display; + xevent.xclient.window = window; + xevent.xclient.message_type = dnd->XdndStatus; + xevent.xclient.format = 32; + + XDND_STATUS_TARGET_WIN (&xevent) = from; + XDND_STATUS_WILL_ACCEPT_SET (&xevent, will_accept); + if (will_accept) + XDND_STATUS_WANT_POSITION_SET (&xevent, want_position); + if (want_position) + XDND_STATUS_RECT_SET (&xevent, x, y, w, h); + if (dnd_version_at_least (dnd->dragging_version, 2)) + if (will_accept) + XDND_STATUS_ACTION (&xevent) = action; + + XSendEvent (dnd->display, window, 0, 0, &xevent); +} + +void +xdnd_send_leave(DndClass *dnd, Window window, Window from) +{ + XEvent xevent; + + memset(&xevent, 0, sizeof (xevent)); + + xevent.xany.type = ClientMessage; + xevent.xany.display = dnd->display; + xevent.xclient.window = window; + xevent.xclient.message_type = dnd->XdndLeave; + xevent.xclient.format = 32; + + XDND_LEAVE_SOURCE_WIN (&xevent) = from; + + XSendEvent (dnd->display, window, 0, 0, &xevent); +} + +void +xdnd_send_drop(DndClass *dnd, Window window, Window from, unsigned long time) +{ + XEvent xevent; + + memset (&xevent, 0, sizeof (xevent)); + + xevent.xany.type = ClientMessage; + xevent.xany.display = dnd->display; + xevent.xclient.window = window; + xevent.xclient.message_type = dnd->XdndDrop; + xevent.xclient.format = 32; + + XDND_DROP_SOURCE_WIN (&xevent) = from; + if (dnd_version_at_least (dnd->dragging_version, 1)) + XDND_DROP_TIME (&xevent) = time; + + XSendEvent (dnd->display, window, 0, 0, &xevent); +} + +void +xdnd_send_finished(DndClass * dnd, Window window, Window from, int error) +{ + XEvent xevent; + memset (&xevent, 0, sizeof (xevent)); + xevent.xany.type = ClientMessage; + xevent.xany.display = dnd->display; + xevent.xclient.window = window; + xevent.xclient.message_type = dnd->XdndFinished; + xevent.xclient.format = 32; + + XDND_FINISHED_TARGET_WIN (&xevent) = from; + + XSendEvent (dnd->display, window, 0, 0, &xevent); +} + +int +xdnd_convert_selection(DndClass *dnd, Window window, Window requester, Atom type) +{ + if (window != XGetSelectionOwner (dnd->display, dnd->XdndSelection)) + { + dnd_debug ("xdnd_convert_selection(): XGetSelectionOwner failed"); + return 1; + } + + XConvertSelection (dnd->display, dnd->XdndSelection, type, + dnd->Xdnd_NON_PROTOCOL_ATOM, requester, CurrentTime); + return 0; +} + +int +xdnd_set_selection_owner(DndClass * dnd, Window window, Atom type) +{ + if (!XSetSelectionOwner(dnd->display,dnd->XdndSelection,window,CurrentTime)) + { + dnd_debug ("xdnd_set_selection_owner(): XSetSelectionOwner failed"); + return 1; + } + + return 0; +} + +void +xdnd_selection_send(DndClass * dnd, XSelectionRequestEvent * request, + unsigned char *data, int length) +{ + XEvent xevent; + + dnd_debug (" requestor = %ld", request->requestor); + dnd_debug (" property = %ld", request->property); + dnd_debug (" length = %d", length); + + XChangeProperty (dnd->display, request->requestor, request->property, + request->target, 8, PropModeReplace, data, length); + + xevent.xselection.type = SelectionNotify; + xevent.xselection.property = request->property; + xevent.xselection.display = request->display; + xevent.xselection.requestor = request->requestor; + xevent.xselection.selection = request->selection; + xevent.xselection.target = request->target; + xevent.xselection.time = request->time; + + XSendEvent (dnd->display, request->requestor, 0, 0, &xevent); +} + +// +// Unused +// + +void +xdnd_set_type_list(DndClass * dnd, Window window, Atom * typelist) +{ + int n = array_length (typelist); + + XChangeProperty (dnd->display, window, dnd->XdndTypeList, XA_ATOM, 32, + PropModeReplace, (unsigned char *) typelist, n); +} + +/* result must be free'd */ +void +xdnd_get_type_list(DndClass * dnd, Window window, Atom ** typelist) +{ + Atom type, *a; + int format, i; + unsigned long count, remaining; + unsigned char *data = NULL; + + *typelist = 0; + + XGetWindowProperty (dnd->display, window, dnd->XdndTypeList, + 0, 0x8000000L, False, XA_ATOM, &type, &format, &count, &remaining, &data); + + if (type != XA_ATOM || format != 32 || count == 0 || !data) + { + if (data) + XFree (data); + dnd_debug ("XGetWindowProperty failed in xdnd_get_type_list - dnd->XdndTypeList = %ld", dnd->XdndTypeList); + return; + } + *typelist = malloc ((count + 1) * sizeof (Atom)); + a = (Atom *) data; + for (i = 0; i < count; i++) + (*typelist)[i] = a[i]; + (*typelist)[count] = 0; + + XFree (data); +} diff --git a/Source/x11/xutil.c b/Source/x11/xutil.c new file mode 100644 index 0000000..97ac552 --- /dev/null +++ b/Source/x11/xutil.c @@ -0,0 +1,284 @@ +/* xutil.c - utility functions for X + * + * Raster graphics library + * + * Copyright (c) 1997 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + + +#include +#include +#include +#include +#include + +#include + +#ifdef XSHM +#include +#include +#endif /* XSHM */ + +#include "xrtools.h" + + +#ifdef XSHM + +static int shmError; + +static int (*oldErrorHandler)(); + +static int +errorHandler(Display *dpy, XErrorEvent *err) +{ + shmError=1; + if(err->error_code!=BadAccess) + (*oldErrorHandler)(dpy, err); + + return 0; +} + + +#endif + + +RXImage* +RCreateXImage(RContext *context, int depth, unsigned width, unsigned height) +{ + RXImage *rximg; + Visual *visual = context->visual; + + rximg = malloc(sizeof(RXImage)); + if (!rximg) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + +#ifndef XSHM + rximg->image = XCreateImage(context->dpy, visual, depth, + ZPixmap, 0, NULL, width, height, 8, 0); + if (!rximg->image) { + free(rximg); + RErrorCode = RERR_XERROR; + return NULL; + } + rximg->image->data = malloc(rximg->image->bytes_per_line*height); + if (!rximg->image->data) { + XDestroyImage(rximg->image); + free(rximg); + RErrorCode = RERR_NOMEMORY; + return NULL; + } + +#else /* XSHM */ + if (!context->attribs->use_shared_memory) { + retry_without_shm: + + context->attribs->use_shared_memory = 0; + rximg->is_shared = 0; + rximg->image = XCreateImage(context->dpy, visual, depth, + ZPixmap, 0, NULL, width, height, 8, 0); + if (!rximg->image) { + free(rximg); + RErrorCode = RERR_XERROR; + return NULL; + } + rximg->image->data = malloc(rximg->image->bytes_per_line*height); + if (!rximg->image->data) { + XDestroyImage(rximg->image); + free(rximg); + RErrorCode = RERR_NOMEMORY; + return NULL; + } + } else { + rximg->is_shared = 1; + + rximg->info.readOnly = False; + + rximg->image = XShmCreateImage(context->dpy, visual, depth, + ZPixmap, NULL, &rximg->info, width, + height); + + rximg->info.shmid = shmget(IPC_PRIVATE, + rximg->image->bytes_per_line*height, + IPC_CREAT|0777); + if (rximg->info.shmid < 0) { + context->attribs->use_shared_memory = 0; + perror("wrlib:could not allocate shared memory segment"); + XDestroyImage(rximg->image); + goto retry_without_shm; + } + + rximg->info.shmaddr = shmat(rximg->info.shmid, 0, 0); + if (rximg->info.shmaddr == (void*)-1) { + context->attribs->use_shared_memory = 0; + if (shmctl(rximg->info.shmid, IPC_RMID, 0) < 0) + perror("wrlib:shmctl"); + perror("wrlib:could not allocate shared memory"); + XDestroyImage(rximg->image); + goto retry_without_shm; + } + + shmError = 0; + XSync(context->dpy, False); + oldErrorHandler = XSetErrorHandler(errorHandler); + XShmAttach(context->dpy, &rximg->info); + XSync(context->dpy, False); + XSetErrorHandler(oldErrorHandler); + + rximg->image->data = rximg->info.shmaddr; +/* rximg->image->obdata = &(rximg->info);*/ + + if (shmError) { + context->attribs->use_shared_memory = 0; + XDestroyImage(rximg->image); + if (shmdt(rximg->info.shmaddr) < 0) + perror("wrlib:shmdt"); + if (shmctl(rximg->info.shmid, IPC_RMID, 0) < 0) + perror("wrlib:shmctl"); +/* printf("wrlib:error attaching shared memory segment to XImage\n"); + */ + goto retry_without_shm; + } + } +#endif /* XSHM */ + + return rximg; +} + + +void +RDestroyXImage(RContext *context, RXImage *rximage) +{ +#ifndef XSHM + XDestroyImage(rximage->image); +#else /* XSHM */ + if (rximage->is_shared) { + XSync(context->dpy, False); + XShmDetach(context->dpy, &rximage->info); + XDestroyImage(rximage->image); + if (shmdt(rximage->info.shmaddr) < 0) + perror("wrlib:shmdt"); + if (shmctl(rximage->info.shmid, IPC_RMID, 0) < 0) + perror("wrlib:shmctl"); + } else { + XDestroyImage(rximage->image); + } +#endif + free(rximage); +} + + +static unsigned +getDepth(Display *dpy, Drawable d) +{ + Window w; + int foo; + unsigned bar; + unsigned depth; + + XGetGeometry(dpy, d, &w, &foo, &foo, &bar, &bar, &bar, &depth); + + return depth; +} + + + +RXImage* +RGetXImage(RContext *context, Drawable d, int x, int y, + unsigned width, unsigned height) +{ + RXImage *ximg = NULL; + +#ifdef XSHM + if (context->attribs->use_shared_memory && 0) { + ximg = RCreateXImage(context, getDepth(context->dpy, d), + width, height); + + if (ximg && !ximg->is_shared) { + RDestroyXImage(context, ximg); + ximg = NULL; + } + if (ximg) { + XShmGetImage(context->dpy, d, ximg->image, x, y, AllPlanes); + } + } + if (!ximg) { + ximg = malloc(sizeof(RXImage)); + if (!ximg) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + ximg->is_shared = 0; + ximg->image = XGetImage(context->dpy, d, x, y, width, height, + AllPlanes, ZPixmap); + } + return ximg; +#else /* !XSHM */ + ximg = malloc(sizeof(RXImage)); + if (!ximg) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + + ximg->image = XGetImage(context->dpy, d, x, y, width, height, + AllPlanes, ZPixmap); + + return ximg; +#endif /* !XSHM */ +} + + +void +RPutXImage(RContext *context, Drawable d, GC gc, RXImage *ximage, int src_x, + int src_y, int dest_x, int dest_y, + unsigned int width, unsigned int height) +{ +#ifndef XSHM + XPutImage(context->dpy, d, gc, ximage->image, src_x, src_y, dest_x, + dest_y, width, height); +#else + if (ximage->is_shared) { + XShmPutImage(context->dpy, d, gc, ximage->image, src_x, src_y, + dest_x, dest_y, width, height, False); + } else { + XPutImage(context->dpy, d, gc, ximage->image, src_x, src_y, dest_x, + dest_y, width, height); + } + XFlush(context->dpy); +#endif /* XSHM */ +} + + +#ifdef XSHM +Pixmap +R_CreateXImageMappedPixmap(RContext *context, RXImage *rximage) +{ + Pixmap pix; + + pix = XShmCreatePixmap(context->dpy, context->drawable, + rximage->image->data, &rximage->info, + rximage->image->width, rximage->image->height, + rximage->image->depth); + + return pix; +} + +#endif /* XSHM */ + diff --git a/Source/xdps/AFMFileFontInfo.h b/Source/xdps/AFMFileFontInfo.h new file mode 100644 index 0000000..a1e908e --- /dev/null +++ b/Source/xdps/AFMFileFontInfo.h @@ -0,0 +1,88 @@ +/* + AFMFileFontInfo.h + + Private data of PXKFont class. + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: February 1997 + + This file is part of the GNUstep GUI X/DPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#ifndef __AFMFileFontInfo_h__ +#define __AFMFileFontInfo_h__ + +#include +#include +#include "parseAFM.h" + +typedef struct { + NSGlyph glyph; + NSSize advancement; +} tPairKerningInfo; + +@interface PXKFontEnumerator : GSFontEnumerator +{ +} +@end + +@interface AFMGlyphInfo : NSObject +{ + NSString* name; + NSGlyph code; + NSRect bbox; + NSSize advancement; + int lastKernPair; + int numOfPairs; + tPairKerningInfo* kerning; +} + ++ (AFMGlyphInfo*) glyphFromAFMCharMetricInfo: (AFMCharMetricInfo*)metricInfo; + +- (AFMGlyphInfo*)mutableCopyWithZone: (NSZone*)zone; + +- (NSString*) name; +- (NSGlyph) code; +- (NSRect) boundingRect; +- (NSSize) advancement; +- (BOOL) isEncoded; + +- (void) transformUsingMatrix: (const float*)matrix; + +- (void) incrementNumberOfKernPairs; +- (void) addPairKerningForGlyph:(NSGlyph)glyph advancement:(NSSize)advancement; +- (NSSize) advancementIfFollowedByGlyph: (NSGlyph)glyph + isNominal: (BOOL*)nominal; + +@end + + +@interface AFMFileFontInfo : GSFontInfo +{ + NSString *afmFileName; + NSMapTable *glyphsByName; + AFMGlyphInfo *glyphs[256]; +} + +- (AFMFileFontInfo*)mutableCopyWithZone: (NSZone*)zone; +- (AFMFileFontInfo*)initUnscaledWithFontName: (NSString*)name; +@end + +#endif /* __AFMFileFontInfo_h__ */ + diff --git a/Source/xdps/AFMFileFontInfo.m b/Source/xdps/AFMFileFontInfo.m new file mode 100644 index 0000000..a793846 --- /dev/null +++ b/Source/xdps/AFMFileFontInfo.m @@ -0,0 +1,810 @@ +/* + AFMFileFontInfo.m + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: February 1997 + + This file is part of the GNUstep GUI X/DPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include +#include +#include + +#include +#include +#include +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "xdps/NSDPSContext.h" +#include "AFMFileFontInfo.h" +#include "general.h" +#include "fonts.h" + +/* This dictionary keeps global font info objects indexed by AFM file names. + A global font info instance is the representation of AFM file; all the + dimensions are in the 1x1 space not in the 1000x1000 space of the AFM file. + Each font object maintains a copy of this instance with all the dimensions + scaled to the font size. */ +static NSMutableDictionary* globalFontInfoDictionary = nil; + +static NSMutableDictionary* globalFileDictionary = nil; + +#ifndef LIB_FOUNDATION_LIBRARY +/* Define callbacks for a map table that has cStrings as keys */ + +/* hpjw from Aho, Sethi & Ullman: Principles of compiler design. */ +static unsigned __NSHashCString(void *table, const void *aString) +{ + register const char* p = (char*)aString; + register unsigned hash = 0, hash2; + register int i, n = strlen((char*)aString); + + for(i=0; i < n; i++) { + hash <<= 4; + hash += *p++; + if((hash2 = hash & 0xf0000000)) + hash ^= (hash2 >> 24) ^ hash2; + } + return hash; +} + +static BOOL __NSCompareCString(void *table, + const void *anObject1, const void *anObject2) +{ + return strcmp((char*)anObject1, (char*)anObject2) == 0; +} + +static void __NSRetainNothing(void *table, const void *anObject) +{ +} + +static void __NSReleaseNothing(void *table, void *anObject) +{ +} + +static NSString* __NSDescribePointers(void *table, const void *anObject) +{ + return [NSString stringWithCString:anObject]; +} + +static const NSMapTableKeyCallBacks NSNonOwnedCStringMapKeyCallBacks = { + (unsigned(*)(NSMapTable*, const void*))__NSHashCString, + (BOOL(*)(NSMapTable*, const void*, const void*))__NSCompareCString, + (void (*)(NSMapTable*, const void* anObject))__NSRetainNothing, + (void (*)(NSMapTable*, void* anObject))__NSReleaseNothing, + (NSString *(*)(NSMapTable*, const void*))__NSDescribePointers, + (const void *)NULL +}; +#endif /* LIB_FOUNDATION_LIBRARY */ + +static int +afmEnumerator (char* resourceType, char* resourceName, char* resourceFile, + char* fontsList) +{ + NSString* afmFileName = [NSString stringWithCString: resourceFile]; + [(NSMutableArray*)fontsList addObject: afmFileName]; + return 0; +} + +@implementation AFMFileFontInfo + ++ (void)initialize +{ + static BOOL initialized = NO; + + if (!initialized) { + initialized = YES; + globalFontInfoDictionary = [NSMutableDictionary new]; + globalFileDictionary = [NSMutableDictionary new]; + } +} + +- (NSString *) _getFontResource +{ + NSString* fontFile; + DPSContext ctxt; + char font_file[FILENAME_MAX + 1]; + + ctxt = [(NSDPSContext *)GSCurrentContext() xDPSContext]; + + + fontFile = nil; + PSWGetFontFile(ctxt, [fontName cString], font_file); + if (strncmp(font_file, "/Resource", 9) == 0) + { + char completePath[FILENAME_MAX + 1]; + int found; + /* We're using GS which returns files differently */ + PSWGSFontFile(ctxt, [fontName cString], font_file); + PSWCompleteFilename (font_file, &found, completePath); + if (found) + { + fontFile = [NSString stringWithCString: completePath]; + fontFile = [[fontFile stringByDeletingPathExtension] + stringByAppendingPathExtension:@"afm"]; + } + } + else if (font_file[0] != '/') + { + /* Can't handle this yet, try the Adobe way... */ + NSMutableArray *fontsList = [[NSMutableArray new] autorelease]; + NSDebugLLog(@"Fonts", @"Font file resource returned relative-path %s", + font_file); + EnumeratePSResourceFiles (NULL, NULL, PSResFontAFM, [fontName cString], + afmEnumerator, (char*)fontsList); + if (![fontsList count]) + NSLog (@"WARNING: Font file not found! Check if the PSRESOURCEPATH " + @"environment variable points to the right directory. If so then " + @"probably you did not build the PS resource database using the " + @"`makepsres' utility."); + else + fontFile = [fontsList objectAtIndex: 0]; + } + + if (fontFile) + NSDebugLLog(@"Fonts", @"Found AFM file %@ for font %@", fontFile, fontName); + return fontFile; +} + +- _setFontInfo +{ + NSAutoreleasePool* pool; + AFMFontInfo* cFontInfo; + AFMGlobalFontInfo* gfi; + int fontType; + FILE* file; + int i, code; + NSString *sweight; + + afmFileName = [globalFileDictionary objectForKey: fontName]; + if (afmFileName == nil) + { + afmFileName = [self _getFontResource]; + if (afmFileName == nil) + { + NSLog (@"No AFM file for font %@. Can't get font info", fontName); + return nil; + } + [globalFileDictionary setObject: afmFileName forKey: fontName]; + } + RETAIN(afmFileName); + + if (![[NSFileManager defaultManager] isReadableFileAtPath: afmFileName]) + { + NSLog (@"Cannot read AFM file %@ for font %@", afmFileName, fontName); + return nil; + } + + file = fopen ([afmFileName cString], "r"); + if (!file) + { + NSLog (@"Cannot open AFM file %@ for font %@", afmFileName, fontName); + return nil; + } + + code = AFMParseFile (file, &cFontInfo, AFM_G | AFM_M | AFM_P); + if (code != afm_ok) { + switch (code) { + case afm_parseError: + NSLog (@"parse error in AFM file %@", afmFileName); + break; + case afm_earlyEOF: + NSLog (@"unexpected EOF in AFM file %@", afmFileName); + break; + case afm_storageProblem: + NSLog (@"memory allocation problem while parsing the AFM file %@", + afmFileName); + break; + } + fclose (file); + return nil; + } + fclose (file); + + gfi = cFontInfo->gfi; + + pool = [NSAutoreleasePool new]; + + /* + * Set the font information in instance variables and in the AFM dictionary. + */ + + /* The font may actually be a GS alias, so do not set the fontName + * field. */ + // fontName = [[NSString stringWithCString:gfi->fontName] retain]; + [fontDictionary setObject: fontName forKey: NSAFMFontName]; + + familyName = [[NSString stringWithCString:gfi->familyName] retain]; + [fontDictionary setObject: familyName forKey: NSAFMFamilyName]; + + italicAngle = gfi->italicAngle; + [fontDictionary setObject: [NSNumber numberWithFloat:gfi->italicAngle] + forKey: NSAFMItalicAngle]; + + sweight = [NSString stringWithCString:gfi->weight]; + [fontDictionary setObject: sweight forKey: NSAFMWeight]; + + underlinePosition = ((float)gfi->underlinePosition) / 1000; + [fontDictionary setObject: [NSNumber numberWithFloat:underlinePosition] + forKey: NSAFMUnderlinePosition]; + + underlineThickness = ((float)gfi->underlineThickness) / 1000; + [fontDictionary setObject: [NSNumber numberWithFloat:underlineThickness] + forKey: NSAFMUnderlineThickness]; + + capHeight = ((float)gfi->capHeight) / 1000; + [fontDictionary setObject: [NSNumber numberWithFloat:capHeight] + forKey: NSAFMCapHeight]; + + xHeight = ((float)gfi->xHeight) / 1000; + [fontDictionary setObject: [NSNumber numberWithFloat:xHeight] + forKey: NSAFMXHeight]; + + descender = ((float)gfi->descender) / 1000; + [fontDictionary setObject: [NSNumber numberWithFloat:descender] + forKey: NSAFMDescender]; + + ascender = ((float)gfi->ascender) / 1000; + [fontDictionary setObject: [NSNumber numberWithFloat:ascender] + forKey: NSAFMAscender]; + + encodingScheme = [[NSString stringWithCString:gfi->encodingScheme] + retain]; + [fontDictionary setObject: encodingScheme forKey: NSAFMEncodingScheme]; + + [fontDictionary setObject: [NSString stringWithCString:gfi->afmVersion] + forKey: NSAFMFormatVersion]; + [fontDictionary setObject:[NSString stringWithCString:gfi->notice] + forKey: NSAFMNotice]; + [fontDictionary setObject:[NSString stringWithCString:gfi->version] + forKey: NSAFMVersion]; + + /* Setup bbox as expected by NSFont */ + fontBBox.origin.x = ((float)gfi->fontBBox.llx) / 1000; + fontBBox.origin.y = ((float)gfi->fontBBox.lly) / 1000; + fontBBox.size.width + = ((float)(gfi->fontBBox.urx - gfi->fontBBox.llx)) / 1000; + fontBBox.size.height + = ((float)(gfi->fontBBox.ury - gfi->fontBBox.lly)) / 1000; + + isFixedPitch = gfi->isFixedPitch; + + /* Get the font type from the DGS server */ + PSWGetFontType ([fontName cString], &fontType); + isBaseFont = (fontType != 0); + + maximumAdvancement.width = FLT_MIN; + maximumAdvancement.height = FLT_MIN; + minimumAdvancement.width = FLT_MAX; + minimumAdvancement.height = FLT_MAX; + + /* Fill in the glyphs arrays. */ + glyphsByName = NSCreateMapTable (NSNonOwnedCStringMapKeyCallBacks, + NSObjectMapValueCallBacks, 256); + for (i = 0; i < cFontInfo->numOfChars; i++) { + AFMCharMetricInfo charMetricInfo = cFontInfo->cmi[i]; + AFMGlyphInfo* glyph + = [AFMGlyphInfo glyphFromAFMCharMetricInfo:&charMetricInfo]; + NSSize glyphAdvancement = [glyph advancement]; + + NSMapInsert (glyphsByName, [[glyph name] cString], glyph); + maximumAdvancement.width + = MAX (maximumAdvancement.width, glyphAdvancement.width); + maximumAdvancement.height + = MAX (maximumAdvancement.height, glyphAdvancement.height); + minimumAdvancement.width + = MIN (minimumAdvancement.width, glyphAdvancement.width); + minimumAdvancement.height + = MIN (minimumAdvancement.height, glyphAdvancement.height); + if (charMetricInfo.code > 0) { + glyphs[charMetricInfo.code] = [glyph retain]; + } + } + + /* Set the entries in the kerning array for all the glyphs in the pair + kerning array. */ + { + AFMGlyphInfo* glyph1 = nil; + AFMGlyphInfo* glyph2 = nil; + const char* previousGlyphName = ""; + AFMPairKernData pkd; + NSSize advancement; + + /* First compute the numbers of kern pairs for each glyph. This is used to + avoid unnecessary allocations of kern pair arrays in glyph objects. */ + for (i = 0; i < cFontInfo->numOfPairs; i++) { + pkd = cFontInfo->pkd[i]; + + /* Check the name of the first glyph. Use a hint here: the kern pairs are + grouped on the first glyph. */ + if (strcmp (pkd.name1, previousGlyphName)) { + previousGlyphName = pkd.name1; + glyph1 = NSMapGet (glyphsByName, pkd.name1); + } + [glyph1 incrementNumberOfKernPairs]; + } + + /* Now set the pair kerns in glyphs. */ + for (i = 0; i < cFontInfo->numOfPairs; i++) { + pkd = cFontInfo->pkd[i]; + + if (strcmp (pkd.name1, previousGlyphName)) { + previousGlyphName = pkd.name1; + glyph1 = NSMapGet (glyphsByName, pkd.name1); + } + + glyph2 = NSMapGet (glyphsByName, pkd.name2); + + if (!glyph1) { + NSLog (@"unknown glyph name %s in AFM file %@", pkd.name1, afmFileName); + continue; + } + if (!glyph2) { + NSLog (@"unknown glyph name %s in AFM file %@", pkd.name2, afmFileName); + continue; + } + + advancement = NSMakeSize (pkd.xamt, pkd.yamt); + [glyph1 addPairKerningForGlyph:[glyph2 code] advancement:advancement]; + } + } + + /* Free the cFontInfo structure */ + free (gfi->afmVersion); + free (gfi->fontName); + free (gfi->fullName); + free (gfi->familyName); + free (gfi->weight); + free (gfi->version); + free (gfi->notice); + free (gfi->encodingScheme); + for (i = 0; i < cFontInfo->numOfChars; i++) { + AFMCharMetricInfo cmi = cFontInfo->cmi[i]; + free (cmi.name); + } + for (i = 0; i < cFontInfo->numOfPairs; i++) { + AFMPairKernData pkd = cFontInfo->pkd[i]; + free (pkd.name1); + free (pkd.name2); + } + free (cFontInfo); + + [pool release]; + + return self; +} + +- (void) transformUsingMatrix: (const float*)fmatrix +{ + float a = fmatrix[0]; + float b = fmatrix[1]; + float c = fmatrix[2]; + float d = fmatrix[3]; + float tx = fmatrix[4]; + float ty = fmatrix[5]; + float x1, y1, width1, height1; + int i; + + memcpy(matrix, fmatrix, sizeof(matrix)); + + for (i = 0; i < 256; i++) { + [glyphs[i] transformUsingMatrix: fmatrix]; + } + + x1 = fontBBox.origin.x; + y1 = fontBBox.origin.y; + width1 = fontBBox.size.width; + height1 = fontBBox.size.height; + fontBBox.origin.x = a * x1 + c * y1 + tx; + fontBBox.origin.y = b * x1 + d * y1 + ty; + fontBBox.size.width = a * width1 + c * height1; + fontBBox.size.height = b * width1 + d * height1; + + width1 = maximumAdvancement.width; + height1 = maximumAdvancement.height; + maximumAdvancement.width = a * width1 + c * height1; + maximumAdvancement.height = b * width1 + d * height1; + + width1 = minimumAdvancement.width; + height1 = minimumAdvancement.height; + minimumAdvancement.width = a * width1 + c * height1; + minimumAdvancement.height = b * width1 + d * height1; + + underlinePosition = a * underlinePosition + tx; + underlineThickness = a * underlineThickness + tx; + capHeight = a * capHeight + tx; + ascender = a * ascender + tx; + descender = a * descender + tx; + + xHeight = a * xHeight + tx; +} + +- (AFMFileFontInfo *) transformedFontInfoForMatrix: (const float *)fmatrix +{ + AFMFileFontInfo *new = [self mutableCopy]; + [new transformUsingMatrix: fmatrix]; + return AUTORELEASE(new); +} + +- initUnscaledWithFontName: (NSString*)name +{ + AFMFileFontInfo *fontInfo; + + /* Check whether the font info is cached */ + fontInfo = [globalFontInfoDictionary objectForKey: name]; + if(fontInfo != nil) + { + RELEASE(self); + // retain to act like we were alloc'd + return RETAIN(fontInfo); + } + /* Tough. Parse the AFM file and create a new font info for + the unscaled font. */ + [super init]; + fontName = RETAIN(name); + if ([self _setFontInfo] == nil) + { + RELEASE(self); + return nil; + } + /* Cache the font info for later use */ + [globalFontInfoDictionary setObject: self forKey: fontName]; + + return self; +} + +- initWithFontName: (NSString*)name matrix: (const float *)fmatrix +{ + AFMFileFontInfo *fontInfo, *baseFontInfo; + + RELEASE(self); + /* Grab an unscaled font info and create a new scaled one. */ + baseFontInfo = [[AFMFileFontInfo alloc] initUnscaledWithFontName: name]; + if(baseFontInfo == nil) + { + return nil; + } + fontInfo = [baseFontInfo transformedFontInfoForMatrix: fmatrix]; + RELEASE(baseFontInfo); + RETAIN(fontInfo); + + return fontInfo; +} + +- (void) dealloc +{ + int i; + + /* Don't free the glyphsByName map table. It is owned by the first font info + object that is never freed. */ + for (i = 0; i < 256; i++) + TEST_RELEASE(glyphs[i]); + + TEST_RELEASE(afmFileName); + [super dealloc]; +} + +- (void)set +{ + if ([[GSCurrentContext() focusView] isFlipped]) + { + float invmatrix[6]; + memcpy(invmatrix, matrix, sizeof(invmatrix)); + invmatrix[3] = -invmatrix[3]; + PSWSetFont ([fontName cString], invmatrix); + } + else + PSWSetFont ([fontName cString], matrix); +} + +- (NSString*)afmFileContents +{ + return [NSString stringWithContentsOfFile: afmFileName]; +} + +- copyWithZone: (NSZone *)zone +{ + AFMFileFontInfo* new; + if (NSShouldRetainWithZone(self, zone)) + new = RETAIN(self); + else + { + int i; + new = [super copyWithZone: zone]; + for (i = 0; i < 256; i++) { + new->glyphs[i] = [glyphs[i] copyWithZone: zone]; + } + new->afmFileName = [afmFileName copyWithZone: zone]; + } + return new; +} + +- mutableCopyWithZone: (NSZone *)zone +{ + int i; + AFMFileFontInfo* new = [super mutableCopyWithZone: zone]; + for (i = 0; i < 256; i++) { + new->glyphs[i] = [glyphs[i] mutableCopyWithZone: zone]; + } + new->afmFileName = [afmFileName copyWithZone: zone]; + + return new; +} + +- (NSSize)advancementForGlyph:(NSGlyph)glyph +{ + return [glyphs[glyph] advancement]; +} + +- (NSRect)boundingRectForGlyph:(NSGlyph)glyph +{ + return [glyphs[glyph] boundingRect]; +} + +- (BOOL)glyphIsEncoded:(NSGlyph)glyph +{ + return [glyphs[glyph] isEncoded]; +} + +- (NSGlyph)glyphWithName:(NSString*)glyphName +{ + AFMGlyphInfo* glyph = NSMapGet (glyphsByName, [glyphName cString]); + + return glyph ? [glyph code] : -1; +} + +- (NSPoint)positionOfGlyph:(NSGlyph)curGlyph + precededByGlyph:(NSGlyph)prevGlyph + isNominal:(BOOL*)nominal +{ + NSPoint point; + NSSize size; + + if (curGlyph == NSControlGlyph || prevGlyph == NSControlGlyph + || curGlyph < 0 || curGlyph > 255 || prevGlyph < 0 || prevGlyph >255) { + if (nominal) + *nominal = NO; + return NSZeroPoint; + } + + if (curGlyph == NSNullGlyph) { + size = [glyphs[prevGlyph] advancement]; + point.x = size.width; + point.y = size.height; + if (nominal) + *nominal = NO; + return point; + } + + if (glyphs[prevGlyph]) { + if (!glyphs[curGlyph]) { + point.x = maximumAdvancement.width; + point.y = maximumAdvancement.height; + if (nominal) + *nominal = NO; + return point; + } + size = [glyphs[prevGlyph] advancementIfFollowedByGlyph: + [glyphs[curGlyph] code] + isNominal:nominal]; + point.x = size.width; + point.y = size.height; + return point; + } + return NSZeroPoint; +} + +- (float)widthOfString:(NSString*)string +{ + /* TODO: We should really map here the characters from string to + series of glyphs. Until then we consider the glyphs to be + equivalent with characters. */ + + int i, length = [string length]; + const char* cString = [string cString]; + float width = 0; + + for (i = 0; i < length; i++) { + width += [glyphs[(int)cString[i]] advancement].width; + } + + return width; +} + +@end /* AFMFileFontInfo */ + + +@implementation AFMGlyphInfo + ++ (AFMGlyphInfo*)glyphFromAFMCharMetricInfo:(AFMCharMetricInfo*)mi +{ + AFMGlyphInfo* glyph = [[self new] autorelease]; + + glyph->name = [[NSString stringWithCString:mi->name] retain]; + glyph->code = mi->code; + + /* Setup bbox as defined by NSRect */ + glyph->bbox.origin.x = ((float)mi->charBBox.llx) / 1000; + glyph->bbox.origin.y = ((float)mi->charBBox.lly) / 1000; + glyph->bbox.size.width = ((float)mi->charBBox.urx - mi->charBBox.llx) / 1000; + glyph->bbox.size.height = ((float)mi->charBBox.ury - mi->charBBox.lly)/ 1000; + + glyph->advancement.width = ((float)mi->wx) / 1000; + glyph->advancement.height = ((float)mi->wy) / 1000; + + return glyph; +} + +- (void)transformUsingMatrix:(const float*)matrix; +{ + float a = matrix[0]; + float b = matrix[1]; + float c = matrix[2]; + float d = matrix[3]; + float tx = matrix[4]; + float ty = matrix[5]; + float x1 = bbox.origin.x; + float y1 = bbox.origin.y; + float width1 = bbox.size.width; + float height1 = bbox.size.height; + int i; + + bbox.origin.x = a * x1 + c * y1 + tx; + bbox.origin.y = b * x1 + d * y1 + ty; + bbox.size.width = a * width1 + c * height1; + bbox.size.height = b * width1 + d * height1; + + x1 = advancement.width; + y1 = advancement.height; + advancement.width = a * x1 + c * y1 + tx; + advancement.height = b * x1 + d * y1 + ty; + + for (i = 0; i < numOfPairs; i++) { + x1 = kerning[i].advancement.width; + y1 = kerning[i].advancement.height; + kerning[i].advancement.width = a * x1 + c * y1 + tx; + kerning[i].advancement.height = b * x1 + d * y1 + ty; + } +} + +- (void)incrementNumberOfKernPairs +{ + numOfPairs++; +} + +- (void)addPairKerningForGlyph:(NSGlyph)glyph advancement:(NSSize)_advancement +{ + tPairKerningInfo kernInfo = { + glyph, + { advancement.width + ((float)_advancement.width) / 1000, + advancement.height + ((float)_advancement.height) / 1000 + } + }; + int i; + + if (kerning == NULL) + kerning = malloc (numOfPairs * sizeof (tPairKerningInfo)); + + /* Insert the glyph in the proper position in the kerning array so this will + be sorted ascending after the glyph code. */ + for (i = 0; i < lastKernPair; i++) + if (kerning[i].glyph > glyph) { + /* Make room for a new kerning pair in this position. */ + memmove (&kerning[i + 1], &kerning[i], + (lastKernPair - i) * sizeof (tPairKerningInfo)); + break; + } + + kerning[i] = kernInfo; + lastKernPair++; +} + +- (NSSize)advancementIfFollowedByGlyph:(NSGlyph)glyph + isNominal:(BOOL*)nominal +{ + /* Search for the glyph using a binary search algorithm */ + int lower = 0; + int upper = numOfPairs; + int midpoint; + + if (!kerning) { + if (nominal) + *nominal = NO; + return advancement; + } + + while (upper >= lower) { + midpoint = (lower + upper) / 2; + if (kerning[midpoint].glyph == glyph) { + if (nominal) + *nominal = YES; + return kerning[midpoint].advancement; + } + else if (kerning[midpoint].glyph > glyph) + upper = midpoint - 1; + else if (kerning[midpoint].glyph < glyph) + lower = midpoint + 1; + } + + /* The glyph was not found in the kernings array. Return the advancement of + receiver. */ + if (nominal) + *nominal = NO; + return advancement; +} + +- copyWithZone: (NSZone *)zone +{ + AFMGlyphInfo *copy; + if (NSShouldRetainWithZone(self, zone)) + copy = RETAIN(self); + else + { + copy = (AFMGlyphInfo*) NSCopyObject (self, 0, zone); + copy->name = [name copyWithZone: zone]; + if (kerning) + { + copy->kerning = malloc (numOfPairs * sizeof (tPairKerningInfo)); + memcpy (copy->kerning, kerning, + numOfPairs * sizeof (tPairKerningInfo)); + } + } + return copy; +} + +- mutableCopyWithZone: (NSZone *)zone +{ + AFMGlyphInfo *copy; + copy = (AFMGlyphInfo*) NSCopyObject (self, 0, zone); + copy->name = [name copyWithZone: zone]; + if (kerning) + { + copy->kerning = malloc (numOfPairs * sizeof (tPairKerningInfo)); + memcpy (copy->kerning, kerning, + numOfPairs * sizeof (tPairKerningInfo)); + } + return copy; +} + +- (void)dealloc +{ + RELEASE(name); + if (kerning) + free (kerning); + [super dealloc]; +} + +- (NSString*)name { return name; } +- (NSGlyph)code { return code; } +- (NSRect)boundingRect { return bbox; } +- (NSSize)advancement { return advancement; } +- (BOOL)isEncoded { return YES; } + +@end /* AFMGlyphInfo */ diff --git a/Source/xdps/GNUmakefile b/Source/xdps/GNUmakefile new file mode 100644 index 0000000..7c2bdaa --- /dev/null +++ b/Source/xdps/GNUmakefile @@ -0,0 +1,66 @@ +# +# Main makefile for GNUstep Backend xdps +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# If you are interested in a warranty or support for this source code, +# contact Scott Christley at scottc@net-community.com +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../back.make +include $(GNUSTEP_MAKEFILES)/common.make + +SUBPROJECT_NAME=xdps + +# The pswrap source files to be compiled +xdps_PSWRAP_FILES = \ +general.psw \ +drawingfuncs.psw \ +extensions.psw \ +fonts.psw + +# The C source files to be compiled +xdps_C_FILES = \ +parseAFM.c + +# The Objective-C source files to be compiled +xdps_OBJC_FILES = \ +AFMFileFontInfo.m \ +NSDPSContext.m \ +NSDPSContextOps.m \ +PXKFontManager.m + +xdps_HEADER_FILES_DIR = ../../Headers/xdps +xdps_HEADER_FILES_INSTALL_DIR = gnustep/xdps + +xdps_HEADER_FILES = \ +NSDPSContext.h + +-include GNUmakefile.preamble + +include $(GNUSTEP_MAKEFILES)/subproject.make + +-include GNUmakefile.postamble + diff --git a/Source/xdps/GNUmakefile.preamble b/Source/xdps/GNUmakefile.preamble new file mode 100644 index 0000000..f211065 --- /dev/null +++ b/Source/xdps/GNUmakefile.preamble @@ -0,0 +1,53 @@ +# +# GNUmakefile.preamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +GNUSTEP_INSTALL_LIBDIR=$(GNUSTEP_LIBRARIES_ROOT) +ADDITIONAL_CPPFLAGS += -Wall $(CONFIG_SYSTEM_DEFS) + +# Additional flags to pass to the Objective-C compiler +#ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +#ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I../../Headers \ + -I../$(GNUSTEP_TARGET_DIR) + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# + + diff --git a/Source/xdps/NSDPSContext.m b/Source/xdps/NSDPSContext.m new file mode 100644 index 0000000..21639b6 --- /dev/null +++ b/Source/xdps/NSDPSContext.m @@ -0,0 +1,764 @@ +/* + NSDPSContext.m + + Encapsulation of Display Postscript contexts + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "x11/XGServer.h" +#include "xdps/NSDPSContext.h" + +#define BOOL XWINDOWSBOOL +#include +#include +#undef BOOL + +#ifdef HAVE_WRASTER_H +#include "wraster.h" +#else +#include "x11/wraster.h" +#endif + +#include "general.h" +#include "extensions.h" +#include "drawingfuncs.h" +#include "AFMFileFontInfo.h" + +// +// DPS exceptions +// +NSString *DPSPostscriptErrorException = @"DPSPostscriptErrorException"; +NSString *DPSNameTooLongException = @"DPSNameTooLongException"; +NSString *DPSResultTagCheckException = @"DPSResultTagCheckException"; +NSString *DPSResultTypeCheckException = @"DPSResultTypeCheckException"; +NSString *DPSInvalidContextException = @"DPSInvalidContextException"; +NSString *DPSSelectException = @"DPSSelectException"; +NSString *DPSConnectionClosedException = @"DPSConnectionClosedException"; +NSString *DPSReadException = @"DPSReadException"; +NSString *DPSWriteException = @"DPSWriteException"; +NSString *DPSInvalidFDException = @"DPSInvalidFDException"; +NSString *DPSInvalidTEException = @"DPSInvalidTEException"; +NSString *DPSInvalidPortException = @"DPSInvalidPortException"; +NSString *DPSOutOfMemoryException = @"DPSOutOfMemoryException"; +NSString *DPSCantConnectException = @"DPSCantConnectException"; + +#define XDPY (((RContext *)context)->dpy) +#define XDRW (((RContext *)context)->drawable) + +enum { + A_COEFF = 0, + B_COEFF, + C_COEFF, + D_COEFF, + TX_CONS, + TY_CONS +}; + +// +// Class variables +// +static BOOL GNU_CONTEXT_TRACED = NO; +static BOOL GNU_CONTEXT_SYNCHRONIZED = NO; + +static NSDPSContext *context_list = nil; +static FILE *gstream = NULL; + +/* Text handler for text contexts */ +static void +GNUstepOutputTextProc (DPSContext ctxt, char *buf, long unsigned int count) +{ + /* FIXME: If there's a possibility of having more than one text context + we should have some simple hash to determine what stream to write to */ + if (gstream) + fwrite(buf, 1, count, gstream); + else + DPSDefaultTextBackstop (ctxt, buf, count); +} + +/* Text handler for screen contexts */ +static void +GNUstepTextProc (DPSContext ctxt, char *buf, long unsigned int count) +{ + DPSDefaultTextBackstop (ctxt, buf, count); +} + +/* Error handler for all types of contexts */ +static void +GNUstepErrorProc (DPSContext ctxt, DPSErrorCode errCode, + unsigned arg1, unsigned args) +{ + DPSDefaultErrorProc (ctxt, errCode, arg1, arg1); +} + +@interface NSDPSContext (Private) +- (void) createDPSContext; +- (void) createTextContext; +@end + +@implementation NSDPSContext + ++ (void)initialize +{ + if (self == [NSDPSContext class]) + { + // Set initial version + [self setVersion: 1]; + + GNU_CONTEXT_TRACED = NO; + GNU_CONTEXT_SYNCHRONIZED = NO; + } +} + +/* Initialize AppKit backend */ ++ (void)initializeBackend +{ + NSDebugLog(@"Initializing GNUstep GUI X/DPS Backend.\n"); + [NSGraphicsContext setDefaultContextClass: [NSDPSContext class]]; + [GSFontEnumerator setDefaultClass: [PXKFontEnumerator class]]; + [GSFontInfo setDefaultClass: [AFMFileFontInfo class]]; +} + ++ (void) setCurrentContext: (NSGraphicsContext *)aContext +{ + [super setCurrentContext: aContext]; + DPSSetContext([(NSDPSContext *)aContext xDPSContext]); +} + +// +// Initializing a Context +// +- init +{ + return [self initWithContextInfo: nil]; +} + +- (id) initWithContextInfo: (NSDictionary *)info +{ + NSString *contextType; + + [super initWithContextInfo: info]; + + /* A context is only associated with one server. Do not retain + the server, however */ + server = GSCurrentServer(); + + chained_parent = nil; + chained_child = nil; + contextType = [info objectForKey: + NSGraphicsContextRepresentationFormatAttributeName]; + if (contextType && [contextType isEqual: NSGraphicsContextPSFormat]) + { + NSString *path; + is_screen_context = NO; + error_proc = GNUstepErrorProc; + text_proc = GNUstepOutputTextProc; + path = [info objectForKey: @"NSOutputFile"]; + if (path == nil) + { + NSLog(@"Warning: No path set for stream context, default temp.ps"); + path = @"temp.ps"; + } + gstream = fopen([path cString], "w"); + if (gstream == NULL) + { + NSLog(@"Error: Could not open output path for stream context"); + } + } + else + { + is_screen_context = YES; + error_proc = GNUstepErrorProc; + text_proc = GNUstepTextProc; + } + + context = [self xrContext]; + if (is_screen_context && !XDPSExtensionPresent(XDPY)) + { +#if HAVE_DPS_DPSNXARGS_H + /* Make it possible for this client to start a DPS NX agent */ + XDPSNXSetClientArg(XDPSNX_AUTO_LAUNCH, (void *)True); +#else + NSLog (@"DPS extension not in server!"); + exit (1); +#endif + } + + /* + * Create the context + */ + if (is_screen_context) + { + [self createDPSContext]; + } + else + { + [self createTextContext]; + } + + if (dps_context == NULL) + { + [self dealloc]; + return nil; + } + + /* Add context to global list of contexts */ + next_context = context_list; + context_list = self; + + if (GSDebugSet(@"NSDPSContext") == YES) + { + NSLog(@"NSDPSContext: Tracing Postscript \n"); + [self setOutputTraced: YES]; + } + + return self; +} + +- (void)dealloc +{ + DESTROY(chained_child); + + DPSDestroySpace(DPSSpaceFromContext(dps_context)); + if (is_screen_context == 0) + { + if (gstream) + fclose(gstream); + } + /* Remove context from global list of contexts */ + { + NSDPSContext *ctxt = context_list, *previous=nil; + + while(ctxt) + { + if(ctxt == self) + break; + previous = ctxt; + ctxt = ctxt->next_context; + } + if(!ctxt) + NSLog(@"Internal Error: Couldn't find context to delete"); + else + { + if(previous) + previous->next_context = next_context; + else + context_list = next_context; + } + } + [super dealloc]; +} + +// +// Testing the Drawing Destination +// +- (BOOL)isDrawingToScreen +{ + return is_screen_context; +} + +- (NSDPSContext *)DPSContext +{ + return self; +} + +- (void)wait +{ + DPSWaitContext (dps_context); +} + ++ (void) waitAllContexts +{ + NSDPSContext *ctxt; + ctxt = context_list; + while(ctxt) + { + [ctxt wait]; + ctxt = ctxt->next_context; + } +} + +// +// Managing Returned Text and Errors +// ++ (NSString *)stringForDPSError:(const DPSBinObjSeqRec *)error +{ + return nil; +} + +- (DPSErrorProc)errorProc +{ + return error_proc; +} + +- (void)setErrorProc:(DPSErrorProc)proc +{ + error_proc = proc; +} + +- (void)setTextProc:(DPSTextProc)proc +{ + text_proc = proc; +} + +- (DPSTextProc)textProc +{ + return text_proc; +} + +// +// Managing Chained Contexts +// +- (void)setParentContext:(NSDPSContext *)parent +{ + chained_parent = parent; +} + +- (void)chainChildContext:(NSDPSContext *)child +{ + if (child) + { + chained_child = [child retain]; + [child setParentContext: self]; + } +} + +- (NSDPSContext *)childContext +{ + return chained_child; +} + +- (NSDPSContext *)parentContext +{ + return chained_parent; +} + +- (void)unchainContext +{ + if (chained_child) + { + [chained_child setParentContext: nil]; + [chained_child release]; + chained_child = nil; + } +} + +// +// Debugging Aids +// ++ (BOOL)areAllContextsOutputTraced +{ + return GNU_CONTEXT_TRACED; +} + ++ (BOOL)areAllContextsSynchronized +{ + return GNU_CONTEXT_SYNCHRONIZED; +} + ++ (void)setAllContextsOutputTraced:(BOOL)flag +{ + GNU_CONTEXT_TRACED = flag; +} + ++ (void)setAllContextsSynchronized:(BOOL)flag +{ + GNU_CONTEXT_SYNCHRONIZED = flag; +} + +- (BOOL)isOutputTraced +{ + return is_output_traced; +} + +- (BOOL)isSynchronized +{ + return is_synchronized; +} + +- (void)setOutputTraced:(BOOL)flag +{ + is_output_traced = flag; + XDPSChainTextContext(dps_context, flag); +} + +- (void)setSynchronized:(BOOL)flag +{ + is_synchronized = flag; +} + +@end + +// +// Methods for XWindows implementation +// +@implementation NSDPSContext (GNUstepXDPS) + +- (Display*)xDisplay +{ + if (is_screen_context) + return [(XGServer *)server xDisplay]; + else + return NULL; +} + +- (void *) xrContext +{ + if (is_screen_context) + return [(XGServer *)server xrContext]; + else + return NULL; +} + +- (DPSContext)xDPSContext +{ + return dps_context; +} + +- (void)createDPSContext +{ + int x, y, supported; + unsigned long valuemask; + XGCValues values; + + /* Create a GC for the initial window */ + values.foreground = ((RContext *)context)->black; + values.background = ((RContext *)context)->white; + values.function = GXcopy; + values.plane_mask = AllPlanes; + values.clip_mask = None; + valuemask = (GCFunction | GCPlaneMask | GCClipMask + | GCForeground|GCBackground); + ((RContext *)context)->copy_gc = + XCreateGC(XDPY, XDRW, valuemask, &values); + + /* Create the context if need be */ + if (!dps_context) + { + /* Pass None as the drawable argument; the program will execute correctly + but will not render any text or graphics. */ + dps_context = XDPSCreateSimpleContext(XDPY, None, + ((RContext *)context)->copy_gc, + 0, 0, + text_proc, + error_proc, + NULL); + if (dps_context == NULL) + { + NSLog(@"Could not connect to DPS\n"); + NSLog(@"Trying again...\n"); + dps_context = XDPSCreateSimpleContext(XDPY, None, + ((RContext *)context)->copy_gc, + 0, 0, + text_proc, + error_proc, + NULL); + + if (dps_context == NULL) + { + NSLog(@"DPS is not available\n"); + exit(1); + } + } + + // Make it the active context + DPSSetContext(dps_context); + XDPSRegisterContext(dps_context, NO); + + // Use pass-through event handling + XDPSSetEventDelivery(XDPY, dps_event_pass_through); + } + + PSWinitcontext (XGContextFromGC (((RContext *)context)->copy_gc), + XDRW, 0, 0); + PSWGetTransform (dps_context, ctm, invctm, &x, &y); + PSWinitcontext (XGContextFromGC (((RContext *)context)->copy_gc), + None, 0, 0); + PSWRevision(&dps_revision); + + /* Check for operator extensions */ + DPSWKnownExtensions(dps_context, &ext_flags); + /* Check if composite-related extensions work */ + /* FIXME: This crashes DPS on some implementations */ + //DPSWWorkingExtensions(dps_context, &supported); + supported = 0; + if (supported == 0) + ext_flags = (ext_flags + & ~(COMPOSITE_EXT | ALPHAIMAGE_EXT | COMPOSITERECT_EXT + | DISSOLVE_EXT | READIMAGE_EXT | SETALPHA_EXT)); + /* FIXME: alphaimage and composite work badly in DGS 5.50. Perhaps when + we find a version that works we can put an additional test here. For now, + just turn them off. + */ + ext_flags = (ext_flags & ~(COMPOSITE_EXT | ALPHAIMAGE_EXT | DISSOLVE_EXT )); + + NSDebugLLog(@"NSDPSContext", @"Using DPS Revision: %d\n", dps_revision); + NSDebugLLog(@"NSDPSContext", @"DPS Default Matrix: [%f %f %f %f %f %f]\n", + ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]); + NSDebugLLog(@"NSDPSContext", @"DPS Extensions flags: %d\n", ext_flags); + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"DPSDefaultMatrix"] + == NO) + { + NSDebugLog(@"Reseting default matrix\n"); + ctm[0] /= fabs(ctm[0]); + ctm[3] /= fabs(ctm[3]); + PSWSetMatrix(ctm); + } +} + +- (void)createTextContext +{ + if (dps_context) + return; + + dps_context = DPSCreateTextContext(text_proc, error_proc); + if (dps_context == NULL) + { + NSLog(@"Could not create DPS text context"); + return; + } +} + +- (void) flushGraphics +{ + DPSFlushContext(dps_context); + XFlush([(XGServer *)server xDisplay]); +} + +- (void) _localTransform: (float *)local_ctm inverse: (float *)local_inv + offset: (NSPoint *)offset +{ + int x, y; + if (local_ctm == NULL || local_inv == NULL) + return; + PSWGetTransform (dps_context, local_ctm, local_inv, &x, &y); + if (offset) + { + offset->x = x; + offset->y = y; + } +} + +- (NSPoint)userPointFromXPoint:(NSPoint)xPoint +{ + float lctm[6], linv[6]; + NSPoint offset, userPoint; + + [self _localTransform: lctm inverse: linv offset: &offset]; + //xPoint.x -= offset.x; + //xPoint.y -= offset.y; + userPoint.x = linv[A_COEFF] * xPoint.x + linv[C_COEFF] * xPoint.y + + linv[TX_CONS]; + userPoint.y = linv[B_COEFF] * xPoint.x + linv[D_COEFF] * xPoint.y + + linv[TY_CONS]; + return userPoint; +} + +- (NSPoint)XPointFromUserPoint:(NSPoint)userPoint +{ + float lctm[6], linv[6]; + NSPoint offset, xPoint; + + [self _localTransform: lctm inverse: linv offset: &offset]; + xPoint.x = lctm[A_COEFF] * userPoint.x + lctm[C_COEFF] * userPoint.y + + lctm[TX_CONS] + offset.x; + xPoint.y = lctm[B_COEFF] * userPoint.x + lctm[D_COEFF] * userPoint.y + + lctm[TY_CONS] + offset.y; + xPoint.x = floor (xPoint.x); + xPoint.y = floor (xPoint.y); + NSDebugLLog(@"CTM", @"Matrix [%f,%f,%f,%f,%f,%f] (%f,%f)\n", + lctm[A_COEFF], lctm[B_COEFF], lctm[C_COEFF], lctm[D_COEFF], + lctm[TX_CONS], lctm[TY_CONS], offset.x, offset.y); + return xPoint; +} + +- (NSRect)userRectFromXRect:(NSRect)xrect +{ + float lctm[6], linv[6]; + float x, y, w, h; + + [self _localTransform: lctm inverse: linv offset: NULL]; + x = linv[A_COEFF] * NSMinX(xrect) + linv[C_COEFF] * NSMinY(xrect) + + linv[TX_CONS]; + y = linv[B_COEFF] * NSMinX(xrect) + linv[D_COEFF] * NSMinY(xrect) + + linv[TY_CONS]; + w = linv[A_COEFF] * NSWidth(xrect) + linv[C_COEFF] * NSHeight(xrect); + h = linv[B_COEFF] * NSWidth(xrect) + linv[D_COEFF] * NSHeight(xrect); + if (h < 0) + y -= h; + h = fabs(h); + if (w < 0) + x -= w; + w = fabs(w); + return NSMakeRect(x, y, w, h); +} + +- (NSRect)XRectFromUserRect:(NSRect)urect +{ + NSPoint offset; + float lctm[6], linv[6]; + float x, y, w, h; + + [self _localTransform: lctm inverse: linv offset: &offset]; + x = lctm[A_COEFF] * NSMinX(urect) + lctm[C_COEFF] * NSMinY(urect) + + lctm[TX_CONS] + offset.x; + y = lctm[B_COEFF] * NSMinX(urect) + lctm[D_COEFF] * NSMinY(urect) + + lctm[TY_CONS] + offset.y; + w = lctm[A_COEFF] * NSWidth(urect) + lctm[C_COEFF] * NSHeight(urect); + h = lctm[B_COEFF] * NSWidth(urect) + lctm[D_COEFF] * NSHeight(urect); + NSDebugLLog(@"CTM", @"Matrix [%f,%f,%f,%f,%f,%f] (%f,%f)\n", + lctm[A_COEFF], lctm[B_COEFF], lctm[C_COEFF], lctm[D_COEFF], + lctm[TX_CONS], lctm[TY_CONS], offset.x, offset.y); + if (h < 0) + y += h; + h = fabs(floor(h)); + if (w < 0) + x += w; + w = fabs(floor(w)); + x = floor(x); + y = floor(y); + return NSMakeRect(x, y, w, h); +} + +- (op_extensions_t) operatorExtensions +{ + return ext_flags; +} + +@end + +@implementation NSDPSContext (NSGraphics) + +/* Optimized drawing functions */ +- (void) NSRectFillList: (const NSRect *)rects : (int) count +{ + int i; + float rectvals[count*4]; + + if (count*4 > 65536) + { + NSLog(@"DPS Rendering Error: RectFillList with > 16384 rects"); + return; + } + + for (i = 0; i < count; i++) + { + rectvals[i*4 ] = NSMinX(rects[i]); + rectvals[i*4 + 1] = NSMinY(rects[i]); + rectvals[i*4 + 2] = NSWidth(rects[i]); + rectvals[i*4 + 3] = NSHeight(rects[i]); + } + PSWRectFillList(rectvals, count*4); +} + +- (void) NSRectFillListWithGrays: (const NSRect *)rects : (const float *)grays + :(int) count +{ +#if 1 + int i; + float rectvals[count*5]; + + if (count*5 > 65536) + { + NSLog(@"DPS Rendering Error: RectFillListGray with > 13107 rects"); + return; + } + + for (i = 0; i < count; i++) + { + rectvals[i*5 ] = NSMinX(rects[i]); + rectvals[i*5 + 1] = NSMinY(rects[i]); + rectvals[i*5 + 2] = NSWidth(rects[i]); + rectvals[i*5 + 3] = NSHeight(rects[i]); + rectvals[i*5 + 4] = grays[i]; + } + PSWRectFillListGray(rectvals, count*5); +#else + int i, last_gray, tcount; + + PSsetgray(grays[0]); + last_gray = grays[0]; + tcount = 0; + for (i = 0; i < count; i++) + { + if (grays[i] != last_gray) + { + NSRectFillList(&rects[i-tcount], tcount); + tcount = 0; + PSsetgray(grays[i]); + last_gray = grays[i]; + } + else + tcount++; + } +#endif +} + +- (void) NSDottedFrameRect: (const NSRect) aRect +{ + PSWDottedFrameRect (aRect.origin.x, aRect.origin.y, + aRect.size.width, aRect.size.height); +} + +- (void) NSFrameRect: (const NSRect) aRect +{ + PSWFrameRect (aRect.origin.x, aRect.origin.y, + aRect.size.width, aRect.size.height); +} + +- (void) NSFrameRectWithWidth: (const NSRect) aRect : (float) frameWidth +{ + PSWFrameRectWithWidth (aRect.origin.x, aRect.origin.y, + aRect.size.width, aRect.size.height, frameWidth); +} + +// +// Read the Color at a Screen Position +// +- (NSColor *) NSReadPixel: (NSPoint) location +{ + return nil; +} + + + +- (void) NSBeep +{ + XBell([(XGServer *)server xDisplay], 50); +} + +@end diff --git a/Source/xdps/NSDPSContextOps.m b/Source/xdps/NSDPSContextOps.m new file mode 100644 index 0000000..c8a7726 --- /dev/null +++ b/Source/xdps/NSDPSContextOps.m @@ -0,0 +1,1368 @@ +/* + NSDPSContextOps - Translate method calls to PS ops. + + Copyright (C) 1999 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Apr 1999 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#include + +#ifdef HAVE_WRASTER_H +#include "wraster.h" +#else +#include "x11/wraster.h" +#endif + +#define BOOL XWINDOWSBOOL +#include +#include +#undef BOOL +#include +#include +#include + +#include "x11/XGServerWindow.h" +#include "xdps/NSDPSContext.h" +#include "AppKit/NSFont.h" +#include "extensions.h" +#include "fonts.h" +#include "general.h" + +#define XDPY (((RContext *)context)->dpy) +#define XSCR (((RContext *)context)->screen_number) + +@interface NSDPSContext(PrivateOps) +- (void)DPSundefineuserobject: (int)index; +@end + +@implementation NSDPSContext (Ops) + +/* ----------------------------------------------------------------------- */ +/* Color operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPScurrentblackgeneration +{ + DPScurrentblackgeneration(dps_context); +} + +- (void)DPScurrentcmykcolor: (float *)c : (float *)m : (float *)y : (float *)k +{ + DPScurrentcmykcolor(dps_context, c, m, y, k); +} + +- (void)DPScurrentcolorscreen +{ + DPScurrentcolorscreen(dps_context); +} + +- (void)DPScurrentcolortransfer +{ + DPScurrentcolortransfer(dps_context); +} + +- (void)DPScurrentundercolorremoval +{ + DPScurrentundercolorremoval(dps_context); +} + +- (void)DPSsetblackgeneration +{ + DPSsetblackgeneration(dps_context); +} + +- (void)DPSsetcmykcolor: (float)c : (float)m : (float)y : (float)k +{ + DPSsetcmykcolor(dps_context, c, m, y, k); +} + +- (void)DPSsetcolorscreen +{ + DPSsetcolorscreen(dps_context); +} + +- (void)DPSsetcolortransfer +{ + DPSsetcolortransfer(dps_context); +} + +- (void)DPSsetundercolorremoval +{ + DPSsetundercolorremoval(dps_context); +} + +/* ----------------------------------------------------------------------- */ +/* Data operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSclear +{ + DPSclear(dps_context); +} + +- (void)DPScleartomark +{ + DPScleartomark(dps_context); +} + +- (void)DPScopy: (int)n +{ + DPScopy(dps_context, n); +} + +- (void)DPScount: (int *)n +{ + DPScount(dps_context, n); +} + +- (void)DPScounttomark: (int *)n +{ + DPScounttomark(dps_context, n); +} + +- (void)DPSdup +{ + DPSdup(dps_context); +} + +- (void)DPSexch +{ + DPSexch(dps_context); +} + +- (void)DPSexecstack +{ + DPSexecstack(dps_context); +} + +- (void)DPSget +{ + DPSget(dps_context); +} + +- (void)DPSindex: (int)i +{ + DPSindex(dps_context, i); +} + +- (void)DPSmark +{ + DPSmark(dps_context); +} + +- (void)DPSmatrix +{ + DPSmatrix(dps_context); +} + +- (void)DPSnull +{ + DPSnull(dps_context); +} + +- (void)DPSpop +{ + DPSpop(dps_context); +} + +- (void)DPSput +{ + DPSput(dps_context); +} + +- (void)DPSroll: (int)n : (int)j +{ + DPSroll(dps_context, n, j); +} + +/* ----------------------------------------------------------------------- */ +/* Font operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSFontDirectory +{ + DPSFontDirectory(dps_context); +} + +- (void)DPSISOLatin1Encoding +{ + DPSISOLatin1Encoding(dps_context); +} + +- (void)DPSSharedFontDirectory +{ + DPSSharedFontDirectory(dps_context); +} + +- (void)DPSStandardEncoding +{ + DPSStandardEncoding(dps_context); +} + +- (void)DPScachestatus: (int *)bsize : (int *)bmax : (int *)msize +{ + //PScachestatus(dps_context); +} + +- (void)DPScurrentcacheparams +{ + DPScurrentcacheparams(dps_context); +} + +- (void)DPScurrentfont +{ + DPScurrentfont(dps_context); +} + +- (void)DPSdefinefont +{ + DPSdefinefont(dps_context); +} + +- (void)DPSfindfont: (const char *)name +{ + DPSfindfont(dps_context, name); +} + +- (void)DPSmakefont +{ + DPSmakefont(dps_context); +} + +- (void)DPSscalefont: (float)size +{ + DPSscalefont(dps_context, size); +} + +- (void)DPSselectfont: (const char *)name : (float)scale +{ + DPSselectfont(dps_context, name, scale); +} + +- (void)DPSsetcachedevice: (float)wx : (float)wy : (float)llx : (float)lly : (float)urx : (float)ury +{ + DPSsetcachedevice(dps_context, wx, wy, llx, lly, urx, ury); +} + +- (void)DPSsetcachelimit: (float)n +{ + DPSsetcachelimit(dps_context, n); +} + +- (void)DPSsetcacheparams +{ + DPSsetcacheparams(dps_context); +} + +- (void)DPSsetcharwidth: (float)wx : (float)wy +{ + DPSsetcharwidth(dps_context, wx, wy); +} + +- (void)DPSsetfont: (int)f +{ + DPSsetfont(dps_context, f); +} + +- (void)DPSundefinefont: (const char *)name +{ + DPSundefinefont(dps_context, name); +} + +- (void) GSSetFont: (NSFont*) font +{ + NSString *fontName = [font fontName]; + + if ([[self focusView] isFlipped]) + { + float invmatrix[6]; + + memcpy(invmatrix, [font matrix], sizeof(invmatrix)); + invmatrix[3] = -invmatrix[3]; + PSWSetFont ([fontName cString], invmatrix); + } + else + PSWSetFont ([fontName cString], [font matrix]); +} + +/* ----------------------------------------------------------------------- */ +/* System operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSrestore +{ + DPSrestore(dps_context); +} + +- (void)DPSsave +{ + DPSsave(dps_context); +} + +/* ----------------------------------------------------------------------- */ +/* Gstate operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSconcat: (const float *)m +{ + DPSconcat(dps_context, m); +} + +- (void)DPScurrentdash +{ + DPScurrentdash(dps_context); +} + +- (void)DPScurrentflat: (float *)flatness +{ + DPScurrentflat(dps_context, flatness); +} + +- (void)DPScurrentgray: (float *)gray +{ + DPScurrentgray(dps_context, gray); +} + +- (void)DPScurrentgstate: (int)gst +{ + DPScurrentgstate(dps_context, gst); +} + +- (void)DPScurrenthalftone +{ + DPScurrenthalftone(dps_context); +} + +- (void)DPScurrenthalftonephase: (float *)x : (float *)y +{ + DPScurrenthalftonephase(dps_context, x, y); +} + +- (void)DPScurrenthsbcolor: (float *)h : (float *)s : (float *)b +{ + DPScurrenthsbcolor(dps_context, h, s, b); +} + +- (void)DPScurrentlinecap: (int *)linecap +{ + DPScurrentlinecap(dps_context, linecap); +} + +- (void)DPScurrentlinejoin: (int *)linejoin +{ + DPScurrentlinejoin(dps_context, linejoin); +} + +- (void)DPScurrentlinewidth: (float *)width +{ + DPScurrentlinewidth(dps_context, width); +} + +- (void)DPScurrentmatrix +{ + DPScurrentmatrix(dps_context); +} + +- (void)DPScurrentmiterlimit: (float *)limit +{ + DPScurrentmiterlimit(dps_context, limit); +} + +- (void)DPScurrentpoint: (float *)x : (float *)y +{ + DPScurrentpoint(dps_context, x, y); +} + +- (void)DPScurrentrgbcolor: (float *)r : (float *)g : (float *)b +{ + DPScurrentrgbcolor(dps_context, r, g, b); +} + +- (void)DPScurrentscreen +{ + DPScurrentscreen(dps_context); +} + +- (void)DPScurrentstrokeadjust: (int *)b +{ + DPScurrentstrokeadjust(dps_context, b); +} + +- (void)DPScurrenttransfer +{ + DPScurrenttransfer(dps_context); +} + +- (void)DPSdefaultmatrix +{ + DPSdefaultmatrix(dps_context); +} + +- (void)DPSgrestore +{ + DPSgrestore(dps_context); +} + +- (void)DPSgrestoreall +{ + DPSgrestoreall(dps_context); +} + +- (void)DPSgsave +{ + DPSgsave(dps_context); +} + +- (void)DPSgstate +{ + DPSgstate(dps_context); +} + +- (void)DPSinitgraphics +{ + DPSinitgraphics(dps_context); +} + +- (void)DPSinitmatrix +{ + DPSinitmatrix(dps_context); + /* This works around problems with non-"identity" matrices */ + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"DPSDefaultMatrix"] + == NO) + { + float nctm[6]; + NSDebugLog(@"Resetting default matrix\n"); + nctm[0]=1; nctm[1]=0; nctm[2]=0; nctm[3]=-1; nctm[4]=0; nctm[5]=0; + PSWSetMatrix(nctm); + } +} + +- (void)DPSrotate: (float)angle +{ + DPSrotate(dps_context, angle); +} + +- (void)DPSscale: (float)x : (float)y +{ + DPSscale(dps_context, x, y); +} + +- (void)DPSsetdash: (const float *)pat : (int)size : (float)offset +{ + DPSsetdash(dps_context, pat, size, offset); +} + +- (void)DPSsetflat: (float)flatness +{ + DPSsetflat(dps_context, flatness); +} + +- (void)DPSsetgray: (float)gray +{ + DPSsetgray(dps_context, gray); +} + +- (void)DPSsetgstate: (int)gst +{ + DPSsetgstate(dps_context, gst); +} + +- (void)DPSsethalftone +{ + DPSsethalftone(dps_context); +} + +- (void)DPSsethalftonephase: (float)x : (float)y +{ + DPSsethalftonephase(dps_context, x, y); +} + +- (void)DPSsethsbcolor: (float)h : (float)s : (float)b +{ + DPSsethsbcolor(dps_context, h, s, b); +} + +- (void)DPSsetlinecap: (int)linecap +{ + DPSsetlinecap(dps_context, linecap); +} + +- (void)DPSsetlinejoin: (int)linejoin +{ + DPSsetlinejoin(dps_context, linejoin); +} + +- (void)DPSsetlinewidth: (float)width +{ + DPSsetlinewidth(dps_context, width); +} + +- (void)DPSsetmatrix +{ + DPSsetmatrix(dps_context); +} + +- (void)DPSsetmiterlimit: (float)limit +{ + DPSsetmiterlimit(dps_context, limit); +} + +- (void)DPSsetrgbcolor: (float)r : (float)g : (float)b +{ + DPSsetrgbcolor(dps_context, r, g, b); +} + +- (void)DPSsetscreen +{ + DPSsetscreen(dps_context); +} + +- (void)DPSsetstrokeadjust: (int)b +{ + DPSsetstrokeadjust(dps_context, b); +} + +- (void)DPSsettransfer +{ + DPSsettransfer(dps_context); +} + +- (void)DPStranslate: (float)x : (float)y +{ + DPStranslate(dps_context, x, y); +} + +/* Should work the same as 'unique_index exch defineuserobject' */ +- (int) GSDefineGState +{ + return PSDefineAsUserObj(); +} + +- (void) GSUndefineGState: (int)gst +{ + [self DPSundefineuserobject: gst]; +} + +/* Should work the same as 'currentgstate pop' */ +- (void) GSReplaceGState: (int)gst +{ + [self DPScurrentgstate: gst]; + [self DPSpop]; +} + +/* ----------------------------------------------------------------------- */ +/* I/O operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSflush +{ + DPSflush(dps_context); +} + +/* ----------------------------------------------------------------------- */ +/* Matrix operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSconcatmatrix +{ + DPSconcatmatrix(dps_context); +} + +- (void)DPSdtransform: (float)x1 : (float)y1 : (float *)x2 : (float *)y2 +{ + DPSdtransform(dps_context, x1, y1, x2, y2); +} + +- (void)DPSidentmatrix +{ + DPSidentmatrix(dps_context); +} + +- (void)DPSidtransform: (float)x1 : (float)y1 : (float *)x2 : (float *)y2 +{ + DPSidtransform(dps_context, x1, y1, x2, y2); +} + +- (void)DPSinvertmatrix +{ + DPSinvertmatrix(dps_context); +} + +- (void)DPSitransform: (float)x1 : (float)y1 : (float *)x2 : (float *)y2 +{ + DPSitransform(dps_context, x1, y1, x2, y2); +} + +- (void)DPStransform: (float)x1 : (float)y1 : (float *)x2 : (float *)y2 +{ + DPStransform(dps_context, x1, y1, x2, y2); +} + +/* ----------------------------------------------------------------------- */ +/* Opstack operations */ +/* ----------------------------------------------------------------------- */ + +- (void)DPSdefineuserobject +{ + DPSdefineuserobject(dps_context); +} + +- (void)DPSexecuserobject: (int)index +{ + DPSexecuserobject(dps_context, index); +} + +- (void)DPSundefineuserobject: (int)index +{ + DPSundefineuserobject(dps_context, index); +} + +- (void)DPSgetboolean: (int *)it +{ + DPSgetboolean(dps_context, it); +} + +- (void)DPSgetchararray: (int)size : (char *)s +{ + DPSgetchararray(dps_context, size, s); +} + +- (void)DPSgetfloat: (float *)it +{ + DPSgetfloat(dps_context, it); +} + +- (void)DPSgetfloatarray: (int)size : (float *)a +{ + DPSgetfloatarray(dps_context, size, a); +} + +- (void)DPSgetint: (int *)it +{ + DPSgetint(dps_context, it); +} + +- (void)DPSgetintarray: (int)size : (int *)a +{ + DPSgetintarray(dps_context, size, a); +} + +- (void)DPSgetstring: (char *)s +{ + DPSgetstring(dps_context, s); +} + +- (void)DPSsendboolean: (int)it +{ + DPSsendboolean(dps_context, it); +} + +- (void)DPSsendchararray: (const char *)s : (int)size +{ + DPSsendchararray(dps_context, s, size); +} + +- (void)DPSsendfloat: (float)it +{ + DPSsendfloat(dps_context, it); +} + +- (void)DPSsendfloatarray: (const float *)a : (int)size +{ + DPSsendfloatarray(dps_context, a, size); +} + +- (void)DPSsendint: (int)it +{ + DPSsendint(dps_context, it); +} + +- (void)DPSsendintarray: (const int *)a : (int)size +{ + DPSsendintarray(dps_context, a, size); +} + +- (void)DPSsendstring: (const char *)s +{ + DPSsendstring(dps_context, s); +} + +/* ----------------------------------------------------------------------- */ +/* Paint operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSashow: (float)x : (float)y : (const char *)s +{ + DPSashow(dps_context, x, y, s); +} + +- (void)DPSawidthshow: (float)cx : (float)cy : (int)c : (float)ax : (float)ay : (const char *)s +{ + DPSawidthshow(dps_context, cx, cy, c, ax, ay, s); +} + +- (void)DPScopypage +{ + DPScopypage(dps_context); +} + +- (void)DPSeofill +{ + DPSeofill(dps_context); +} + +- (void)DPSerasepage +{ + DPSerasepage(dps_context); +} + +- (void)DPSfill +{ + DPSfill(dps_context); +} + +- (void)DPSimage +{ + DPSimage(dps_context); +} + +- (void)DPSimagemask +{ + DPSimagemask(dps_context); +} + +- (void)DPScolorimage +{ + DPScolorimage(dps_context); +} + +- (void)DPSalphaimage +{ + if (ext_flags & ALPHAIMAGE_EXT) + PSWalphaimage(); + else + NSDebugLLog(@"NSDPSContext", @"DPS does not support alphaimage op\n"); +} + +- (void)DPSkshow: (const char *)s +{ + DPSkshow(dps_context, s); +} + +- (void)DPSrectfill: (float)x : (float)y : (float)w : (float)h +{ + DPSrectfill(dps_context, x, y, w, h); +} + +- (void)DPSrectstroke: (float)x : (float)y : (float)w : (float)h +{ + DPSrectstroke(dps_context, x, y, w, h); +} + +- (void)DPSshow: (const char *)s +{ + DPSshow(dps_context, s); +} + +- (void)DPSshowpage +{ + DPSshowpage(dps_context); +} + +- (void)DPSstroke +{ + DPSstroke(dps_context); +} + +- (void)DPSstrokepath +{ + DPSstrokepath(dps_context); +} + +- (void)DPSueofill: (const char *)nums : (int)n : (const char *)ops : (int)l +{ + DPSueofill(dps_context, nums, n, ops, l); +} + +- (void)DPSufill: (const char *)nums : (int)n : (const char *)ops : (int)l +{ + DPSufill(dps_context, nums, n, ops, l); +} + +- (void)DPSustroke: (const char *)nums : (int)n : (const char *)ops : (int)l +{ + DPSustroke(dps_context, nums, n, ops, l); +} + +- (void)DPSustrokepath: (const char *)nums : (int)n : (const char *)ops : (int)l +{ + DPSustrokepath(dps_context, nums, n, ops, l); +} + +- (void)DPSwidthshow: (float)x : (float)y : (int)c : (const char *)s +{ + DPSwidthshow(dps_context, x, y, c, s); +} + +- (void)DPSxshow: (const char *)s : (const float *)numarray : (int)size +{ + DPSxshow(dps_context, s, numarray, size); +} + +- (void)DPSxyshow: (const char *)s : (const float *)numarray : (int)size +{ + DPSxyshow(dps_context, s, numarray, size); +} + +- (void)DPSyshow: (const char *)s : (const float *)numarray : (int)size +{ + DPSyshow(dps_context, s, numarray, size); +} + +/* ----------------------------------------------------------------------- */ +/* Path operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSarc: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2 +{ + DPSarc(dps_context, x, y, r, angle1, angle2); +} + +- (void)DPSarcn: (float)x : (float)y : (float)r : (float)angle1 : (float)angle2 +{ + DPSarcn(dps_context, x, y, r, angle1, angle2); +} + +- (void)DPSarct: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r +{ + DPSarct(dps_context, x1, y1, x2, y2, r); +} + +- (void)DPSarcto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)r : (float *)xt1 : (float *)yt1 : (float *)xt2 : (float *)yt2 +{ + DPSarcto(dps_context, x1, y1, x2, y2, r, xt1, yt1, xt2, yt2); +} + +- (void)DPScharpath: (const char *)s : (int)b +{ + DPScharpath(dps_context, s, b); +} + +- (void)DPSclip +{ + DPSclip(dps_context); +} + +- (void)DPSclippath +{ + DPSclippath(dps_context); +} + +- (void)DPSclosepath +{ + DPSclosepath(dps_context); +} + +- (void)DPScurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3 : (float)y3 +{ + DPScurveto(dps_context, x1, y1, x2, y2, x3, y3); +} + +- (void)DPSeoclip +{ + DPSeoclip(dps_context); +} + +- (void)DPSeoviewclip +{ + DPSeoviewclip(dps_context); +} + +- (void)DPSflattenpath +{ + DPSflattenpath(dps_context); +} + +- (void)DPSinitclip +{ + DPSinitclip(dps_context); +} + +- (void)DPSinitviewclip +{ + DPSinitviewclip(dps_context); +} + +- (void)DPSlineto: (float)x : (float)y +{ + DPSlineto(dps_context, x, y); +} + +- (void)DPSmoveto: (float)x : (float)y +{ + DPSmoveto(dps_context, x, y); +} + +- (void)DPSnewpath +{ + DPSnewpath(dps_context); +} + +- (void)DPSpathbbox: (float *)llx : (float *)lly : (float *)urx : (float *)ury +{ + DPSpathbbox(dps_context, llx, lly, urx, ury); +} + +- (void)DPSpathforall +{ + DPSpathforall(dps_context); +} + +- (void)DPSrcurveto: (float)x1 : (float)y1 : (float)x2 : (float)y2 : (float)x3 : (float)y3 +{ + DPSrcurveto(dps_context, x1, y1, x2, y2, x3, y3); +} + +- (void)DPSrectclip: (float)x : (float)y : (float)w : (float)h +{ + DPSrectclip(dps_context, x, y, w, h); +} + +- (void)DPSrectviewclip: (float)x : (float)y : (float)w : (float)h +{ + DPSrectviewclip(dps_context, x, y, w, h); +} + +- (void)DPSreversepath +{ + DPSreversepath(dps_context); +} + +- (void)DPSrlineto: (float)x : (float)y +{ + DPSrlineto(dps_context, x, y); +} + +- (void)DPSrmoveto: (float)x : (float)y +{ + DPSrmoveto(dps_context, x, y); +} + +- (void)DPSsetbbox: (float)llx : (float)lly : (float)urx : (float)ury +{ + DPSsetbbox(dps_context, llx, lly, urx, ury); +} + +- (void)DPSsetucacheparams +{ + DPSsetucacheparams(dps_context); +} + +- (void)DPSuappend: (const char *)nums : (int)n : (char *)ops : (int)l +{ + DPSuappend(dps_context, nums, n, ops, l); +} + +- (void)DPSucache +{ + DPSucache(dps_context); +} + +- (void)DPSucachestatus +{ + DPSucachestatus(dps_context); +} + +- (void)DPSupath: (int)b +{ + DPSupath(dps_context, b); +} + +- (void)DPSviewclip +{ + DPSviewclip(dps_context); +} + +- (void)DPSviewclippath +{ + DPSviewclippath(dps_context); +} + +/* ----------------------------------------------------------------------- */ +/* X operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPScurrentdrawingfunction: (int *)function +{ + DPScurrentXdrawingfunction(dps_context, function); +} + +- (void)DPScurrentgcdrawable: (void **)gc : (void **)draw : (int *)x : (int *)y +{ + /* FIXME: This really can't work since this returns an XGContext not a GC */ + DPScurrentXgcdrawable(dps_context, gc, (int *)draw, x, y); +} + +- (void)DPScurrentgcdrawablecolor: (void **)gc : (void **)draw : (int *)x : (int *)y + : (int *)colorInfo +{ + /* FIXME: This really can't work since this returns an XGContext not a GC */ + DPScurrentXgcdrawablecolor(dps_context, gc, (int *)draw, x, y, colorInfo); +} + +- (void)DPScurrentoffset: (int *)x : (int *)y +{ + DPScurrentXoffset(dps_context, x, y); +} + +- (void)DPSsetdrawingfunction: (int)function +{ + DPSsetXdrawingfunction(dps_context, function); +} + +- (void)DPSsetoffset: (short int)x : (short int)y +{ + DPSsetXoffset(dps_context, x, y); +} + +- (void)DPSsetXrgbactual: (double)r : (double)g : (double)b : (int *)success +{ + DPSsetXrgbactual(dps_context, r, g, b, success); +} + +- (void)DPSsetgcdrawable: (void *)gc : (void *)draw : (int)x : (int)y +{ + DPSsetXgcdrawable(dps_context, XGContextFromGC(gc), (int)draw, x, y); +} + +- (void)DPSsetgcdrawablecolor: (void *)gc : (void *)draw : (int)x : (int)y + : (const int *)colorInfo +{ + DPSsetXgcdrawablecolor(dps_context, XGContextFromGC(gc), (int)draw, x, y, colorInfo); +} + +/*-------------------------------------------------------------------------*/ +/* Graphics Extension Ops */ +/*-------------------------------------------------------------------------*/ +- (void) _copyBits: (int) srcGstate : (NSRect) srcRect : (NSPoint) destPoint +{ + XRectangle dst; + XRectangle src; + Drawable source, draw; + NSWindow *window; + gswindow_device_t *windev; + + window = [[self focusView] window]; + if ([window gState] == 0) + return; + windev = [XGServer _windowWithTag: [window windowNumber]]; + draw = (windev->buffer) ? windev->buffer : windev->ident; + if (draw == 0) + return; + + NSDebugLLog (@"CTM", @"Frame %@\n", NSStringFromRect(windev->xframe)); + source = 0; + if (srcGstate != 0) + { + int gc, x, y; + PSgsave(); + PSsetgstate(srcGstate); + PScurrentXgcdrawable(&gc, (int *)(&source), &x, &y); + if (source == 0) + return; + if (source == draw) + { + /* This probably shouldn't happen, It might come from a bug + in DGS 0.5.x + */ + } + NSDebugLLog (@"Copy", @"Orig %@\n", NSStringFromRect(srcRect)); + srcRect = [self XRectFromUserRect: srcRect]; + NSDebugLLog (@"Copy", @"XCoor %@\n", NSStringFromRect(srcRect)); + PSgrestore(); + } + else + { + source = draw; + srcRect = [self XRectFromUserRect: srcRect]; + } + NSDebugLLog (@"Copy", @"ODest %@\n", NSStringFromPoint(destPoint)); + destPoint = [self XPointFromUserPoint: destPoint]; + /* FIXME: Why is this needed? */ + if (![[self focusView] isFlipped]) + destPoint.y -= NSHeight(srcRect); + NSDebugLLog (@"Copy", @"XDest %@\n", NSStringFromPoint(destPoint)); + + src.x = NSMinX(srcRect); src.y = NSMinY(srcRect); + src.width = NSWidth(srcRect); src.height = NSHeight(srcRect); + dst.x = destPoint.x; dst.y = destPoint.y; + NSDebugLLog (@"NSWindow", @"Copying bitmap from (%d %d %d %d) to (%d %d)\n", + src.x, src.y, src.width, src.height, dst.x, dst.y); + [self wait]; + XCopyArea([self xDisplay], source, draw, windev->gc, + src.x, src.y, src.width, src.height, dst.x, dst.y); +} + +- (void) DPScomposite: (float)x : (float)y : (float)w : (float)h : (int)gstateNum : (float)dx : (float)dy : (int)op +{ + if (ext_flags & COMPOSITE_EXT) + PSWcomposite(x, y, w, h, gstateNum, dx, dy, op); + else + { + NSRect s = NSMakeRect(x, y, w, h); + NSPoint d = NSMakePoint(dx, dy); + NSDebugLLog(@"NSDPSContext", @"DPS does not support composite op\n"); + [self wait]; + [self _copyBits:gstateNum : s : d]; + } +} + +- (void) DPScompositerect: (float)x : (float)y : (float)w : (float)h : (int)op +{ + if (ext_flags & COMPOSITERECT_EXT) + PSWcompositerect(x, y, w, h, op); + else + { + /* Try to emulate this */ + float gray; + XGCValues gcv; + NSWindow *window; + gswindow_device_t *windev; + + DPScurrentgray(dps_context, &gray); + if (fabs(gray - 0.667) < .002) + DPSsetgray(dps_context, 0.333); + else + DPSsetrgbcolor(dps_context, 0.121, 0.121, 0); + + switch (op) + { + case NSCompositeClear: + gcv.function = GXclear; + break; + case NSCompositeCopy: + gcv.function = GXcopy; + break; + case NSCompositeSourceOver: + gcv.function = GXcopy; + break; + case NSCompositeSourceIn: + gcv.function = GXcopy; + break; + case NSCompositeSourceOut: + gcv.function = GXcopy; + break; + case NSCompositeSourceAtop: + gcv.function = GXcopy; + break; + case NSCompositeDestinationOver: + gcv.function = GXcopy; + break; + case NSCompositeDestinationIn: + gcv.function = GXcopy; + break; + case NSCompositeDestinationOut: + gcv.function = GXcopy; + break; + case NSCompositeDestinationAtop: + gcv.function = GXcopy; + break; + case NSCompositeXOR: + gcv.function = GXcopy; + break; + case NSCompositePlusDarker: + gcv.function = GXcopy; + break; + case NSCompositeHighlight: + gcv.function = GXxor; + break; + case NSCompositePlusLighter: + gcv.function = GXcopy; + break; + default: + gcv.function = GXcopy; + break; + } + + window = [[self focusView] window]; + windev = [XGServer _windowWithTag: [window windowNumber]]; + [self wait]; + XChangeGC(XDPY, windev->gc, GCFunction, &gcv); + DPSrectfill(dps_context, x, y, w, h); + [window flushWindow]; + gcv.function = GXcopy; + XChangeGC(XDPY, windev->gc, GCFunction, &gcv); + DPSsetgray(dps_context, gray); + } +} + +- (void) DPSdissolve: (float)x : (float)y : (float)w : (float)h : (int)gstateNum + : (float)dx : (float)dy : (float)delta +{ + if (ext_flags & DISSOLVE_EXT) + PSWdissolve(x, y, w, h, gstateNum, dx, dy, delta); + else + NSDebugLLog(@"NSDPSContext", @"DPS does not support dissolve op\n"); +} + +- (void) DPSreadimage +{ + if (ext_flags & READIMAGE_EXT) + PSWreadimage(); + else + NSDebugLLog(@"NSDPSContext", @"DPS does not support readimage op\n"); +} + +- (void) DPSsetalpha: (float)a +{ + if (ext_flags & SETALPHA_EXT) + PSWsetalpha(a); + else + NSDebugLLog(@"NSDPSContext", @"DPS does not support setalpha op\n"); +} + +- (void) DPScurrentalpha: (float *)alpha +{ + if (ext_flags & SETALPHA_EXT) + PSWcurrentalpha(alpha); + else + NSDebugLLog(@"NSDPSContext", @"DPS does not support currentalpha op\n"); +} + +- (void) DPSflushpage +{ + if (ext_flags & FLUSHPAGE_EXT) + PSWflushpage(); +} + +/* ----------------------------------------------------------------------- */ +/* Client functions */ +/* ----------------------------------------------------------------------- */ +- (void) DPSPrintf: (char *)fmt : (va_list)args +{ + int count; + char buf[1024]; + count = vsnprintf(buf, 1024, fmt, args); + DPSWriteData(dps_context, buf, MIN(1024, count)); +} + +- (void) DPSWriteData: (char *)buf : (unsigned int)count +{ + DPSWriteData(dps_context, buf, count); +} + +// +// Imaging Functions +// +- (void) NSDrawBitmap: (NSRect) rect : (int) pixelsWide : (int) pixelsHigh + : (int) bitsPerSample : (int) samplesPerPixel + : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar + : (BOOL) hasAlpha : (NSString *) colorSpaceName + : (const unsigned char *const [5]) data +{ + int bytes; + int working_alphaimage; + + // FIXME +#if 0 + working_alphaimage = [self operatorExtensions] + & ALPHAIMAGE_EXT; +#else + working_alphaimage = NO; +#endif + + /* Save scaling */ + PSmatrix(); PScurrentmatrix(); + PSmoveto(NSMinX(rect), NSMinY(rect)); + PSscale(NSWidth(rect), NSHeight(rect)); + + if (bitsPerSample == 0) + bitsPerSample = 8; + bytes = + (bitsPerSample * pixelsWide * pixelsHigh + 7) / 8; + if (bytes * samplesPerPixel != bytesPerRow * pixelsHigh) + { + NSLog(@"Image Rendering Error: Dodgy bytesPerRow value %d", bytesPerRow); + NSLog(@" pixelsHigh=%d, bytes=%d, samplesPerPixel=%d", + bytesPerRow, pixelsHigh, bytes); + return; + } + + // send the PostScript code + if(hasAlpha && working_alphaimage == YES) + { + // FIXME + NSLog(@"Alphaimage not implemented"); + return; + } + else if(samplesPerPixel > 1) + { + if(isPlanar || (hasAlpha && (working_alphaimage == NO))) + { + if(bitsPerSample != 8) + { + NSLog(@"Image format conversion not supported for bps!=8"); + return; + } + } + PSWColorImageHeader(pixelsWide, pixelsHigh, + bitsPerSample, + hasAlpha?(samplesPerPixel-1):samplesPerPixel); + } + else + PSWImageHeader(pixelsWide, pixelsHigh, bitsPerSample); + + // The context is now waiting for data on its standard input + if(isPlanar || (hasAlpha && (working_alphaimage == NO))) + { + // We need to do a format conversion. + // We do this on the fly, sending data to the context as soon as + // it is computed. + int i, j, spp, isAlpha, alpha; + unsigned char val; + isAlpha = hasAlpha && (working_alphaimage == NO); + if(isAlpha) + spp = samplesPerPixel - 1; + else + spp = samplesPerPixel; + + for(j=0; j + Date: March 1996 + + This file is part of the GNUstep GUI X/DPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "config.h" +#include "xdps/NSDPSContext.h" + +@interface PXKEPSImageRep : NSEPSImageRep +{ +} + +@end + +@implementation PXKEPSImageRep + +- (Class) classForCoder: aCoder +{ + if ([self class] == [PXKEPSImageRep class]) + return [super class]; + return [self class]; +} + +@end diff --git a/Source/xdps/PXKFontManager.m b/Source/xdps/PXKFontManager.m new file mode 100644 index 0000000..d740eac --- /dev/null +++ b/Source/xdps/PXKFontManager.m @@ -0,0 +1,75 @@ +/* + PXKFontEnumerator.m + + NSFontManager helper for GNUstep GUI X/DPS Backend + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: February 1997 + A completely rewritten version of the original source of Scott Christley. + + This file is part of the GNUstep GUI X/DPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include "xdps/NSDPSContext.h" +#include "AFMFileFontInfo.h" +#include "general.h" +#include "fonts.h" + +@implementation PXKFontEnumerator + +/* It would be probably more portable to use the standard PS resource + enumerator functions, but the makepsres utility does not understand how + DGS organize its resources. So we use the below techniques to identify + the font and AFM files. + + For Adobe DPS implementations I use the PS resources because it's more + portable. + */ + +- (void)enumerateFontsAndFamilies +{ + int count, length; + DPSContext ctxt; + NSArray *fontList; + NSMutableData *data; + + ctxt = [(NSDPSContext *)GSCurrentContext() xDPSContext]; + + PSWEnumerateFonts(ctxt, "*", &count, &length); + NSDebugLLog(@"Fonts", @"FontManager found %d font names\n", count); + data = [NSMutableData dataWithLength: count+length]; + PSWGetFontList(ctxt, count+length, (char *)[data mutableBytes]); + fontList = [[[NSString alloc] initWithData: data encoding: NSASCIIStringEncoding] + componentsSeparatedByString: @" "]; + allFontNames = RETAIN(fontList); + // FIXME Enumeration of font families is missing + allFontFamilies = nil; +} + +@end diff --git a/Source/xdps/drawingfuncs.psw b/Source/xdps/drawingfuncs.psw new file mode 100644 index 0000000..e18a8d2 --- /dev/null +++ b/Source/xdps/drawingfuncs.psw @@ -0,0 +1,64 @@ +/* + drawingfuncs.psw + + Support functions for the C drawing functions defined in OpenStep. + + Copyright (C) 1996,2001 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: January 1997 + Rewritten: Adam Fedor + Date: May 2001 + + This file is part of the GNUstep GUI X/DPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include + +defineps PSWFrameRectWithWidth (float x, y, w, h, linewidth) + linewidth setlinewidth + 0 setgray + x y w h rectstroke +endps + +defineps PSWFrameRect (float x, y, w, h) + 1 setlinewidth + 0 setgray + x y w h rectstroke +endps + +defineps PSWDottedFrameRect (float x, y, w, h) + 1 setlinewidth + [1] 0 setdash + 0 setgray + x y w h rectstroke +endps + +/* Optimized drawing of a list of rectangles. The list consists of + sucessive 4-tuples of rectangle values x, y, w, and h. Note that the + number of rectangles cannot exceed 65536/4 = 16384 */ +defineps PSWRectFillList (float numstring rectvals[x]; int x) + rectvals rectfill +endps + +/* Optimized drawing of a list of rectangles with different gray + values. The list consists of + sucessive 5-tuples of rectangle values x, y, w, h, and gray. Note that the + number of rectangles cannot exceed 65536/5 = 13107 */ +defineps PSWRectFillListGray (float rectvals[x]; int x) + mark rectvals {counttomark 4 gt {setgray rectfill} if} forall pop +endps diff --git a/Source/xdps/extensions.psw b/Source/xdps/extensions.psw new file mode 100644 index 0000000..9b5ab93 --- /dev/null +++ b/Source/xdps/extensions.psw @@ -0,0 +1,103 @@ +/* + general.psw + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Adam Fedor + Date: May 2000 + + This file is part of the GNUstep GUI X/DPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include + +defineps DPSWKnownExtensions (DPSContext ctxt | int *extflag) + + 0 + systemdict /alphaimage known {1 add} if + systemdict /composite known {2 add} if + systemdict /compositerect known {4 add} if + systemdict /dissolve known {8 add} if + systemdict /readimage known {16 add} if + systemdict /setalpha known {32 add} if + systemdict /flushpage known {64 add} if + extflag + +endps + +defineps DPSWWorkingExtensions(DPSContext ctxt | boolean *supported) + + { + 0 0 10 10 null 10 10 2 composite + } stopped not + supported + +endps + +/* Define our own versions of NeXT extension wrappers since they + aren't neccesarily in the DPS library +*/ + +defineps PSWalphaimage () + alphaimage +endps + +defineps PSWcomposite (float x, y, w, h; int gstateNum; float dx, dy; int op) + x y w h + gstateNum dup 0 eq {null} {execuserobject} ifelse + dx dy op composite +endps + +defineps PSWcompositerect (float x, y, w, h; int op) + x y w h op compositerect +endps + +defineps PSWdissolve (float x, y, w, h; int gstateNum; float dx, dy, delta) + x y w h + gstateNum dup 0 eq {null} {execuserobject} ifelse + dx dy delta dissolve +endps + +defineps PSWreadimage () + readimage +endps + +defineps PSWsetalpha (float alpha) + alpha setalpha +endps + +defineps PSWcurrentalpha (| float *alpha) + currentalpha alpha +endps + +defineps PSWflushpage () + flushpage +endps + +/* Image helper wrappers */ + +defineps PSWColorImageHeader(int width, height, bps, spp) + width height bps + [width 0 0 height neg 0 height] + currentfile false spp colorimage +endps + +defineps PSWImageHeader(int width, height, bps) + width height bps + [width 0 0 height neg 0 height] + currentfile image +endps diff --git a/Source/xdps/fonts.psw b/Source/xdps/fonts.psw new file mode 100644 index 0000000..af77958 --- /dev/null +++ b/Source/xdps/fonts.psw @@ -0,0 +1,165 @@ +/* + fonts.psw + + Support functions to determine the installed fonts. + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: February 1997 + + This file is part of the GNUstep GUI X/DPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include + +/* These next two procedues are meant to be used together. They find all font + names and then fills an array with those names +*/ +defineps PSWEnumerateFonts(DPSContext ctxt; char *pattern | + int *count; int *total_length) + 0 0 % count total_length + (pattern) { + dup length string cvs % fonts count total_length newfont + 3 1 roll % fonts newfont count total_length + exch 1 add exch % fonts newfont newcount total_length + 2 index length add % fonts newfont newcount newtotal_length + } 256 string /Font resourceforall + total_length dup count + % fonts count +endps + +defineps PSWGetFontList(DPSContext ctxt; int length | + char fontNames[length]) + % fonts count + { + fontNames ( ) fontNames + } repeat +endps + +/* The mapping between font names and file name is DPS dependent. On NeXTSTEP + for example (and on systems conforming to red book), you can find out the + filename where a font is defined like below: + + /Font /Category findresource + begin + /Times-Roman 1024 string ResourceFileName + end + + This pushes on the stack %font%Times-Roman. The program should search in + the standard places a directory called `Times-Roman.font' to determine the + definition of the font. +*/ +defineps PSWGetFontFile(DPSContext ctxt; char *fontn | char *filen) + /Font /Category findresource + begin + /fontn 1024 string ResourceFileName + end + filen +endps + +/* Procedure for finding font file with GS. */ +defineps PSWGSFontFile(DPSContext ctxt; char *fontn | char *filen) + + userdict /Fontmap get % Get the Fontmap dictionary + /fontn get % Lookup the desired font + aload pop % Filename is stored in an array + dup type (test string) type ne % If fontn was just an alias + { % Get the real file name + userdict /Fontmap get exch get + aload pop + } if + filen + +endps + +/* PSWFontNames() puts on the PS stack a sequence of two elements pairs and + returns the number of the total elements. Each pair of elements consists + from the name of the font and either the filename where the font is defined + or the name of the font whose alias is. To get each pair of elements call + the PSWGetNextFont() function. + + Note: This procedure depends on DGS. The function to be used on a DPS system + conforming to red book should use the following statements to find out the + font names: + + /fonts [ + (%font%*) {100 string copy} 100 string filenameforall + ] def + + The mapping between font names and file name is DPS dependent. On NeXTSTEP + for example (and on systems conforming to red book), you can find out the + filename where a font is defined like below: + + /Font /Category findresource + begin + /Times-Roman 1024 string ResourceFileName + end + + This pushes on the stack %font%Times-Roman. The program should search in + the standard places a directory called `Times-Roman.font' to determine the + definition of the font. + + Maybe we should place in Postscript all the DPS dependencies and present to + the program the same interface. +*/ + +defineps PSWFontNames (| int* noOfFonts) + mark + /temp 1024 string def + userdict /Fontmap get { + /filename exch + % In 3.53 the filename was passed as name; in 4.03 it is passed + % as an array that contains the file name + dup type /arraytype eq {aload pop} if + temp cvs dup length string copy + def + /fontname exch temp cvs dup length string copy def + fontname filename + } + forall + counttomark 2 idiv noOfFonts +endps + +defineps PSWGetFontsArray (| char *fontname, *fileOrFont) + fileOrFont fontname +endps + + +/* PSWCompleteFilename() returns the complete path to the filename passed as + argument. The file is searched in the standard DGS places. */ +defineps PSWCompleteFilename (char* filename; | boolean *found; char* completePath) + (filename) findlibfile + {closefile completePath true found} {false found pop} ifelse +endps + + +defineps PSWGetFontAndType (| char* fontname; int* fonttype) + fontname fonttype +endps + + +/* Set the current font */ +defineps PSWSetFont (char* font; float fontMatrix[6]) + (font) findfont fontMatrix makefont setfont +endps + + +/* Get the font type */ +defineps PSWGetFontType (char* font; | int* fontType) + (font) findfont /FontType get fontType +endps diff --git a/Source/xdps/general.psw b/Source/xdps/general.psw new file mode 100644 index 0000000..463bdc3 --- /dev/null +++ b/Source/xdps/general.psw @@ -0,0 +1,65 @@ +/* + general.psw + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: August 1997 + + This file is part of the GNUstep GUI X/DPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include + +/* Initialize the graphic context */ +defineps PSWinitcontext (int gc, drawable, x, y) + gc drawable x y setXgcdrawable + initmatrix initclip + gsave initgraphics currenttransfer grestore settransfer +endps + + +defineps PSWGetTransform (DPSContext ctxt | float ctm[6], invctm[6]; + int *XOffset, *YOffset) + matrix currentmatrix dup ctm + matrix invertmatrix invctm + currentXoffset YOffset XOffset +endps + + +defineps PSWConcatMatrix (float matrix[6]) + matrix concat +endps + +defineps PSWSetMatrix (float matrix[6]) + matrix setmatrix +endps + +defineps PSWVersion (| char* versionstr) + version versionstr +endps + +defineps PSWRevision (| int* revstr) + revision revstr +endps + +defineps PSWProduct (| char* productname) + product productname +endps + + + diff --git a/Source/xdps/parseAFM.c b/Source/xdps/parseAFM.c new file mode 100644 index 0000000..ac2e781 --- /dev/null +++ b/Source/xdps/parseAFM.c @@ -0,0 +1,1138 @@ +/* + * parseAFM.c,v + * + * (c) Copyright 1991-1994 Adobe Systems Incorporated. + * All rights reserved. + * + * Permission to use, copy, modify, distribute, and sublicense this software + * and its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notices appear in all copies and that + * both those copyright notices and this permission notice appear in + * supporting documentation and that the name of Adobe Systems Incorporated + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. No trademark license + * to use the Adobe trademarks is hereby granted. If the Adobe trademark + * "Display PostScript"(tm) is used to describe this software, its + * functionality or for any other purpose, such use shall be limited to a + * statement that this software works in conjunction with the Display + * PostScript system. Proper trademark attribution to reflect Adobe's + * ownership of the trademark shall be given whenever any such reference to + * the Display PostScript system is made. + * + * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR + * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. + * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE + * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT + * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE. + * + * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems + * Incorporated which may be registered in certain jurisdictions + * + * Author: Adobe Systems Incorporated + */ + +#include +#include +#include +#include +#include +#include +#include "parseAFM.h" + +#define TRUE 1 +#define FALSE 0 +#define EOL '\n' /* end-of-line indicator */ +#define MAX_NAME 4096 /* max length for identifiers */ +#define BOOL int +#define FLAGS int + +#define lineterm '\n' /* line terminating character */ +#define normalEOF 1 /* return code from parsing routines used only */ + /* in this module */ +#define Space "space" /* used in string comparison to look for the width */ + /* of the space character to init the widths array */ +#define False "false" /* used in string comparison to check the value of */ + /* boolean keys (e.g. IsFixedPitch) */ +#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0) + + +/*************************** GLOBALS ***********************/ + +static char *ident = NULL; /* storage buffer for keywords */ + +/* "shorts" for fast case statement + * The values of each of these enumerated items correspond to an entry in the + * table of strings defined below. Therefore, if you add a new string as + * new keyword into the keyStrings table, you must also add a corresponding + * parseKey AND it MUST be in the same position! + * + * IMPORTANT: since the sorting algorithm is a binary search, the strings of + * keywords must be placed in lexicographical order, below. [Therefore, the + * enumerated items are not necessarily in lexicographical order, depending + * on the name chosen. BUT, they must be placed in the same position as the + * corresponding key string.] The NOPE shall remain in the last position, + * since it does not correspond to any key string, and it is used in the + * "recognize" procedure to calculate how many possible keys there are. + */ + +enum parseKey { + ASCENDER = 0, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT, + DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, + ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN, + FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH, + ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME, + NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, + STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS, + STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION, + UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT, + NOPE }; + +/* keywords for the system: + * This a table of all of the current strings that are vaild AFM keys. + * Each entry can be referenced by the appropriate parseKey value (an + * enumerated data type defined above). If you add a new keyword here, + * a corresponding parseKey MUST be added to the enumerated data type + * defined above, AND it MUST be added in the same position as the + * string is in this table. + * + * IMPORTANT: since the sorting algorithm is a binary search, the keywords + * must be placed in lexicographical order. And, NULL should remain at the + * end. + */ + +static char *keyStrings[] = { + "Ascender", "B", "C", "CC", "CapHeight", "Comment", + "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites", + "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern", + "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch", + "ItalicAngle", "KP", "KPX", "L", "N", + "Notice", "PCC", "StartCharMetrics", "StartComposites", + "StartFontMetrics", "StartKernData", "StartKernPairs", + "StartTrackKern", "TrackKern", "UnderlinePosition", + "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight", + NULL }; + +/*************************** PARSING ROUTINES **************/ + +/*************************** token *************************/ + +/* A "AFM File Conventions" tokenizer. That means that it will + * return the next token delimited by white space. See also + * the `linetoken' routine, which does a similar thing but + * reads all tokens until the next end-of-line. + */ + +static char *token(stream) + FILE *stream; +{ + int ch, idx; + + /* skip over white space */ + while ((ch = fgetc(stream)) == ' ' || ch == lineterm || ch == '\r' || + ch == ',' || ch == '\t' || ch == ';'); + + idx = 0; + while (ch != EOF && ch != ' ' && ch != lineterm && ch != '\r' + && ch != '\t' && ch != ':' && ch != ';') + { + ident[idx++] = ch; + ch = fgetc(stream); + } /* while */ + + if (ch == EOF && idx < 1) return ((char *)NULL); + if (idx >= 1 && ch != ':' ) ungetc(ch, stream); + if (idx < 1 ) ident[idx++] = ch; /* single-character token */ + ident[idx] = 0; + + return(ident); /* returns pointer to the token */ + +} /* token */ + + +/*************************** linetoken *************************/ + +/* "linetoken" will get read all tokens until the EOL character from + * the given stream. This is used to get any arguments that can be + * more than one word (like Comment lines and FullName). + */ + +static char *linetoken(stream) + FILE *stream; +{ + int ch, idx; + + while ((ch = fgetc(stream)) == ' ' || ch == '\t' ); + + idx = 0; + while (ch != EOF && ch != lineterm && ch != '\r') + { + ident[idx++] = ch; + ch = fgetc(stream); + } /* while */ + + ungetc(ch, stream); + ident[idx] = 0; + + return(ident); /* returns pointer to the token */ + +} /* linetoken */ + + +/*************************** recognize *************************/ + +/* This function tries to match a string to a known list of + * valid AFM entries (check the keyStrings array above). + * "ident" contains everything from white space through the + * next space, tab, or ":" character. + * + * The algorithm is a standard Knuth binary search. + */ + +static enum parseKey recognize(ident) + register char *ident; +{ + int lower = 0, upper = (int) NOPE, midpoint, cmpvalue; + BOOL found = FALSE; + + while ((upper >= lower) && !found) + { + midpoint = (lower + upper)/2; + if (keyStrings[midpoint] == NULL) break; + cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME); + if (cmpvalue == 0) found = TRUE; + else if (cmpvalue < 0) upper = midpoint - 1; + else lower = midpoint + 1; + } /* while */ + + if (found) return (enum parseKey) midpoint; + else return NOPE; + +} /* recognize */ + + +/************************* parseGlobals *****************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "StartCharMetrics" keyword, which essentially marks the + * end of the Global Font Information and the beginning of the character + * metrics information. + * + * If the caller of "parseFile" specified that it wanted the Global + * Font Information (as defined by the "AFM File Specification" + * document), then that information will be stored in the returned + * data structure. + * + * Any Global Font Information entries that are not found in a + * given file, will have the usual default initialization value + * for its type (i.e. entries of type int will be 0, etc). + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static BOOL parseGlobals(fp, gfi) + FILE *fp; + register AFMGlobalFontInfo *gfi; +{ + BOOL cont = TRUE, save = (gfi != NULL); + int error = afm_ok; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + error = afm_earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Global Font info section */ + /* without saving any of the data */ + switch (recognize(keyword)) + { + case STARTCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire global font info section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case STARTFONTMETRICS: + keyword = token(fp); + gfi->afmVersion = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->afmVersion, keyword); + break; + case COMMENT: + keyword = linetoken(fp); + break; + case FONTNAME: + keyword = token(fp); + gfi->fontName = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->fontName, keyword); + break; + case ENCODINGSCHEME: + keyword = token(fp); + gfi->encodingScheme = (char *) + malloc(strlen(keyword) + 1); + strcpy(gfi->encodingScheme, keyword); + break; + case FULLNAME: + keyword = linetoken(fp); + gfi->fullName = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->fullName, keyword); + break; + case FAMILYNAME: + keyword = linetoken(fp); + gfi->familyName = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->familyName, keyword); + break; + case WEIGHT: + keyword = token(fp); + gfi->weight = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->weight, keyword); + break; + case ITALICANGLE: + keyword = token(fp); + gfi->italicAngle = atof(keyword); + if (errno == ERANGE) error = afm_parseError; + break; + case ISFIXEDPITCH: + keyword = token(fp); + if (MATCH(keyword, False)) + gfi->isFixedPitch = 0; + else + gfi->isFixedPitch = 1; + break; + case UNDERLINEPOSITION: + keyword = token(fp); + gfi->underlinePosition = atoi(keyword); + break; + case UNDERLINETHICKNESS: + keyword = token(fp); + gfi->underlineThickness = atoi(keyword); + break; + case VERSION: + keyword = token(fp); + gfi->version = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->version, keyword); + break; + case NOTICE: + keyword = linetoken(fp); + gfi->notice = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->notice, keyword); + break; + case FONTBBOX: + keyword = token(fp); + gfi->fontBBox.llx = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.lly = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.urx = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.ury = atoi(keyword); + break; + case CAPHEIGHT: + keyword = token(fp); + gfi->capHeight = atoi(keyword); + break; + case XHEIGHT: + keyword = token(fp); + gfi->xHeight = atoi(keyword); + break; + case DESCENDER: + keyword = token(fp); + gfi->descender = atoi(keyword); + break; + case ASCENDER: + keyword = token(fp); + gfi->ascender = atoi(keyword); + break; + case STARTCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = afm_parseError; + break; + } /* switch */ + } /* while */ + + return(error); + +} /* parseGlobals */ + + + +/************************* parseCharWidths **************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndCharMetrics" keyword. It will save the character + * width info (as opposed to all of the character metric information) + * if requested by the caller of parseFile. Otherwise, it will just + * parse through the section without saving any information. + * + * If data is to be saved, parseCharWidths is passed in a pointer + * to an array of widths that has already been initialized by the + * standard value for unmapped character codes. This function parses + * the Character Metrics section only storing the width information + * for the encoded characters into the array using the character code + * as the index into that array. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static int parseCharWidths(fp, cwi) + FILE *fp; + register float *cwi; +{ + BOOL cont = TRUE, save = (cwi != NULL); + int pos = 0, error = afm_ok; + register char *keyword; + + while (cont) + { + keyword = token(fp); + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + if (keyword == NULL) + { + error = afm_earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Char Metrics section without */ + /* saving any of the data*/ + switch (recognize(keyword)) + { + case ENDCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire char metrics section, saving */ + /* only the char x-width info */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + keyword = token(fp); + pos = atoi(keyword); + break; + case XYWIDTH: + /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */ + keyword = token(fp); keyword = token(fp); /* eat values */ + error = afm_parseError; + break; + case XWIDTH: + keyword = token(fp); + if (pos >= 0) /* ignore unmapped chars */ + cwi[pos] = atof(keyword); + break; + case ENDCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case CHARNAME: /* eat values (so doesn't cause parseError) */ + keyword = token(fp); + break; + case CHARBBOX: + keyword = token(fp); keyword = token(fp); + keyword = token(fp); keyword = token(fp); + break; + case LIGATURE: + keyword = token(fp); keyword = token(fp); + break; + case NOPE: + default: + error = afm_parseError; + break; + } /* switch */ + } /* while */ + + return(error); + +} /* parseCharWidths */ + + +/************************* parseCharMetrics ************************/ + +/* This function is called by parseFile if the caller of parseFile + * requested that all character metric information be saved + * (as opposed to only the character width information). + * + * parseCharMetrics is passed in a pointer to an array of records + * to hold information on a per character basis. This function + * parses the Character Metrics section storing all character + * metric information for the ALL characters (mapped and unmapped) + * into the array. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static int parseCharMetrics(fp, fi) + FILE *fp; + register AFMFontInfo *fi; +{ + BOOL cont = TRUE, firstTime = TRUE; + int error = afm_ok, count = 0; + register AFMCharMetricInfo *temp = fi->cmi; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + { + error = afm_earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + if (count < fi->numOfChars) + { + if (firstTime) firstTime = FALSE; + else temp++; + temp->code = atoi(token(fp)); + count++; + } + else + { + error = afm_parseError; + cont = FALSE; + } + break; + case XYWIDTH: + temp->wx = atoi(token(fp)); + temp->wy = atoi(token(fp)); + break; + case XWIDTH: + temp->wx = atoi(token(fp)); + break; + case CHARNAME: + keyword = token(fp); + temp->name = (char *) malloc(strlen(keyword) + 1); + strcpy(temp->name, keyword); + break; + case CHARBBOX: + temp->charBBox.llx = atoi(token(fp)); + temp->charBBox.lly = atoi(token(fp)); + temp->charBBox.urx = atoi(token(fp)); + temp->charBBox.ury = atoi(token(fp)); + break; + case LIGATURE: { + AFMLigature **tail = &(temp->ligs); + AFMLigature *node = *tail; + + if (*tail != NULL) + { + while (node->next != NULL) + node = node->next; + tail = &(node->next); + } + + *tail = (AFMLigature *) calloc(1, sizeof(AFMLigature)); + keyword = token(fp); + (*tail)->succ = (char *) malloc(strlen(keyword) + 1); + strcpy((*tail)->succ, keyword); + keyword = token(fp); + (*tail)->lig = (char *) malloc(strlen(keyword) + 1); + strcpy((*tail)->lig, keyword); + break; } + case ENDCHARMETRICS: + cont = FALSE;; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = afm_parseError; + break; + } /* switch */ + } /* while */ + + if ((error == afm_ok) && (count != fi->numOfChars)) + error = afm_parseError; + + return(error); + +} /* parseCharMetrics */ + + + +/************************* parseTrackKernData ***********************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndTrackKern" or "EndKernData" keywords. It will save the + * track kerning data if requested by the caller of parseFile. + * + * parseTrackKernData is passed in a pointer to the FontInfo record. + * If data is to be saved, the FontInfo record will already contain + * a valid pointer to storage for the track kerning data. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static int parseTrackKernData(fp, fi) + FILE *fp; + register AFMFontInfo *fi; +{ + BOOL cont = TRUE, save = (fi->tkd != NULL); + int pos = 0, error = afm_ok, tcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + { + error = afm_earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Track Kerning Data */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDTRACKKERN: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Track Kerning Data section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case TRACKKERN: + if (tcount < fi->numOfTracks) + { + keyword = token(fp); + fi->tkd[pos].degree = atoi(keyword); + keyword = token(fp); + fi->tkd[pos].minPtSize = atof(keyword); + if (errno == ERANGE) error = afm_parseError; + keyword = token(fp); + fi->tkd[pos].minKernAmt = atof(keyword); + if (errno == ERANGE) error = afm_parseError; + keyword = token(fp); + fi->tkd[pos].maxPtSize = atof(keyword); + if (errno == ERANGE) error = afm_parseError; + keyword = token(fp); + fi->tkd[pos++].maxKernAmt = atof(keyword); + if (errno == ERANGE) error = afm_parseError; + tcount++; + } + else + { + error = afm_parseError; + cont = FALSE; + } + break; + case ENDTRACKKERN: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = afm_parseError; + break; + } /* switch */ + } /* while */ + + if (error == afm_ok && tcount != fi->numOfTracks) + error = afm_parseError; + + return(error); + +} /* parseTrackKernData */ + + +/************************* parsePairKernData ************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndKernPairs" or "EndKernData" keywords. It will save + * the pair kerning data if requested by the caller of parseFile. + * + * parsePairKernData is passed in a pointer to the FontInfo record. + * If data is to be saved, the FontInfo record will already contain + * a valid pointer to storage for the pair kerning data. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static int parsePairKernData(fp, fi) + FILE *fp; + register AFMFontInfo *fi; +{ + BOOL cont = TRUE, save = (fi->pkd != NULL); + int pos = 0, error = afm_ok, pcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + { + error = afm_earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Pair Kerning Data */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDKERNPAIRS: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Pair Kerning Data section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case KERNPAIR: + if (pcount < fi->numOfPairs) + { + keyword = token(fp); + fi->pkd[pos].name1 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name1, keyword); + keyword = token(fp); + fi->pkd[pos].name2 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name2, keyword); + keyword = token(fp); + fi->pkd[pos].xamt = atoi(keyword); + keyword = token(fp); + fi->pkd[pos++].yamt = atoi(keyword); + pcount++; + } + else + { + error = afm_parseError; + cont = FALSE; + } + break; + case KERNPAIRXAMT: + if (pcount < fi->numOfPairs) + { + keyword = token(fp); + fi->pkd[pos].name1 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name1, keyword); + keyword = token(fp); + fi->pkd[pos].name2 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name2, keyword); + keyword = token(fp); + fi->pkd[pos++].xamt = atoi(keyword); + pcount++; + } + else + { + error = afm_parseError; + cont = FALSE; + } + break; + case ENDKERNPAIRS: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = afm_parseError; + break; + } /* switch */ + } /* while */ + + if (error == afm_ok && pcount != fi->numOfPairs) + error = afm_parseError; + + return(error); + +} /* parsePairKernData */ + + +/************************* parseCompCharData **************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndComposites" keyword. It will save the composite + * character data if requested by the caller of parseFile. + * + * parseCompCharData is passed in a pointer to the FontInfo record, and + * a boolean representing if the data should be saved. + * + * This function will create the appropriate amount of storage for + * the composite character data and store a pointer to the storage + * in the FontInfo record. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static int parseCompCharData(fp, fi) + FILE *fp; + register AFMFontInfo *fi; +{ + BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL); + int pos = 0, j = 0, error = afm_ok, ccount = 0, pcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + error = afm_earlyEOF; + break; /* get out of loop */ + } + if (ccount > fi->numOfComps) + { + error = afm_parseError; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Composite Character info */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDCOMPOSITES: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Composite Character info section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case COMPCHAR: + if (ccount < fi->numOfComps) + { + keyword = token(fp); + if (pcount != fi->ccd[pos].numOfPieces) + error = afm_parseError; + pcount = 0; + if (firstTime) firstTime = FALSE; + else pos++; + fi->ccd[pos].ccName = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->ccd[pos].ccName, keyword); + keyword = token(fp); + fi->ccd[pos].numOfPieces = atoi(keyword); + fi->ccd[pos].pieces = (AFMPcc *) + calloc(fi->ccd[pos].numOfPieces, sizeof(AFMPcc)); + j = 0; + ccount++; + } + else + { + error = afm_parseError; + cont = FALSE; + } + break; + case COMPCHARPIECE: + if (pcount < fi->ccd[pos].numOfPieces) + { + keyword = token(fp); + fi->ccd[pos].pieces[j].pccName = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->ccd[pos].pieces[j].pccName, keyword); + keyword = token(fp); + fi->ccd[pos].pieces[j].deltax = atoi(keyword); + keyword = token(fp); + fi->ccd[pos].pieces[j++].deltay = atoi(keyword); + pcount++; + } + else + error = afm_parseError; + break; + case ENDCOMPOSITES: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = afm_parseError; + break; + } /* switch */ + } /* while */ + + if (error == afm_ok && ccount != fi->numOfComps) + error = afm_parseError; + + return(error); + +} /* parseCompCharData */ + + + + +/*************************** 'PUBLIC' FUNCTION ********************/ + + +/*************************** parseFile *****************************/ + +/* parseFile is the only 'public' procedure available. It is called + * from an application wishing to get information from an AFM file. + * The caller of this function is responsible for locating and opening + * an AFM file and handling all errors associated with that task. + * + * parseFile expects 3 parameters: a vaild file pointer, a pointer + * to a (FontInfo *) variable (for which storage will be allocated and + * the data requested filled in), and a mask specifying which + * data from the AFM File should be saved in the FontInfo structure. + * + * The file will be parsed and the requested data will be stored in + * a record of type FontInfo (refer to ParseAFM.h). + * + * parseFile returns an error code as defined in parseAFM.h. + * + * The position of the read/write pointer associated with the file + * pointer upon return of this function is undefined. + */ + +extern int AFMParseFile (fp, fi, flags) + FILE *fp; + AFMFontInfo **fi; + FLAGS flags; +{ + + int code = afm_ok; /* return code from each of the parsing routines */ + int error = afm_ok; /* used as the return code from this function */ + + register char *keyword; /* used to store a token */ + + + /* storage data for the global variable ident */ + ident = (char *) calloc(MAX_NAME, sizeof(char)); + if (ident == NULL) {error = afm_storageProblem; return(error);} + + (*fi) = (AFMFontInfo *) calloc(1, sizeof(AFMFontInfo)); + if ((*fi) == NULL) {error = afm_storageProblem; return(error);} + + if (flags & AFM_G) + { + (*fi)->gfi = (AFMGlobalFontInfo *) calloc(1, sizeof(AFMGlobalFontInfo)); + if ((*fi)->gfi == NULL) {error = afm_storageProblem; return(error);} + } + + /* The AFM File begins with Global Font Information. This section */ + /* will be parsed whether or not information should be saved. */ + code = parseGlobals(fp, (*fi)->gfi); + + if (code < 0) error = code; + + /* The Global Font Information is followed by the Character Metrics */ + /* section. Which procedure is used to parse this section depends on */ + /* how much information should be saved. If all of the metrics info */ + /* is wanted, parseCharMetrics is called. If only the character widths */ + /* is wanted, parseCharWidths is called. parseCharWidths will also */ + /* be called in the case that no character data is to be saved, just */ + /* to parse through the section. */ + + if ((code != normalEOF) && (code != afm_earlyEOF)) + { + (*fi)->numOfChars = atoi(token(fp)); + if (flags & (AFM_M ^ AFM_W)) + { + (*fi)->cmi = (AFMCharMetricInfo *) + calloc((*fi)->numOfChars, sizeof(AFMCharMetricInfo)); + if ((*fi)->cmi == NULL) {error = afm_storageProblem; return(error);} + code = parseCharMetrics(fp, *fi); + } + else + { + if (flags & AFM_W) + { + (*fi)->cwi = (float *) calloc(256, sizeof(float)); + if ((*fi)->cwi == NULL) + { + error = afm_storageProblem; + return(error); + } + } + /* parse section regardless */ + code = parseCharWidths(fp, (*fi)->cwi); + } /* else */ + } /* if */ + + if ((error != afm_earlyEOF) && (code < 0)) error = code; + + /* The remaining sections of the AFM are optional. This code will */ + /* look at the next keyword in the file to determine what section */ + /* is next, and then allocate the appropriate amount of storage */ + /* for the data (if the data is to be saved) and call the */ + /* appropriate parsing routine to parse the section. */ + + while ((code != normalEOF) && (code != afm_earlyEOF)) + { + keyword = token(fp); + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + code = afm_earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case STARTKERNDATA: + break; + case ENDKERNDATA: + break; + case STARTTRACKKERN: + keyword = token(fp); + if (flags & AFM_T) + { + (*fi)->numOfTracks = atoi(keyword); + (*fi)->tkd = (AFMTrackKernData *) + calloc((*fi)->numOfTracks, sizeof(AFMTrackKernData)); + if ((*fi)->tkd == NULL) + { + error = afm_storageProblem; + return(error); + } + } /* if */ + code = parseTrackKernData(fp, *fi); + break; + case STARTKERNPAIRS: + keyword = token(fp); + if (flags & AFM_P) + { + (*fi)->numOfPairs = atoi(keyword); + (*fi)->pkd = (AFMPairKernData *) + calloc((*fi)->numOfPairs, sizeof(AFMPairKernData)); + if ((*fi)->pkd == NULL) + { + error = afm_storageProblem; + return(error); + } + } /* if */ + code = parsePairKernData(fp, *fi); + break; + case STARTCOMPOSITES: + keyword = token(fp); + if (flags & AFM_C) + { + (*fi)->numOfComps = atoi(keyword); + (*fi)->ccd = (AFMCompCharData *) + calloc((*fi)->numOfComps, sizeof(AFMCompCharData)); + if ((*fi)->ccd == NULL) + { + error = afm_storageProblem; + return(error); + } + } /* if */ + code = parseCompCharData(fp, *fi); + break; + case ENDFONTMETRICS: + code = normalEOF; + break; + case NOPE: + default: + code = afm_parseError; + break; + } /* switch */ + + if ((error != afm_earlyEOF) && (code < 0)) error = code; + + } /* while */ + + if ((error != afm_earlyEOF) && (code < 0)) error = code; + + if (ident != NULL) { free(ident); ident = NULL; } + + return(error); + +} /* parseFile */ diff --git a/Source/xdps/parseAFM.h b/Source/xdps/parseAFM.h new file mode 100644 index 0000000..4edaa6c --- /dev/null +++ b/Source/xdps/parseAFM.h @@ -0,0 +1,324 @@ +/* + * parseAFM.h,v + * + * (c) Copyright 1991-1994 Adobe Systems Incorporated. + * All rights reserved. + * + * Permission to use, copy, modify, distribute, and sublicense this software + * and its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notices appear in all copies and that + * both those copyright notices and this permission notice appear in + * supporting documentation and that the name of Adobe Systems Incorporated + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. No trademark license + * to use the Adobe trademarks is hereby granted. If the Adobe trademark + * "Display PostScript"(tm) is used to describe this software, its + * functionality or for any other purpose, such use shall be limited to a + * statement that this software works in conjunction with the Display + * PostScript system. Proper trademark attribution to reflect Adobe's + * ownership of the trademark shall be given whenever any such reference to + * the Display PostScript system is made. + * + * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR + * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. + * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE + * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT + * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE. + * + * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems + * Incorporated which may be registered in certain jurisdictions + * + * Author: Adobe Systems Incorporated + */ + +/*************************************************************** +** +** This header file is used in conjuction with the parseAFM.c file. +** Together these files provide the functionality to parse Adobe Font +** Metrics files and store the information in predefined data structures. +** It is intended to work with an application program that needs font metric +** information. The program can be used as is by making a procedure call to +** parse an AFM file and have the data stored, or an application developer +** may wish to customize the code. +** +** This header file defines the data structures used as well as the key +** strings that are currently recognized by this version of the AFM parser. +** This program is based on the document "Adobe Font Metrics Files, +** Specification Version 2.0". +** +** AFM files are separated into distinct sections of different data. Because +** of this, the parseAFM program can parse a specified file to only save +** certain sections of information based on the application's needs. A record +** containing the requested information will be returned to the application. +** +** AFM files are divided into five sections of data: +** 1) The Global Font Information +** 2) The Character Metrics Information +** 3) The Track Kerning Data +** 4) The Pair-Wise Kerning Data +** 5) The Composite Character Data +** +** Basically, the application can request any of these sections independent +** of what other sections are requested. In addition, in recognizing that +** many applications will want ONLY the x-width of characters and not all +** of the other character metrics information, there is a way to receive +** only the width information so as not to pay the storage cost for the +** unwanted data. An application should never request both the +** "quick and dirty" char metrics (widths only) and the Character Metrics +** Information since the Character Metrics Information will contain all +** of the character widths as well. +** +** There is a procedure in parseAFM.c, called parseFile, that can be +** called from any application wishing to get information from the AFM File. +** This procedure expects 3 parameters: a vaild file descriptor, a pointer +** to a (AFMFontInfo *) variable (for which space will be allocated and then +** will be filled in with the data requested), and a mask specifying +** which data from the AFM File should be saved in the AFMFontInfo structure. +** +** The flags that can be used to set the appropriate mask are defined below. +** In addition, several commonly used masks have already been defined. +** +** History: +** original: DSM Thu Oct 20 17:39:59 PDT 1988 +** modified: DSM Mon Jul 3 14:17:50 PDT 1989 +** - added 'storageProblem' return code +** - fixed typos +** +**************************************************************/ + +#include + +/* +** Flags that can be AND'ed together to specify exactly what +** information from the AFM file should be saved. +*/ +#define AFM_G 0x01 /* 0000 0001 */ /* Global Font Info */ +#define AFM_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */ +#define AFM_M 0x06 /* 0000 0110 */ /* All Char Metric Info */ +#define AFM_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */ +#define AFM_T 0x10 /* 0001 0000 */ /* Track Kerning Info */ +#define AFM_C 0x20 /* 0010 0000 */ /* Composite Char Info */ + +/* +** Commonly used flags +*/ +#define AFM_GW (AFM_G | AFM_W) +#define AFM_GM (AFM_G | AFM_M) +#define AFM_GMP (AFM_G | AFM_M | AFM_P) +#define AFM_GMK (AFM_G | AFM_M | AFM_P | AFM_T) +#define AFM_ALL (AFM_G | AFM_M | AFM_P | AFM_T | AFM_C) + +/* +** Possible return codes from the AFMParseFile procedure. +** +** afm_ok means there were no problems parsing the file. +** +** afm_parseError means that there was some kind of parsing error, but the +** parser went on. This could include problems like the count for any given +** section does not add up to how many entries there actually were, or +** there was a key that was not recognized. The return record may contain +** vaild data or it may not. +** +** afm_earlyEOF means that an End of File was encountered before expected. This +** may mean that the AFM file had been truncated, or improperly formed. +** +** afm_storageProblem means that there were problems allocating storage for +** the data structures that would have contained the AFM data. +*/ +#define afm_ok 0 +#define afm_parseError -1 +#define afm_earlyEOF -2 +#define afm_storageProblem -3 + +/************************* TYPES ********************************/ +/* +** Below are all of the data structure definitions. These structures +** try to map as closely as possible to grouping and naming of data +** in the AFM Files. +*/ + +/* +** Bounding box definition. Used for the Font BBox as well as the +** Character BBox. +*/ +typedef struct +{ + int llx; /* lower left x-position */ + int lly; /* lower left y-position */ + int urx; /* upper right x-position */ + int ury; /* upper right y-position */ +} AFMBBox; + +/* +** Global Font information. +** The key that each field is associated with is in comments. For an +** explanation about each key and its value please refer to the AFM +** documentation (full title & version given above). +*/ +typedef struct +{ + char *afmVersion; /* key: StartFontMetrics */ + char *fontName; /* key: FontName */ + char *fullName; /* key: FullName */ + char *familyName; /* key: FamilyName */ + char *weight; /* key: Weight */ + float italicAngle; /* key: ItalicAngle */ + int isFixedPitch; /* key: IsFixedPitch */ + AFMBBox fontBBox; /* key: FontBBox */ + int underlinePosition; /* key: UnderlinePosition */ + int underlineThickness; /* key: UnderlineThickness */ + char *version; /* key: Version */ + char *notice; /* key: Notice */ + char *encodingScheme; /* key: EncodingScheme */ + int capHeight; /* key: CapHeight */ + int xHeight; /* key: XHeight */ + int ascender; /* key: Ascender */ + int descender; /* key: Descender */ +} AFMGlobalFontInfo; + +/* +** Ligature definition is a linked list since any character can have +** any number of ligatures. +*/ +typedef struct _t_ligature +{ + char *succ, *lig; + struct _t_ligature *next; +} AFMLigature; + +/* +** Character Metric Information. This structure is used only if ALL +** character metric information is requested. If only the character +** widths is requested, then only an array of the character x-widths +** is returned. +** +** The key that each field is associated with is in comments. For an +** explanation about each key and its value please refer to the +** Character Metrics section of the AFM documentation (full title +** & version given above). +*/ +typedef struct +{ + int code, /* key: C */ + wx, /* key: WX */ + wy; /* together wx and wy are associated with key: W */ + char *name; /* key: N */ + AFMBBox charBBox; /* key: B */ + AFMLigature *ligs; /* key: L (linked list; not a fixed number of Ls */ +} AFMCharMetricInfo; + +/* +** Track kerning data structure. +** The fields of this record are the five values associated with every +** TrackKern entry. +** +** For an explanation about each value please refer to the +** Track Kerning section of the AFM documentation (full title +** & version given above). +*/ +typedef struct +{ + int degree; + float minPtSize, + minKernAmt, + maxPtSize, + maxKernAmt; +} AFMTrackKernData; + +/* +** Pair Kerning data structure. +** The fields of this record are the four values associated with every +** KP entry. For KPX entries, the yamt will be zero. +** +** For an explanation about each value please refer to the +** Pair Kerning section of the AFM documentation (full title +** & version given above). +*/ +typedef struct +{ + char *name1; + char *name2; + int xamt, + yamt; +} AFMPairKernData; + +/* +** PCC is a piece of a composite character. This is a sub structure of a +** compCharData described below. +** These fields will be filled in with the values from the key PCC. +** +** For an explanation about each key and its value please refer to the +** Composite Character section of the AFM documentation (full title +** & version given above). +*/ +typedef struct +{ + char *pccName; + int deltax, + deltay; +} AFMPcc; + +/* +** Composite Character Information data structure. +** The fields ccName and numOfPieces are filled with the values associated +** with the key CC. The field pieces points to an array (size = numOfPieces) +** of information about each of the parts of the composite character. That +** array is filled in with the values from the key PCC. +** +** For an explanation about each key and its value please refer to the +** Composite Character section of the AFM documentation (full title +** & version given above). +*/ +typedef struct +{ + char *ccName; + int numOfPieces; + AFMPcc *pieces; +} AFMCompCharData; + +/* +** AFMFontInfo +** Record type containing pointers to all of the other data +** structures containing information about a font. +** A a record of this type is filled with data by the +** parseFile function. +*/ +typedef struct +{ + AFMGlobalFontInfo *gfi; /* ptr to a GlobalAFMFontInfo record */ + float *cwi; /* ptr to 256 element array of char widths */ + int numOfChars; /* number of entries in char metrics array */ + AFMCharMetricInfo *cmi; /* ptr to char metrics array */ + int numOfTracks; /* number to entries in track kerning array */ + AFMTrackKernData *tkd; /* ptr to track kerning array */ + int numOfPairs; /* number to entries in pair kerning array */ + AFMPairKernData *pkd; /* ptr to pair kerning array */ + int numOfComps; /* number to entries in comp char array */ + AFMCompCharData *ccd; /* ptr to comp char array */ +} AFMFontInfo; + +/************************* PROCEDURES ***************************/ + +/* +** Call this procedure to do the grunt work of parsing an AFM file. +** +** "fp" should be a valid file pointer to an AFM file. +** +** "fi" is a pointer to a pointer to a AFMFontInfo record sturcture +** (defined above). Storage for the AFMFontInfo structure will be +** allocated in parseFile and the structure will be filled in +** with the requested data from the AFM File. +** +** "flags" is a mask with bits set representing what data should +** be saved. Defined above are valid flags that can be used to set +** the mask, as well as a few commonly used masks. +** +** The possible return codes from AFMParseFile are defined above. +*/ + +extern int AFMParseFile ( /* FILE *fp; AFMFontInfo **fi; int flags; */ ); diff --git a/Source/xlib/GNUmakefile b/Source/xlib/GNUmakefile new file mode 100644 index 0000000..72a7034 --- /dev/null +++ b/Source/xlib/GNUmakefile @@ -0,0 +1,73 @@ +# +# Main makefile for GNUstep Backend xlib +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# If you are interested in a warranty or support for this source code, +# contact Scott Christley at scottc@net-community.com +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../back.make +include $(GNUSTEP_MAKEFILES)/common.make + +include ../../config.make + +SUBPROJECT_NAME=xlib + +# The C source files to be compiled +xlib_C_FILES = xrtools.c + +# The Objective-C source files to be compiled +xlib_OBJC_FILES = \ +XGBitmapImageRep.m \ +XGBitmap.m \ +XGCommonFont.m \ +XGFont.m \ +XGFontManager.m \ +XGContext.m \ +XGGState.m \ +XGGeometry.m \ +linking.m + +ifeq ($(WITH_XFT),yes) +xlib_OBJC_FILES += XftFontInfo.m +endif + +xlib_HEADER_FILES_DIR = ../../Headers/xlib +xlib_HEADER_FILES_INSTALL_DIR = gnustep/xlib + +xlib_HEADER_FILES = \ +XGContext.h \ +XGPrivate.h \ +XGGeometry.h \ +XGGState.h \ +XGGStateOps.h + +-include GNUmakefile.preamble + +include $(GNUSTEP_MAKEFILES)/subproject.make + +-include GNUmakefile.postamble + diff --git a/Source/xlib/GNUmakefile.preamble b/Source/xlib/GNUmakefile.preamble new file mode 100644 index 0000000..f211065 --- /dev/null +++ b/Source/xlib/GNUmakefile.preamble @@ -0,0 +1,53 @@ +# +# GNUmakefile.preamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +GNUSTEP_INSTALL_LIBDIR=$(GNUSTEP_LIBRARIES_ROOT) +ADDITIONAL_CPPFLAGS += -Wall $(CONFIG_SYSTEM_DEFS) + +# Additional flags to pass to the Objective-C compiler +#ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +#ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I../../Headers \ + -I../$(GNUSTEP_TARGET_DIR) + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# + + diff --git a/Source/xlib/XGBitmap.m b/Source/xlib/XGBitmap.m new file mode 100644 index 0000000..ea850b2 --- /dev/null +++ b/Source/xlib/XGBitmap.m @@ -0,0 +1,1144 @@ +/* + XGBitmapImageRep.m + + NSBitmapImageRep for GNUstep GUI X/GPS Backend + + Copyright (C) 1996-1999 Free Software Foundation, Inc. + + Author: Adam Fedor + Author: Scott Christley + Date: Feb 1996 + Author: Felipe A. Rodriguez + Date: May 1998 + Author: Richard Frith-Macdonald + Date: Mar 1999 + + This file is part of the GNUstep GUI X/GPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include + +#include +#include + +#include +#include "xlib/XGPrivate.h" + +/* Macros that make it easier to convert + between (r,g,b) <--> pixels. +*/ + +#define VARIABLES_DECLARATION \ + unsigned char _rshift, _gshift, _bshift, _ashift; \ + unsigned int _rmask, _gmask, _bmask, _amask; \ + unsigned char _rwidth, _gwidth, _bwidth, _awidth + + + +#define InitRGBShiftsAndMasks(rs,rw,gs,gw,bs,bw,as,aw) \ + do { \ + _rshift = rs; \ + _rmask = (1<> _rshift) & _rmask; \ + g = (pixel >> _gshift) & _gmask; \ + b = (pixel >> _bshift) & _bmask; \ + } while(0) + +/* Note that RGBToPixel assumes that the + r,g,b values are in the correct domain. + If not, the value is nonsense. +*/ + +#define RGBToPixel(r,g,b, pixel) \ + do { \ + pixel = ((r) << _rshift) \ + |((g) << _gshift) \ + |((b) << _bshift); \ + } while(0) + + +/* Composite source image (pixmap) onto a destination image with alpha. + Only works for op=Sover now + + Assumptions: + - all images are valid. + - srect is completely contained in the source images + - srect put at the origin is contained in the destination image +*/ +int +_pixmap_combine_alpha(RContext *context, + RXImage *source_im, RXImage *source_alpha, + RXImage *dest_im, RXImage *dest_alpha, + XRectangle srect, + NSCompositingOperation op, + XGDrawMechanism drawMechanism, + float fraction) +{ + unsigned long pixel; + unsigned short oldAlpha = 0; + unsigned long oldPixel = 0; + unsigned short oldAr = 0; + unsigned short oldAg = 0; + unsigned short oldAb = 0; + unsigned char oldBr = 0; + unsigned char oldBg = 0; + unsigned char oldBb = 0; + + if (drawMechanism == XGDM_FAST15 + || drawMechanism == XGDM_FAST16 + || drawMechanism == XGDM_FAST32 + || drawMechanism == XGDM_FAST32_BGR) + { + VARIABLES_DECLARATION; + unsigned row; + + switch (drawMechanism) + { + case XGDM_FAST15: + InitRGBShiftsAndMasks(10,5,5,5,0,5,0,8); + break; + case XGDM_FAST16: + InitRGBShiftsAndMasks(11,5,5,6,0,5,0,8); + break; + case XGDM_FAST32: + InitRGBShiftsAndMasks(16,8,8,8,0,8,0,8); + break; + case XGDM_FAST32_BGR: + InitRGBShiftsAndMasks(0,8,8,8,16,8,0,8); + break; + default: + NSLog(@"Huh? Backend confused about XGDrawMechanism"); + //Try something. With a bit of luck we see + //which picture goes wrong. + InitRGBShiftsAndMasks(11,5,5,6,0,5,0,8); + } + for (row = 0; row < srect.height; row++) + { + unsigned col; + + for (col = 0; col < srect.width; col++) + { + unsigned r, g, b, alpha; + pixel = XGetPixel(source_im->image, + col+srect.x, row+srect.y); + + PixelToRGB(pixel,r,g,b); + + pixel = 255; + if (source_alpha) + pixel = XGetPixel(source_alpha->image, + col+srect.x, row+srect.y); + + if (fraction < 1) + pixel *= fraction; + alpha = (pixel >> _ashift) & _amask; + + if (alpha == 0) + continue; // background unchanged. + if (alpha != _amask) + { // We really have something to mix! + unsigned short ialpha = _amask - alpha; + /* + * Get the background pixel and convert to RGB. + */ + pixel = XGetPixel(dest_im->image, col, row); + if (pixel != oldPixel) + { + oldPixel = pixel; + PixelToRGB(pixel, oldBr,oldBg,oldBb); + oldAlpha = 0; + } + if (alpha != oldAlpha) + { + oldAlpha = alpha; + oldAr = ialpha * oldBr; + oldAg = ialpha * oldBg; + oldAb = ialpha * oldBb; + } + + // mix in alpha to produce RGB out + r = (oldAr + (r*alpha))/_amask; + g = (oldAg + (g*alpha))/_amask; + b = (oldAb + (b*alpha))/_amask; + } + RGBToPixel(r,g,b,pixel); + XPutPixel(dest_im->image, col, row, pixel); + if (dest_alpha) + { + unsigned short dalpha; + unsigned long dpixel; + /* Alpha gets mixed the same as all the + other color components */ + dpixel = XGetPixel(dest_alpha->image, col, row); + dalpha = (dpixel >> _ashift) & _amask; + dalpha = alpha + dalpha * (_amask - alpha)/_amask; + XPutPixel(dest_alpha->image, col, row, dalpha << _ashift ); + } + } + } + } + else + { + XColor c2; + unsigned row; + + /* + * This block of code should be totally portable as it uses the + * 'official' X mechanism for converting from pixel values to + * RGB color values - on the downside, it's very slow. + */ + pixel = (unsigned long)-1; // Never valid? + c2.pixel = pixel; + + + for (row = 0; row < srect.height; row++) + { + unsigned col; + + for (col = 0; col < srect.width; col++) + { + int r, g, b, alpha; + XColor pcolor, acolor, c0, c1; + pcolor.pixel = XGetPixel(source_im->image, + col + srect.x, row + srect.y); + XQueryColor(context->dpy, context->cmap, &pcolor); + r = pcolor.red >> 8; + g = pcolor.green >> 8; + b = pcolor.blue >> 8; + alpha = 255; + if (source_alpha) + { + acolor.pixel = XGetPixel(source_alpha->image, + col + srect.x, row + srect.y); + XQueryColor(context->dpy, context->cmap, &acolor); + alpha = acolor.red >> 8; + } + if (alpha == 0) + continue; // background unchanged. + + if (fraction < 1) + alpha *= fraction; + if (alpha == 255) + { + c1 = pcolor; + } + else + { + unsigned short ialpha = 255 - alpha; + + /* + * RGB color components in X are 16-bit values - + * but our bitmap contains 8-bit values so we must + * adjust our values up to 16-bit, which we can do + * by increasing their alpha component by 256. + */ + alpha <<= 8; + + /* + * Get the background pixel and convert to RGB if + * we haven't already done the conversion earlier. + */ + c0.pixel = XGetPixel(dest_im->image, col, row); + if (c0.pixel != oldPixel) + { + oldPixel = c0.pixel; + XQueryColor(context->dpy, context->cmap, &c0); + } + + // mix in alpha to produce RGB out + c1.red = ((c0.red*ialpha) + (r*alpha))/255; + c1.green = ((c0.green*ialpha) + (g*alpha))/255; + c1.blue = ((c0.blue*ialpha) + (b*alpha))/255; + } + + /* + * Convert the X RGB value to a colormap entry if we + * don't already have one. Then set the pixel. + * NB. XAllocColor() will not necessarily return a + * color with exactly the rgb components we gave it, so + * we must record those components beforehand. + */ + if (c2.pixel == (unsigned long)-1 + || c2.red != c1.red + || c2.green != c1.green + || c2.blue != c1.blue) + { + c2.red = c1.red; + c2.green = c1.green; + c2.blue = c1.blue; + XAllocColor(context->dpy, context->cmap, &c1); + c2.pixel = c1.pixel; + } + XPutPixel(dest_im->image, col, row, c1.pixel); + if (dest_alpha) + { + XColor da; + /* Alpha gets mixed the same as all the + other color components */ + da.pixel = XGetPixel(dest_alpha->image, col, row); + XQueryColor(context->dpy, context->cmap, &da); + da.red = acolor.red + da.red * (65536 - acolor.red)/65536; + da.green = da.blue = da.red; + XAllocColor(context->dpy, context->cmap, &da); + XPutPixel(dest_alpha->image, col, row, da.pixel); + } + } + } + } + + return 0; +} + +/* + * The following structure holds the information necessary for unpacking + * a bitmap data object. It holds an index into the raw data, precalculated + * spans for magnification and minifaction, plus the buffer which holds + * a complete line of colour to be output to the screen in RGBA form. + */ + +struct _bitmap_decompose { + unsigned char *plane[5]; + int bit_off[5]; + long image_w, image_h, screen_w, screen_h; + int bps, spp, bpp, bpr; + BOOL has_alpha, is_direct_packed, one_is_black; + int cspace, pro_mul; + + unsigned char *r, *g, *b, *a; + int cur_image_row, cur_screen_row; + int first_vis_col, last_vis_col; + + int *row_starts, *row_ends, *col_starts, *col_ends; + int *r_sum, *g_sum, *b_sum, *a_sum, *pix_count; +}; + +/* + * Here we extract a value a given number of bits wide from a bit + * offset into a block of memory starting at "base". The bit numbering + * is assumed to be such that a bit offset of zero and a width of 4 gives + * the upper 4 bits of the first byte, *not* the lower 4 bits. We do allow + * the value to cross a byte boundary, though it is unclear as to whether + * this is strictly necessary for OpenStep tiffs. + */ + +static int +_get_bit_value(unsigned char *base, long msb_off, int bit_width) +{ + long lsb_off, byte1, byte2; + int shift, value; + + /* + * Firstly we calculate the position of the msb and lsb in terms + * of bit offsets and thus byte offsets. The shift is the number of + * spare bits left in the byte containing the lsb + */ + lsb_off= msb_off+bit_width-1; + byte1= msb_off/8; + byte2= lsb_off/8; + shift= 7-(lsb_off%8); + + /* + * We now get the value from the byte array, possibly using two bytes if + * the required set of bits crosses the byte boundary. This is then shifted + * down to it's correct position and extraneous bits masked off before + * being returned. + */ + value=base[byte2]; + if(byte1!=byte2) + value|= base[byte1]<<8; + value >>= shift; + + return value & ((1<cur_screen_row >= img->screen_h) + { + NSLog(@"Tried to create too many screen rows"); + return; + } + + if(img->is_direct_packed) + /* do direct copy, only limited formats supported */ + { + unsigned char *ptr = img->plane[0]; + unsigned char *rptr = img->r; + unsigned char *gptr = img->g; + unsigned char *bptr = img->b; + unsigned char *aptr = img->a; + BOOL oib = img->one_is_black; + BOOL ha = img->has_alpha; + BOOL is_grey = (img->cspace == gray_colorspace); + int i, fc = img->first_vis_col, lc = img->last_vis_col; + + /* do the offset from the right */ + ptr += fc * ( (is_grey ? 1 : 3) + (ha ? 1 : 0) ); + rptr += fc; + gptr += fc; + bptr += fc; + aptr += fc; + + for(i = fc;i <= lc; i++) + { + *rptr = *ptr++; + if(is_grey) + { + if(oib) + *rptr = 255 - *rptr; + *gptr = *bptr = *rptr; + } + else + { + *gptr = *ptr++; + *bptr = *ptr++; + } + *aptr = ha ? *ptr++ : 255; /* opaque default */ + + rptr++; + gptr++; + bptr++; + aptr++; + } + + img->plane[0] += img->bpr; + img->cur_image_row++; + } + else + /* do the full averaging row creation */ + { + int tr, sc; + int s_row = img->row_starts[img->cur_screen_row]; + int e_row = img->row_ends[img->cur_screen_row]; + BOOL zero_count = YES; + + /* local copies of stuff we use a lot to avoid indirect */ + unsigned char **plane = img->plane; + unsigned int *bit_off = img->bit_off; + unsigned int *col_starts = img->col_starts; + unsigned int *col_ends = img->col_ends; + unsigned int *r_sum = img->r_sum; + unsigned int *g_sum = img->g_sum; + unsigned int *b_sum = img->b_sum; + unsigned int *a_sum = img->a_sum; + unsigned int *pix_count = img->pix_count; + unsigned char *rptr = img->r; + unsigned char *gptr = img->g; + unsigned char *bptr = img->b; + unsigned char *aptr = img->a; + int spp = img->spp; + int bpp = img->bpp; + int bps = img->bps; + int bpr = img->bpr; + int pro_mul = img->pro_mul; + int cspace = img->cspace; + BOOL ha = img->has_alpha; + BOOL oib = img->one_is_black; + int fc = img->first_vis_col, lc = img->last_vis_col; + + + /* loop for each required row */ + zero_count = YES; + for(tr = s_row; tr <= e_row; tr++) + { + /* move to the required image row */ + while(img->cur_image_row < tr) + { + int p; + for(p = 0; p < spp; p++) + plane[p] += bpr; + img->cur_image_row++; + } + + /* for each screen pixel */ + for(sc = fc; sc <= lc; sc++) + { + int s_col = col_starts[sc]; + int e_col = col_ends[sc]; + int tc; + + if(zero_count) + { + r_sum[sc] = 0; + g_sum[sc] = 0; + b_sum[sc] = 0; + a_sum[sc] = 0; + pix_count[sc] = 0; + } + + /* for each image pixel */ + for(tc = s_col; tc <= e_col; tc++) + { + unsigned char r, g, b, a; + _get_image_pixel(tc, &r, &g, &b, &a, + plane, bit_off, spp, bpp, bps, + pro_mul, cspace, ha, oib); + r_sum[sc] += r; + g_sum[sc] += g; + b_sum[sc] += b; + a_sum[sc] += a; + pix_count[sc]++; + } + } + + zero_count =NO; + } + + /* + * Build the line by averaging. As integer divide always + * rounds down we can get the effect of adding 0.5 before + * trucating by adding the value of the count right shifted + * one bit, thus giving us the nearest value and therefore a + * better approximation t the colour we hope. + */ + for(sc = fc; sc <= lc; sc++) + { + int count = pix_count[sc]; + int half = count >> 1; + rptr[sc] = (r_sum[sc] + half) / count; + gptr[sc] = (g_sum[sc] + half) / count; + bptr[sc] = (b_sum[sc] + half) / count; + aptr[sc] = (a_sum[sc] + half) / count; + } + } + + img->cur_screen_row++; +} + +/* + * Set the ranges covered by a pixel within the image. Given the source + * number of pixels and the destination number of pixels we calculate which + * pixels in the source are more than 50% overlapped by each pixel in the + * destination and record the start and end of the range. For mappings where + * the source is being magnified this will only be a single pixel, for others + * it may be one or more pixels, spaced evenly along the line. These are + * the pixels which will then be averaged to make the best guess colour for + * the destination pixel. As this is a slow process then a flag is passed in + * which will cause the nearest pixel alorithm that is used for magnification + * to be applied to minificationas well. The result looks rougher, but is much + * faster and proprtional to the size of the output rather than the input + * image. + */ + +static void +_set_ranges(int src_len, int dst_len, + int *start_ptr, int *end_ptr, BOOL fast_min) +{ + float dst_f = (float)dst_len; + int d; + if(fast_min || (src_len <= dst_len)) + /* magnifying */ + { + float src_f = (float)src_len; + for(d = 0; d < dst_len; d++) + { + int middle = (int)((((float)d + 0.5) * src_f) / dst_f); + *start_ptr++ = middle; + *end_ptr++ = middle; + if(middle >= src_len) + NSLog(@"Problem with magnification!"); + } + } + else + { + int start = 0; + for(d = 0; d < dst_len; d++) + { + int end_i = (int)(0.5 + (((d+1) * src_len) / dst_f)); + if((end_i > src_len) || (end_i < 1)) + NSLog(@"Problem with minification!"); + *start_ptr++ = start; + *end_ptr++ = end_i - 1; + start = end_i; + } + } +} + +/* + * Combine the image data with the currentonscreen data and push the + * result back to the screen. The screen handling code is almost identical + * to the original code. The function assumes that the displayable rectangle + * is always a subset of the complete screen rectangle which is the area + * in pixels that would be covered by the entire image. This is used to + * calculate the scaling required. + */ + +int +_bitmap_combine_alpha(RContext *context, + unsigned char * data_planes[5], + int width, int height, + int bits_per_sample, int samples_per_pixel, + int bits_per_pixel, int bytes_per_row, + int colour_space, BOOL one_is_black, + BOOL is_planar, BOOL has_alpha, BOOL fast_min, + RXImage *dest_im, RXImage *dest_alpha, + XRectangle srect, XRectangle drect, + NSCompositingOperation op, + XGDrawMechanism drawMechanism) +{ + struct _bitmap_decompose img; + XColor c0; + XColor c1; + int col_shift = drect.x - srect.x; + int row_shift = drect.y - srect.y; + + /* Sanity check on colourspace and number of colours */ + { + int num_of_colours = samples_per_pixel - (has_alpha ? 1 : 0); + switch(colour_space) + { + case hsb_colorspace: + NSLog(@"HSB colourspace not supported for images"); + return -1; + case rgb_colorspace: + if(num_of_colours != 3) + { + NSLog(@"Bad number of colour planes - d", num_of_colours); + NSLog(@"RGB colourspace requires three planes excluding alpha"); + return -1; + } + break; + case cmyk_colorspace: + if(num_of_colours != 4) + { + NSLog(@"Bad number of colour planes - %d", num_of_colours); + NSLog(@"CMYK colourspace requires four planes excluding alpha"); + return -1; + } + break; + case gray_colorspace: + if(num_of_colours != 1) + { + NSLog(@"Bad number of colour planes - %d", num_of_colours); + NSLog(@"Gray colourspace requires one plane excluding alpha"); + return -1; + } + break; + default: + NSLog(@"Unknown colourspace found"); + return -1; + } + } + + /* bitmap decomposition structure */ + img.bps = bits_per_sample; + img.bpp = bits_per_pixel; + img.spp = samples_per_pixel; + img.bpr = bytes_per_row; + img.image_w = width; + img.image_h = height; + img.screen_w = srect.width; + img.screen_h = srect.height; + img.has_alpha = has_alpha; + img.one_is_black = one_is_black; + img.cspace = colour_space; + img.cur_image_row = 0; + img.cur_screen_row = 0; + + /* + * Promotion value, this is what the samples need to + * be mutiplied by to get an 8 bit value. This is done + * rather than shifting to fill in the lower bits properly. + * The values for 6, 5 and 3 bits shouldbe floats by rights, + * but the difference is negligble and for speed we want to use + * integers. + */ + switch(bits_per_sample) + { + case 8: + img.pro_mul = 1; + break; + case 7: + img.pro_mul = 2; + break; + case 6: + img.pro_mul = 4; /* should be 4.05 */ + break; + case 5: + img.pro_mul = 8; /* should be 8.226 */ + break; + case 4: + img.pro_mul = 17; + break; + case 3: + img.pro_mul = 36; /* should be 36.43 */ + break; + case 2: + img.pro_mul = 85; + break; + case 1: + img.pro_mul = 255; + break; + default: + NSLog(@"Bizzare number of bits per sample %d", bits_per_sample); + return -1; + } + + /* + * Handle planar or meshed data. We hold an array of + * base addresses and bit offsets for all formats. + * Thus for meshed data the bases are the same with + * increasing bit offsets, but for planar data the bases + * are those of the planes, with the bit offset always being + * zero. + */ + { + int i; + + /* zero them */ + for(i=0;i<5;i++) + { + img.plane[i] = NULL; + img.bit_off[i] = 0; + } + + /* set as appropriate */ + if(is_planar) + for(i=0;i>= (8 - _rwidth); + g >>= (8 - _gwidth); + b >>= (8 - _bwidth); + + if (has_alpha) + { + if (dest_alpha) + { + unsigned short dalpha; + unsigned long dpixel; + /* Alpha gets mixed the same as all the + other color components */ + dpixel = XGetPixel(dest_alpha->image, col, row); + dalpha = (dpixel >> _ashift) & _amask; + dalpha = alpha + dalpha * (_amask - alpha)/_amask; + XPutPixel(dest_alpha->image, col, row, + dalpha << _ashift); + } + if (alpha == 0) + continue; // background unchanged. + + if (alpha != _amask) + { + unsigned short ialpha = _amask - alpha; + /* + * Get the background pixel and convert to RGB. + */ + pixel = XGetPixel(dest_im->image, col, row); + if (pixel != oldPixel) + { + oldPixel = pixel; + PixelToRGB(pixel,oldBr,oldBg,oldBb); + oldAlpha = 0; + } + if (alpha != oldAlpha) + { + oldAlpha = alpha; + oldAr = ialpha * oldBr; + oldAg = ialpha * oldBg; + oldAb = ialpha * oldBb; + } + + // mix in alpha to produce RGB out + r = (oldAr + (r * alpha)) / _amask; + g = (oldAg + (g * alpha)) / _amask; + b = (oldAb + (b * alpha)) / _amask; + } + } + else + { + /* Not using alpha, but we still have to set it + in the pixmap */ + if (dest_alpha) + XPutPixel(dest_alpha->image, col, row, + _amask << _ashift); + } + + RGBToPixel(r,g,b,pixel); + XPutPixel(dest_im->image, col, row, pixel); + } + } + } + else + { + XColor c2, a2; + unsigned row, oldAlpha = 65537; + + /* + * This block of code should be totally portable as it uses the + * 'official' X mechanism for converting from pixel values to + * RGB color values - on the downside, it's very slow. + */ + pixel = (unsigned long)-1; // Never valid? + c2.pixel = pixel; + a2.pixel = pixel; + + for (row = 0; row < drect.height; row++) + { + unsigned col; + unsigned char *rptr = img.r + col_shift; + unsigned char *gptr = img.g + col_shift; + unsigned char *bptr = img.b + col_shift; + unsigned char *aptr = img.a + col_shift; + + _create_image_row(&img); + + for (col = 0; col < drect.width; col++) + { + unsigned short r = *rptr++; + unsigned short g = *gptr++; + unsigned short b = *bptr++; + unsigned short alpha = *aptr++;; + + if (has_alpha) + { + if (alpha != oldAlpha) + { + oldAlpha = alpha; + a2.red = alpha << 8; + a2.green = alpha << 8; + a2.blue = alpha << 8; + XAllocColor(context->dpy, context->cmap, &a2); + } + if (dest_alpha) + { + XColor da; + /* Alpha gets mixed the same as all the + other color components */ + da.pixel = XGetPixel(dest_alpha->image, col, row); + XQueryColor(context->dpy, context->cmap, &da); + da.red = a2.red + da.red * (65536 - a2.red)/65536; + da.green = da.blue = da.red; + XAllocColor(context->dpy, context->cmap, &da); + XPutPixel(dest_alpha->image, col, row, da.pixel); + } + if (alpha == 0) + continue; // background unchanged. + + if (alpha == 255) + { + c1.red = r << 8; + c1.green = g << 8; + c1.blue = b << 8; + } + else + { + unsigned short ialpha = 255 - alpha; + + /* + * RGB color components in X are 16-bit values - + * but our bitmap contains 8-bit values so we must + * adjust our values up to 16-bit, which we can do + * by increasing their alpha component by 256. + */ + alpha <<= 8; + + /* + * Get the background pixel and convert to RGB if + * we haven't already done the conversion earlier. + */ + c0.pixel = XGetPixel(dest_im->image, col, row); + if (c0.pixel != pixel) + { + pixel = c0.pixel; + XQueryColor(context->dpy, context->cmap, &c0); + } + + // mix in alpha to produce RGB out + c1.red = ((c0.red*ialpha) + (r*alpha))/255; + c1.green = ((c0.green*ialpha) + (g*alpha))/255; + c1.blue = ((c0.blue*ialpha) + (b*alpha))/255; + } + } + else + { + /* + * Simply convert our 8-bit RGB values to X-style + * 16-bit values, then determine the X colormap + * entry and set the pixel. + */ + c1.red = r << 8; + c1.green = g << 8; + c1.blue = b << 8; + /* Not using alpha, but we still have to set it + in the pixmap */ + if (a2.pixel == pixel) + { + a2.red = 255 << 8; + a2.green = 255 << 8; + a2.blue = 255 << 8; + XAllocColor(context->dpy, context->cmap, &a2); + } + if (dest_alpha) + XPutPixel(dest_alpha->image, col, row, a2.pixel); + } + + /* + * Convert the X RGB value to a colormap entry if we + * don't already have one. Then set the pixel. + * NB. XAllocColor() will not necessarily return a + * color with exactly the rgb components we gave it, so + * we must record those components beforehand. + */ + if (c2.pixel == (unsigned long)-1 + || c2.red != c1.red + || c2.green != c1.green + || c2.blue != c1.blue) + { + c2.red = c1.red; + c2.green = c1.green; + c2.blue = c1.blue; + XAllocColor(context->dpy, context->cmap, &c1); + c2.pixel = c1.pixel; + } + XPutPixel(dest_im->image, col, row, c1.pixel); + } + } + } + } + + /* free used memory */ + free(img.r); + free(img.g); + free(img.b); + free(img.a); + if(!img.is_direct_packed) + { + free(img.row_starts); + free(img.row_ends); + free(img.col_starts); + free(img.col_ends); + free(img.r_sum); + free(img.g_sum); + free(img.b_sum); + free(img.a_sum); + free(img.pix_count); + } + return 0; +} diff --git a/Source/xlib/XGBitmapImageRep.m b/Source/xlib/XGBitmapImageRep.m new file mode 100644 index 0000000..ac5d2bb --- /dev/null +++ b/Source/xlib/XGBitmapImageRep.m @@ -0,0 +1,169 @@ +/* + XGBitmapImageRep.m + + NSBitmapImageRep for GNUstep GUI X/GPS Backend + + Copyright (C) 1996-1999 Free Software Foundation, Inc. + + Author: Adam Fedor + Author: Scott Christley + Date: Feb 1996 + Author: Felipe A. Rodriguez + Date: May 1998 + Author: Richard Frith-Macdonald + Date: Mar 1999 + Rewritten: Adam Fedor + Date: May 2000 + + This file is part of the GNUstep GUI X/GPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include + +#include "xlib/XGContext.h" +#include "xlib/xrtools.h" +#include "x11/XGServerWindow.h" +#include +#include +#include +#include +#include +#include + +@interface NSBitmapImageRep (BackEnd) +- (Pixmap) xPixmapMask; +@end + + +@implementation NSBitmapImageRep (Backend) + +#ifdef WITH_WRASTER ++ (NSArray *) _wrasterFileTypes +{ + int i; + NSMutableArray *warray; + char **types = RSupportedFileFormats(); + + i = 0; + warray = [NSMutableArray arrayWithCapacity: 4]; + while (types[i] != NULL) + { + NSString *type = [NSString stringWithCString: types[i]]; + type = [type lowercaseString]; + if (strcmp(types[i], "TIFF") != 0) + { + [warray addObject: type]; + if (strcmp(types[i], "JPEG") == 0) + [warray addObject: @"jpg"]; + else if (strcmp(types[i], "PPM") == 0) + [warray addObject: @"pgm"]; + } + i++; + } + return warray; +} + +- _initFromWrasterFile: (NSString *)filename number: (int)imageNumber +{ + RImage *image; + RContext *context; + + if (imageNumber > 0) + { + /* RLoadImage doesn't handle this very well */ + RELEASE(self); + return nil; + } + + NSDebugLLog(@"NSImage", @"Loading %@ using wraster routines", filename); + context = [(XGContext *)GSCurrentContext() xrContext]; + image = RLoadImage(context, (char *)[filename cString], imageNumber); + if (!image) + { + RELEASE(self); + return nil; + } + [self initWithBitmapDataPlanes: &(image->data) + pixelsWide: image->width + pixelsHigh: image->height + bitsPerSample: 8 + samplesPerPixel: (image->format == RRGBAFormat) ? 4 : 3 + hasAlpha: (image->format == RRGBAFormat) ? YES : NO + isPlanar: NO + colorSpaceName: NSDeviceRGBColorSpace + bytesPerRow: 0 + bitsPerPixel: 0]; + + /* Make NSBitmapImageRep own the data */ + _imageData = [NSMutableData dataWithBytesNoCopy: image->data + length: (_bytesPerRow*image->height)]; + RETAIN(_imageData); + free(image); + + return self; +} +#endif /* WITH_WRASTER */ + +- (Pixmap) xPixmapMask +{ + unsigned char *bData; + XGContext *ctxt = (XGContext*)GSCurrentContext(); + Display *xDisplay = [ctxt xDisplay]; + Drawable xDrawable; + GC gc; + int x, y; + + // Only produce pixmaps for meshed images with alpha + if ((_numColors != 4) || _isPlanar) + return 0; + + bData = [self bitmapData]; + + [ctxt DPScurrentgcdrawable: (void**)&gc : (void**)&xDrawable : &x : &y]; + + // FIXME: This optimistic computing works only, if there are no + // additional bytes at the end of a line. + return xgps_cursor_mask (xDisplay, xDrawable, bData, _pixelsWide, _pixelsHigh, _numColors); +} + +@end + + +@implementation NSImage (Backend) + +- (Pixmap) xPixmapMask +{ + NSArray *reps = [self representations]; + NSEnumerator *enumerator = [reps objectEnumerator]; + NSImageRep *rep; + + while ((rep = [enumerator nextObject]) != nil) + { + if ([rep isKindOfClass: [NSBitmapImageRep class]]) + { + return [(NSBitmapImageRep*)rep xPixmapMask]; + } + } + + return 0; +} + +@end diff --git a/Source/xlib/XGCommonFont.m b/Source/xlib/XGCommonFont.m new file mode 100644 index 0000000..bcf2314 --- /dev/null +++ b/Source/xlib/XGCommonFont.m @@ -0,0 +1,282 @@ +/* + XGFontInfo + + NSFont helper for GNUstep GUI X/GPS Backend + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Scott Christley + Author: Ovidiu Predescu + Date: February 1997 + Author: Felipe A. Rodriguez + Date: May, October 1998 + Author: Michael Hanni + Date: August 1998 + Author: Fred Kiefer + Date: September 2000 + + This file is part of the GNUstep GUI X/GPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include "xlib/XGContext.h" +#include "xlib/XGPrivate.h" +#include +// For the encoding functions +#include + +static Atom XA_SLANT = (Atom)0; +static Atom XA_SETWIDTH_NAME = (Atom)0; +static Atom XA_CHARSET_REGISTRY = (Atom)0; +static Atom XA_CHARSET_ENCODING = (Atom)0; +static Atom XA_SPACING = (Atom)0; +static Atom XA_PIXEL_SIZE = (Atom)0; +static Atom XA_WEIGHT_NAME = (Atom)0; + +/* + static Atom XA_RESOLUTION_X = (Atom)0; + static Atom XA_RESOLUTION_Y = (Atom)0; + static Atom XA_ADD_STYLE_NAME = (Atom)0; + static Atom XA_AVERAGE_WIDTH = (Atom)0; + static Atom XA_FACE_NAME = (Atom)0; +*/ + +/* + * Initialise the X atoms we are going to use + */ +static BOOL XGInitAtoms(Display *dpy) +{ + // X atoms used to query a font + + if (!dpy) + { + NSDebugLog(@"No Display opened in XGInitAtoms"); + return NO; + } + + XA_PIXEL_SIZE = XInternAtom(dpy, "PIXEL_SIZE", False); + XA_SPACING = XInternAtom(dpy, "SPACING", False); + XA_WEIGHT_NAME = XInternAtom(dpy, "WEIGHT_NAME", False); + XA_SLANT = XInternAtom(dpy, "SLANT", False); + XA_SETWIDTH_NAME = XInternAtom(dpy, "SETWIDTH_NAME", False); + XA_CHARSET_REGISTRY = XInternAtom(dpy, "CHARSET_REGISTRY", False); + XA_CHARSET_ENCODING = XInternAtom(dpy, "CHARSET_ENCODING", False); + +/* + XA_ADD_STYLE_NAME = XInternAtom(dpy, "ADD_STYLE_NAME", False); + XA_RESOLUTION_X = XInternAtom(dpy, "RESOLUTION_X", False); + XA_RESOLUTION_Y = XInternAtom(dpy, "RESOLUTION_Y", False); + XA_AVERAGE_WIDTH = XInternAtom(dpy, "AVERAGE_WIDTH", False); + XA_FACE_NAME = XInternAtom(dpy, "FACE_NAME", False); +*/ + + return YES; +} + +/* + * Read an X Font property of type unsigned long + */ +unsigned long XGFontPropULong(Display *dpy, XFontStruct *font_struct, + Atom atom) +{ + unsigned long lvalue; + + if (XGetFontProperty(font_struct, atom, &lvalue)) + return lvalue; + else + return 0; +} + +/* + * Read an X Font property of type string + */ +NSString *XGFontPropString(Display *dpy, XFontStruct *font_struct, Atom atom) +{ + unsigned long lvalue; + char *value; + NSString *ret = nil; + + if (XGetFontProperty(font_struct, atom, &lvalue) && dpy) + { + value = XGetAtomName(dpy, lvalue); + if (value != NULL) + { + // We convert all props to lowercase so comparing is easier + ret = [[NSString stringWithCString: value] lowercaseString]; + XFree(value); + } + } + + return ret; +} + +NSString *XGFontName(Display *dpy, XFontStruct *font_struct) +{ + return XGFontPropString(dpy, font_struct, XA_FONT); +} + +float XGFontPointSize(Display *dpy, XFontStruct *font_struct) +{ + float size = 12.0; + long pointSize; + + if (!XA_PIXEL_SIZE) + XGInitAtoms(dpy); + + /* + * We use pixel size here not point size, which is about 10 times its size. + * Perhaps we will change that later on! + */ + pointSize = XGFontPropULong(dpy, font_struct, XA_PIXEL_SIZE); + if (pointSize != 0) + { + size = (float) pointSize; + } + + return size; +} + +BOOL XGFontIsFixedPitch(Display *dpy, XFontStruct *font_struct) +{ + /* Is this font fixed pitch? default, NO */ + BOOL fixedFont = NO; + NSString *spacing; + + // If there is no information per character, all must be equal + if (!font_struct->per_char) + { + return YES; + } + + if (!XA_SPACING) + XGInitAtoms(dpy); + + /* + * We could also check the value of MONOSPACED, but I have never seen it set. + */ + spacing = XGFontPropString(dpy, font_struct, XA_SPACING); + if (spacing != nil) + { + if ([spacing isEqualToString: @"m"]) + fixedFont = YES; + } + + /* + * We could calculate the pitch from the XLFD but that does not seem to be + * saved. If we can't get the property, say no and cope. + */ + return fixedFont; +} + +NSString *XGFontFamily(Display *dpy, XFontStruct *font_struct) +{ + NSString *family; + + family = XGFontPropString(dpy, font_struct, XA_FAMILY_NAME); + if (family == nil) + return @"Unknown"; // FIXME: We should return the font name instead + + return [family capitalizedString]; +} + +// Get the weight of a X font +int XGWeightOfFont(Display *dpy, XFontStruct *info) +{ + int w = 5; + NSString *string; + + if (!XA_WEIGHT_NAME) + XGInitAtoms(dpy); + + string = XGFontPropString(dpy, info, XA_WEIGHT_NAME); + + if (string != nil) + { + w = [GSFontInfo weightForString: string]; + } + + return w; +} + +// Get the traits of a X font +NSFontTraitMask XGTraitsOfFont(Display *dpy, XFontStruct *info) +{ + NSFontTraitMask mask = 0; + NSString *string; + int w = XGWeightOfFont(dpy, info); + + if (w >= 9) + mask |= NSBoldFontMask; + else + mask |= NSUnboldFontMask; + + if (XGFontIsFixedPitch(dpy, info)) + mask |= NSFixedPitchFontMask; + + string = XGFontPropString(dpy, info, XA_SLANT); + if (string != nil) + { + char c = [string cString][0]; + + if (c == 'o' || c == 'i') + mask |= NSItalicFontMask; + else + mask |= NSUnitalicFontMask; + } + + string = XGFontPropString(dpy, info, XA_CHARSET_REGISTRY); + if (string != nil) + { + if (![string isEqualToString: @"iso8859"] && + ![string isEqualToString: @"iso10646"] ) + mask |= NSNonStandardCharacterSetFontMask; + } + string = XGFontPropString(dpy, info, XA_CHARSET_ENCODING); + if (string != nil) + { + if (![string isEqualToString: @"1"]) + mask |= NSNonStandardCharacterSetFontMask; + } + + string = XGFontPropString(dpy, info, XA_SETWIDTH_NAME); + if (string != nil) + { + if ([string isEqualToString: @"narrow"]) + mask |= NSNarrowFontMask; + else if ([string isEqualToString: @"semicondensed"]) + mask |= NSCondensedFontMask; + } + + string = XGFontPropString(dpy, info, XA_SPACING); + if (string != nil) + { + if ([string isEqualToString: @"c"]) + mask |= NSCompressedFontMask; + } + + //FIXME: How can I find out about the other traits? + /* + unsigned long weight = XGFontPropULong(dpy, info, XA_WEIGHT); + */ + + return mask; +} diff --git a/Source/xlib/XGContext.m b/Source/xlib/XGContext.m new file mode 100644 index 0000000..863db7f --- /dev/null +++ b/Source/xlib/XGContext.m @@ -0,0 +1,185 @@ +/* -*- mode:ObjC -*- + XGContext - Drawing context using the Xlib Library. + + Copyright (C) 1998,1999,2002 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1998 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "x11/XGServer.h" +#include "xlib/XGContext.h" +#include "xlib/XGPrivate.h" +#include "xlib/XGGState.h" +#include "xlib/xrtools.h" + +#if HAVE_XFT +#include "xlib/XftFontInfo.h" +#endif + +#include +#include +#include + +/** + + XGContext +

+ The documentation below mostly describes methods that are specific to + this backend and wouldn't necessarily be used in other backends. The methods + that this class does implement that would need to be in every backend are + the methods of its NSGraphicContext superclass. See the documentation + for NSGraphicContext for more information. +

+
+*/ +@implementation XGContext + +/* Initialize AppKit backend */ ++ (void)initializeBackend +{ + Class fontClass = Nil; + + NSDebugLog(@"Initializing GNUstep xlib backend.\n"); + + [NSGraphicsContext setDefaultContextClass: [XGContext class]]; + [GSFontEnumerator setDefaultClass: [XGFontEnumerator class]]; + +#if HAVE_XFT + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"GSFontAntiAlias"]) + { + fontClass = [XftFontInfo class]; + } +#endif + if (fontClass == Nil) + { + fontClass = [XGFontInfo class]; + } + [GSFontInfo setDefaultClass: fontClass]; +} + +- (id) initWithContextInfo: (NSDictionary *)info +{ + [super initWithContextInfo: info]; + + /* Create a default gstate */ + gstate = [[XGGState allocWithZone: [self zone]] initWithDrawContext: self]; + + drawMechanism = [(XGServer *)server drawMechanism]; + return self; +} + +/** + Returns the XGDrawMechanism, which roughly describes the depth of + the screen and how pixels should be drawn to the screen for maximum + speed. +*/ +- (XGDrawMechanism) drawMechanism +{ + return drawMechanism; +} + +/** + Returns a pointer to a structure which describes aspects of the + X windows display +*/ +- (void *) xrContext +{ + return [(XGServer *)server xrContext]; +} + +/** + Returns a pointer to the X windows display variable +*/ +- (Display *) xDisplay +{ + return [(XGServer *)server xDisplay]; +} + +- (void) flushGraphics +{ + XFlush([(XGServer *)server xDisplay]); +} + +// +// Read the Color at a Screen Position +// +- (NSColor *) NSReadPixel: (NSPoint) location +{ + [self notImplemented: _cmd]; + return nil; +} + +- (void) NSBeep +{ + XBell([(XGServer *)server xDisplay], 50); +} + +/* Private backend methods */ +- (void) contextDevice: (int)num +{ + [(XGGState *)gstate setWindow: num]; +} + + +@end + +@implementation XGContext (Ops) + +/* ----------------------------------------------------------------------- */ +/* Window system ops */ +/* ----------------------------------------------------------------------- */ +- (void) DPScurrentgcdrawable: (void **)gc : (void **)draw + : (int *)x : (int *)y +{ + if (gc) + *gc = (void *)[(XGGState *)gstate graphicContext]; + if (draw) + *draw = (void *)[(XGGState *)gstate drawable]; + if (x && y) + { + NSPoint offset = [gstate offset]; + *x = offset.x; + *y = offset.y; + } +} + +- (void) DPSsetgcdrawable: (void *)gc : (void *)draw : (int)x : (int)y +{ + [(XGGState *)gstate setGraphicContext: (GC)gc]; + [(XGGState *)gstate setDrawable: (Drawable)draw]; + [gstate setOffset: NSMakePoint(x, y)]; +} + +@end diff --git a/Source/xlib/XGFont.m b/Source/xlib/XGFont.m new file mode 100644 index 0000000..31378b0 --- /dev/null +++ b/Source/xlib/XGFont.m @@ -0,0 +1,380 @@ +/* + XGFontInfo + + NSFont helper for GNUstep GUI X/GPS Backend + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Scott Christley + Author: Ovidiu Predescu + Date: February 1997 + Author: Felipe A. Rodriguez + Date: May, October 1998 + Author: Michael Hanni + Date: August 1998 + Author: Fred Kiefer + Date: September 2000 + + This file is part of the GNUstep GUI X/GPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include "xlib/XGContext.h" +#include "xlib/XGPrivate.h" +#include "xlib/XGGState.h" +#include "x11/XGServer.h" +#include +#include +#include +// For the encoding functions +#include + +static Atom XA_SLANT = (Atom)0; +static Atom XA_SETWIDTH_NAME = (Atom)0; +static Atom XA_CHARSET_REGISTRY = (Atom)0; +static Atom XA_CHARSET_ENCODING = (Atom)0; +static Atom XA_SPACING = (Atom)0; +static Atom XA_PIXEL_SIZE = (Atom)0; +static Atom XA_WEIGHT_NAME = (Atom)0; + +/* + * Initialise the X atoms we are going to use + */ +static BOOL XGInitAtoms(Display *dpy) +{ + // X atoms used to query a font + + if (!dpy) + { + NSDebugLog(@"No Display opened in XGInitAtoms"); + return NO; + } + + XA_PIXEL_SIZE = XInternAtom(dpy, "PIXEL_SIZE", False); + XA_SPACING = XInternAtom(dpy, "SPACING", False); + XA_WEIGHT_NAME = XInternAtom(dpy, "WEIGHT_NAME", False); + XA_SLANT = XInternAtom(dpy, "SLANT", False); + XA_SETWIDTH_NAME = XInternAtom(dpy, "SETWIDTH_NAME", False); + XA_CHARSET_REGISTRY = XInternAtom(dpy, "CHARSET_REGISTRY", False); + XA_CHARSET_ENCODING = XInternAtom(dpy, "CHARSET_ENCODING", False); + +/* + XA_ADD_STYLE_NAME = XInternAtom(dpy, "ADD_STYLE_NAME", False); + XA_RESOLUTION_X = XInternAtom(dpy, "RESOLUTION_X", False); + XA_RESOLUTION_Y = XInternAtom(dpy, "RESOLUTION_Y", False); + XA_AVERAGE_WIDTH = XInternAtom(dpy, "AVERAGE_WIDTH", False); + XA_FACE_NAME = XInternAtom(dpy, "FACE_NAME", False); +*/ + + return YES; +} + + +@interface XGFontInfo (Private) + +- (BOOL) setupAttributes; +- (XCharStruct *)xCharStructForGlyph: (NSGlyph) glyph; + +@end + +@implementation XGFontInfo + +- (XFontStruct*) xFontStruct +{ + return font_info; +} + +- initWithFontName: (NSString*)name matrix: (const float *)fmatrix +{ + [super init]; + ASSIGN(fontName, name); + memcpy(matrix, fmatrix, sizeof(matrix)); + + if (![self setupAttributes]) + { + RELEASE(self); + return nil; + } + + return self; +} + +- (void) dealloc +{ + if (font_info != NULL) + XUnloadFont([XGServer currentXDisplay], font_info->fid); + [super dealloc]; +} + +- (NSMultibyteGlyphPacking)glyphPacking +{ + if (font_info->min_byte1 == 0 && + font_info->max_byte1 == 0) + return NSOneByteGlyphPacking; + else + return NSTwoByteGlyphPacking; +} + +- (NSSize) advancementForGlyph: (NSGlyph)glyph +{ + XCharStruct *pc = [self xCharStructForGlyph: glyph]; + + // if per_char is NULL assume max bounds + if (!pc) + pc = &(font_info->max_bounds); + + return NSMakeSize((float)pc->width, 0); +} + +- (NSRect) boundingRectForGlyph: (NSGlyph)glyph +{ + XCharStruct *pc = [self xCharStructForGlyph: glyph]; + + // if per_char is NULL assume max bounds + if (!pc) + return fontBBox; + + return NSMakeRect((float)pc->lbearing, (float)-pc->descent, + (float)(pc->rbearing - pc->lbearing), + (float)(pc->ascent + pc->descent)); +} + +- (BOOL) glyphIsEncoded: (NSGlyph)glyph +{ + XCharStruct *pc = [self xCharStructForGlyph: glyph]; + + return (pc != NULL); +} + +- (NSGlyph) glyphWithName: (NSString*)glyphName +{ + // FIXME: There is a mismatch between PS names and X names, that we should + // try to correct here + KeySym k = XStringToKeysym([glyphName cString]); + + if (k == NoSymbol) + return 0; + else + return (NSGlyph)k; +} + +- (void) drawString: (NSString*)string + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp +{ + XGCValues gcv; + NSData *d = [string dataUsingEncoding: mostCompatibleStringEncoding + allowLossyConversion: YES]; + int length = [d length]; + const char *cstr = (const char*)[d bytes]; + + // Select this font, although it might already be current. + gcv.font = font_info->fid; + XChangeGC(xdpy, xgcntxt, GCFont, &gcv); + + // FIXME: Use XDrawString16 for NSTwoByteGlyphPacking + XDrawString(xdpy, draw, xgcntxt, xp.x, xp.y, cstr, length); +} + +- (void) draw: (const char*) s lenght: (int) len + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp +{ + // This font must already be active! + XDrawString(xdpy, draw, xgcntxt, xp.x, xp.y, s, len); +} + +- (float) widthOfString: (NSString*)string +{ + NSData *d = [string dataUsingEncoding: mostCompatibleStringEncoding + allowLossyConversion: YES]; + int length = [d length]; + const char *cstr = (const char*)[d bytes]; + + // FIXME: Use XTextWidth16 for NSTwoByteGlyphPacking + return XTextWidth(font_info, cstr, length); +} + +- (float) widthOf: (const char*) s lenght: (int) len +{ + return XTextWidth(font_info, s, len); +} + +- (void) setActiveFor: (Display*) xdpy gc: (GC) xgcntxt +{ + XGCValues gcv; + + // Select this font, although it might already be current. + gcv.font = font_info->fid; + XChangeGC(xdpy, xgcntxt, GCFont, &gcv); +} + +@end + +@implementation XGFontInfo (Private) + +- (BOOL) setupAttributes +{ + Display *xdpy = [XGServer currentXDisplay]; + NSString *weightString; + NSString *reg; + long height; + NSString *xfontname; + + if (!xdpy) + return NO; + + if (!XA_PIXEL_SIZE) + XGInitAtoms(xdpy); + + // Retrieve the XLFD matching the given fontName. DPS->X. + xfontname = XGXFontName(fontName, matrix[0]); + + // Load X font and get font info structure. + if ((xfontname == nil) || + (font_info = XLoadQueryFont(xdpy, [xfontname cString])) == NULL) + { + NSLog(@"Selected font: %@ at %f (%@) is not available.\n" + @"Using system fixed font instead", fontName, matrix[0], xfontname); + + // Try default font + if ((font_info = XLoadQueryFont(xdpy, "9x15")) == NULL) + { + NSLog(@"Unable to open fixed font"); + return NO; + } + } + else + NSDebugLog(@"Loaded font: %@", xfontname); + + // Fill the afmDitionary and ivars + [fontDictionary setObject: fontName forKey: NSAFMFontName]; + ASSIGN(familyName, XGFontFamily(xdpy, font_info)); + [fontDictionary setObject: familyName forKey: NSAFMFamilyName]; + isFixedPitch = XGFontIsFixedPitch(xdpy, font_info); + isBaseFont = NO; + ascender = font_info->max_bounds.ascent; + [fontDictionary setObject: [NSNumber numberWithFloat: ascender] + forKey: NSAFMAscender]; + descender = -(font_info->max_bounds.descent); + [fontDictionary setObject: [NSNumber numberWithFloat: descender] + forKey: NSAFMDescender]; + fontBBox = NSMakeRect( + (float)(0 + font_info->min_bounds.lbearing), + (float)(0 - font_info->max_bounds.ascent), + (float)(font_info->max_bounds.rbearing - font_info->min_bounds.lbearing), + (float)(font_info->max_bounds.ascent + font_info->max_bounds.descent)); + maximumAdvancement = NSMakeSize(font_info->max_bounds.width, + (font_info->max_bounds.ascent +font_info->max_bounds.descent)); + minimumAdvancement = NSMakeSize(0,0); + weight = XGWeightOfFont(xdpy, font_info); + traits = XGTraitsOfFont(xdpy, font_info); + + weightString = [GSFontInfo stringForWeight: weight]; + + if (weightString != nil) + { + [fontDictionary setObject: weightString forKey: NSAFMWeight]; + } + + reg = XGFontPropString(xdpy, font_info, XA_CHARSET_REGISTRY); + if (reg != nil) + { + NSString *enc = XGFontPropString(xdpy, font_info, XA_CHARSET_ENCODING); + + if (enc != nil) + { + mostCompatibleStringEncoding = [GSFontInfo encodingForRegistry: reg + encoding: enc]; + encodingScheme = [NSString stringWithFormat: @"%@-%@", + reg, enc]; + NSDebugLog(@"Found encoding %d for %@", + mostCompatibleStringEncoding, encodingScheme); + RETAIN(encodingScheme); + [fontDictionary setObject: encodingScheme + forKey: NSAFMEncodingScheme]; + } + } + + height = XGFontPropULong(xdpy, font_info, XA_X_HEIGHT); + if (height != 0) + { + xHeight = (float)height; + [fontDictionary setObject: [NSNumber numberWithFloat: xHeight] + forKey: NSAFMXHeight]; + } + + height = XGFontPropULong(xdpy, font_info, XA_CAP_HEIGHT); + if (height != 0) + { + capHeight = (float)height; + [fontDictionary setObject: [NSNumber numberWithFloat: capHeight] + forKey: NSAFMCapHeight]; + } + + // FIXME: italicAngle, underlinePosition, underlineThickness are not set. + // Should use XA_ITALIC_ANGLE, XA_UNDERLINE_POSITION, XA_UNDERLINE_THICKNESS + + return YES; +} + +- (XCharStruct *)xCharStructForGlyph: (NSGlyph) glyph +{ + XCharStruct *pc = NULL; + + if (font_info->per_char) + { + unsigned index; + unsigned min1 = font_info->min_byte1; + unsigned max1 = font_info->max_byte1; + unsigned min2 = font_info->min_char_or_byte2; + unsigned max2 = font_info->max_char_or_byte2; + + // glyph is an unicode char value + // if the font has non-standard encoding we need to remap it. + if ((mostCompatibleStringEncoding != NSASCIIStringEncoding) && + (mostCompatibleStringEncoding != NSISOLatin1StringEncoding) && + (mostCompatibleStringEncoding != NSUnicodeStringEncoding)) + { + // FIXME: This only works for 8-Bit characters + index = encode_unitochar(glyph, mostCompatibleStringEncoding); + } + else + index = glyph; + + if (min1 == 0 && max1 == 0) + { + if (glyph >= min2 && glyph <= max2) + pc = &(font_info->per_char[index - min2]); + } + else + { + unsigned b1 = index >> 8; + unsigned b2 = index & 255; + + if (b1 >= min1 && b1 <= max1 && b2 >= min2 && b2 <= max2) + pc = &(font_info->per_char[(b1 - min1) * (max2 - min2 + 1) + + b2 - min2]); + } + } + + return pc; +} + +@end diff --git a/Source/xlib/XGFontManager.m b/Source/xlib/XGFontManager.m new file mode 100644 index 0000000..f4e3dc9 --- /dev/null +++ b/Source/xlib/XGFontManager.m @@ -0,0 +1,197 @@ +/* + XGFontManager.m + + NSFontManager helper for GNUstep GUI X/GPS Backend + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: February 1997 + A completely rewritten version of the original source of Scott Christley. + Modified: Fred Kiefer + Date: Febuary 2000 + Added some X calls and changed the overall structure + + This file is part of the GNUstep GUI X/GPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "xlib/XGContext.h" +#include "xlib/XGPrivate.h" +#include "x11/XGServer.h" + +#define stringify_it(X) #X + +static NSMutableDictionary* creationDictionary; + +// Fills in the size into an creation string to make it an X font name +NSString *XGXFontName(NSString *fontName, float size) +{ + NSString *creationName = [creationDictionary objectForKey: fontName]; + + if (creationName != nil) + return [NSString stringWithFormat: creationName, (int)size]; + else + return nil; +} + +@implementation XGFontEnumerator + +static NSDictionary *cache; + +static NSString* +cache_name() +{ + static NSString *cacheName = nil; + + if (cacheName == nil) + { + NSFileManager *mgr; + BOOL flag; + Display *dpy = [XGServer currentXDisplay]; + char *display_name = DisplayString(dpy); + NSString *file_name; + NSArray *paths; + NSString *path = nil; + + file_name = [NSString stringWithCString: XDisplayName(display_name)]; + + paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, + NSUserDomainMask, YES); + if ((paths != nil) && ([paths count] > 0)) + { + path = [paths objectAtIndex: 0]; + } + /* + * If standard search paths are not set up, try a default location. + */ + if (path == nil) + { + path = [[NSHomeDirectory() stringByAppendingPathComponent: + @"GNUstep"] stringByAppendingPathComponent: @"Library"]; + } + + mgr = [NSFileManager defaultManager]; + if ([mgr fileExistsAtPath: path isDirectory: &flag] == NO || flag == NO) + { + NSLog(@"Library directory '%@' not available!", path); + return NO; + } + path = [path stringByAppendingPathComponent: @"Fonts"]; + if ([mgr fileExistsAtPath: path] == NO) + { + [mgr createDirectoryAtPath: path attributes: nil]; + } + if ([mgr fileExistsAtPath: path isDirectory: &flag] == NO || flag == NO) + { + NSLog(@"Fonts directory '%@' not available!", path); + return NO; + } + path = [path stringByAppendingPathComponent: @"Cache"]; + if ([mgr fileExistsAtPath: path] == NO) + { + [mgr createDirectoryAtPath: path attributes: nil]; + } + if ([mgr fileExistsAtPath: path isDirectory: &flag] == NO || flag == NO) + { + NSLog(@"Fonts directory '%@' not available!", path); + return NO; + } + cacheName = [path stringByAppendingPathComponent: file_name]; + RETAIN(cacheName); + } + + return cacheName; +} + +static BOOL +load_cache(NSString *cacheName, BOOL async) +{ + NSNumber *v; + id o; + + o = [NSUnarchiver unarchiveObjectWithFile: cacheName]; + if ((o == nil) + || ((v = [o objectForKey: @"Version"]) == nil) + || ([v intValue] != 2)) + { + NSString *file_name = [cacheName lastPathComponent]; + NSDictionary *env = [[NSProcessInfo processInfo] environment]; + NSString *path; + NSTask *task; + + if (async == NO) + { + NSLog(@"No font cache available - building new one - this may " + @"take several seconds (or minutes on a slow machine with " + @"lots of fonts)"); + } + if (!env || !(path = [env objectForKey: @"GNUSTEP_SYSTEM_ROOT"])) + { + path = [NSString stringWithCString: + stringify_it(GNUSTEP_INSTALL_PREFIX)]; + } + path = [path stringByAppendingPathComponent: @"Tools"]; + path = [path stringByAppendingPathComponent: @"font_cacher"]; + task = [NSTask launchedTaskWithLaunchPath: path + arguments: [NSArray arrayWithObject: file_name]]; + if (task == nil || async == YES) + { + return NO; + } + [task waitUntilExit]; + o = [NSUnarchiver unarchiveObjectWithFile: cacheName]; + if (o == nil) + { + NSLog(@"Error - font cache doesn't exist"); + return NO; + } + } + else + { + // Ensure archive is written in latest format. + [NSArchiver archiveRootObject: o toFile: cacheName]; + } + + ASSIGN(cache, o); + return YES; +} + +- (void) enumerateFontsAndFamilies +{ + if (cache == nil) + { + if (load_cache(cache_name(), NO)) + { + allFontNames = [[cache objectForKey: @"AllFontNames"] allObjects]; + allFontFamilies = [cache objectForKey: @"AllFontFamilies"]; + // This dictionary stores the XLFD for each font + creationDictionary = [cache objectForKey: @"CreationDictionary"]; + } + } +} + +@end diff --git a/Source/xlib/XGGState.m b/Source/xlib/XGGState.m new file mode 100644 index 0000000..b345d29 --- /dev/null +++ b/Source/xlib/XGGState.m @@ -0,0 +1,1856 @@ +/* XGGState - Implements graphic state drawing for Xlib + + Copyright (C) 1998 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Nov 1998 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ + +#include "config.h" +#include +#include +#include +#include +#include "xlib/XGGeometry.h" +#include "xlib/XGContext.h" +#include "xlib/XGGState.h" +#include "xlib/XGContext.h" +#include "xlib/XGPrivate.h" +#include "xlib/xrtools.h" +#include "math.h" + +#define XDPY (((RContext *)context)->dpy) + +static BOOL shouldDrawAlpha = YES; + +#define CHECK_GC \ + if (!xgcntxt) \ + [self createGraphicContext] + +#define COPY_GC_ON_CHANGE \ + CHECK_GC; \ + if (sharedGC == YES) \ + [self copyGraphicContext] + +#define AINDEX 5 + +@interface XGGState (Private) +- (void) _alphaBuffer: (gswindow_device_t *)dest_win; +- (void) _paintPath: (ctxt_object_t) drawType; +- (void) createGraphicContext; +- (void) copyGraphicContext; +@end + +@implementation XGGState + +static Region emptyRegion; + ++ (void) initialize +{ + static BOOL beenHere = NO; + + if (beenHere == NO) + { + XPoint pts[5]; + id obj = [[NSUserDefaults standardUserDefaults] + stringForKey: @"GraphicCompositing"]; + if (obj) + shouldDrawAlpha = [obj boolValue]; + + beenHere = YES; + pts[0].x = 0; pts[0].y = 0; + pts[1].x = 0; pts[1].y = 0; + pts[2].x = 0; pts[2].y = 0; + pts[3].x = 0; pts[3].y = 0; + pts[4].x = 0; pts[4].y = 0; + emptyRegion = XPolygonRegion(pts, 5, WindingRule); + NSAssert(XEmptyRegion(emptyRegion), NSInternalInconsistencyException); + } +} + +/* Designated initializer. */ +- initWithDrawContext: (GSContext *)drawContext +{ + [super initWithDrawContext: drawContext]; + + context = (void *)[(XGContext *)drawContext xrContext]; + NSParameterAssert((RContext *)context); + draw = 0; + alpha_buffer = 0; + color.field[AINDEX] = 1.0; + xgcntxt = None; + return self; +} + +- (void) dealloc +{ + if ( sharedGC == NO && xgcntxt ) + { + XFreeGC(XDPY, xgcntxt); + } + if (clipregion) + XDestroyRegion(clipregion); + [super dealloc]; +} + +- (id) deepen +{ + [super deepen]; + + // Copy the GC + if (draw != 0) + [self copyGraphicContext]; + + // Copy the clipregion + if (clipregion) + { + Region region = XCreateRegion(); + + XIntersectRegion(clipregion, clipregion, region); + self->clipregion = region; + } + + return self; +} + +- (void) setWindow: (int)number; +{ + gswindow_device_t *gs_win; + + window = number; + alpha_buffer = 0; + drawingAlpha = NO; + gs_win = [XGServer _windowWithTag: window]; + if (gs_win == NULL) + { + DPS_ERROR(DPSinvalidid, @"Setting invalid window on gstate"); + return; + } + + if (gs_win != NULL && gs_win->alpha_buffer != 0) + { + alpha_buffer = gs_win->alpha_buffer; + if (shouldDrawAlpha) + drawingAlpha = YES; + } +} + +- (void) setDrawable: (Drawable)theDrawable; +{ + draw = theDrawable; +} + +- (void) setGraphicContext: (GC)xGraphicContext +{ + GC source; + unsigned long mask; + BOOL old_shared; + + source = xgcntxt; + old_shared = sharedGC; + if (xGraphicContext == None) + return; + if (xGraphicContext == xgcntxt) + return; + + xgcntxt = xGraphicContext; + sharedGC = YES; /* Not sure if we really own the GC */ + /* Update the GC to reflect our settings */ + if (source == None) + return; + mask = GCForeground | GCFont | GCFunction | GCFillRule | + GCBackground | GCCapStyle | GCJoinStyle | GCLineWidth | + GCLineStyle | GCDashOffset | GCDashList; + XCopyGC(XDPY, source, mask, xgcntxt); + + if (source != None && old_shared == NO) + XFreeGC(XDPY, source); +} + +/* Set various characteristics of the graphic context */ +- (void) setGCValues: (XGCValues)values withMask: (int)mask +{ + COPY_GC_ON_CHANGE; + if (xgcntxt == 0) + return; + XChangeGC(XDPY, xgcntxt, mask, &values); +} + +/* Set the GC clipmask. */ +- (void) setClipMask +{ + COPY_GC_ON_CHANGE; + if (xgcntxt == 0) + return; + if (!clipregion) + { + XSetClipMask(XDPY, xgcntxt, None); + return; + } + + XSetRegion(XDPY, xgcntxt, clipregion); +} + +/* Returns the clip region, which must be freed by the caller */ +- (Region) xClipRegion +{ + Region region = XCreateRegion(); + + if (clipregion) + XIntersectRegion(clipregion, clipregion, region); + else + XIntersectRegion(emptyRegion, emptyRegion, region); + + return region; +} + +- (void) setColor: (xr_device_color_t)acolor; +{ + float alpha = color.field[AINDEX]; + color = acolor; + color.field[AINDEX] = alpha; + gcv.foreground = xrColorToPixel((RContext *)context, color); + [self setGCValues: gcv withMask: GCForeground]; +} + +- (void) setFont: (NSFont*)newFont +{ + XGFontInfo *font_info; + + if (font == newFont) + return; + + ASSIGN(font, newFont); + + COPY_GC_ON_CHANGE; + if (xgcntxt == 0) + return; + + font_info = (XGFontInfo *)[font fontInfo]; + [font_info setActiveFor: XDPY gc: xgcntxt]; +} + +- (NSFont*) currentFont +{ + return font; +} + +- (void) setOffset: (NSPoint)theOffset +{ + offset = theOffset; +} + +- (NSPoint) offset +{ + return offset; +} + +- (void) copyGraphicContext +{ + GC source; + unsigned long mask; + + if (draw == 0) + { + DPS_ERROR(DPSinvalidid, @"Copying a GC with no Drawable defined"); + return; + } + + source = xgcntxt; + mask = 0xffffffff; /* Copy everything (Hopefully) */ + xgcntxt = XCreateGC(XDPY, draw, 0, NULL); + XCopyGC(XDPY, source, mask, xgcntxt); + sharedGC = NO; + return; +} + +// Create a default graphics context. +- (void) createGraphicContext +{ + if (draw == 0) + { + /* This could happen with a defered window */ + DPS_WARN(DPSinvalidid, @"Creating a GC with no Drawable defined"); + return; + } + gcv.function = GXcopy; + gcv.background = ((RContext *)context)->white; + gcv.foreground = ((RContext *)context)->black; + gcv.plane_mask = AllPlanes; + gcv.line_style = LineSolid; + gcv.fill_style = FillSolid; + gcv.fill_rule = WindingRule; + xgcntxt = XCreateGC(XDPY, draw, + GCFunction | GCForeground | GCBackground | GCPlaneMask + | GCFillStyle | GCFillRule| GCLineStyle, + &gcv); + [self setClipMask]; + sharedGC = NO; + return; +} + +- (NSRect)clipRect +{ + XRectangle r; + r.width = 0; r.height = 0; + if (clipregion) + XClipBox(clipregion, &r); + return NSMakeRect(r.x, r.y, r.width-1, r.height-1); +} + +- (BOOL) hasGraphicContext +{ + return (xgcntxt) ? YES : NO; +} + +- (BOOL) hasDrawable +{ + return (draw ? YES : NO); +} + +- (int) window +{ + return window; +} + +- (Drawable) drawable +{ + return draw; +} + +- (GC) graphicContext +{ + return xgcntxt; +} + +- (void) copyBits: (XGGState*)source fromRect: (NSRect)aRect + toPoint: (NSPoint)aPoint +{ + XRectangle dst; + XRectangle src; + NSRect flushRect; + Drawable from; + + flushRect.size = aRect.size; + flushRect.origin = aPoint; + + CHECK_GC; + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for copyBits"); + return; + } + from = source->draw; + if (from == 0) + { + DPS_ERROR(DPSinvalidid, @"No source Drawable defined for copyBits"); + return; + } + + src = XGViewRectToX(source, aRect); + dst = XGViewRectToX(self, flushRect); + NSDebugLLog(@"XGGraphics", @"Copy area from %@ to %@", + NSStringFromRect(aRect), NSStringFromPoint(aPoint)); + XCopyArea(XDPY, from, draw, xgcntxt, + src.x, src.y, src.width, src.height, dst.x, dst.y); +} + +- (void) _alphaBuffer: (gswindow_device_t *)dest_win +{ + if (dest_win->alpha_buffer == 0 + && dest_win->type != NSBackingStoreNonretained) + { + xr_device_color_t old_color; + dest_win->alpha_buffer = XCreatePixmap(XDPY, draw, + NSWidth(dest_win->xframe), + NSHeight(dest_win->xframe), + dest_win->depth); + + /* Fill alpha also (opaque by default) */ + old_color = color; + [self DPSsetgray: 1]; + XFillRectangle(XDPY, dest_win->alpha_buffer, xgcntxt, 0, 0, + NSWidth(dest_win->xframe), NSHeight(dest_win->xframe)); + [self setColor: old_color]; + } + if (shouldDrawAlpha && dest_win->alpha_buffer != 0) + { + alpha_buffer = dest_win->alpha_buffer; + drawingAlpha = YES; + } +} + +- (void) _compositeGState: (XGGState *) source + fromRect: (NSRect) fromRect + toPoint: (NSPoint) toPoint + op: (NSCompositingOperation) op + fraction: (float)delta +{ + XRectangle srect; + XRectangle drect; + + XPoint toXPoint; + + RXImage *source_im; + RXImage *source_alpha; + + RXImage *dest_im; + RXImage *dest_alpha; + + gswindow_device_t *source_win; + gswindow_device_t *dest_win; + + + // --- get source information -------------------------------------------------- + NSDebugLLog(@"XGGraphics", @"Composite from %@ to %@", + NSStringFromRect(fromRect), NSStringFromPoint(toPoint)); + + if (!source) + source = self; + + source_win = [XGServer _windowWithTag: source->window]; + if (!source_win) + { + DPS_ERROR(DPSinvalidid, @"Invalid composite source gstate"); + return; + } + + if (source_win->buffer == 0 && source_win->map_state != IsViewable) + { + /* Can't get pixel information from a window that isn't mapped */ + DPS_ERROR(DPSinvalidaccess, @"Invalid gstate buffer"); + return; + } + + + // --- get destination information ---------------------------------------------- + + dest_win = [XGServer _windowWithTag: window]; + if (!dest_win) + { + DPS_ERROR(DPSinvalidid, @"Invalid composite gstate"); + return; + } + + if (dest_win->buffer == 0 && dest_win->map_state != IsViewable) + { + /* Why bother drawing? */ + return; + } + + + // --- determine region to draw -------------------------------------- + + { + NSRect flushRect; // destination rectangle + // in View coordinates + + flushRect.size = fromRect.size; + flushRect.origin = toPoint; + + drect = XGViewRectToX(self, flushRect); + + toXPoint.x = drect.x; + toXPoint.y = drect.y; + + srect = XGViewRectToX (source, fromRect); + + clipXRectsForCopying (source_win, &srect, dest_win, &drect); + + if (XGIsEmptyRect(drect)) + return; + + } + + // --- get destination XImage ---------------------------------------- + + if (draw == dest_win->ident && dest_win->visibility < 0) + { + /* Non-backingstore window isn't visible, so just make up the image */ + dest_im = RCreateXImage((RContext *)context, dest_win->depth, + XGWidth(drect), XGHeight(drect)); + } + else + { + dest_im = RGetXImage((RContext *)context, draw, XGMinX(drect), XGMinY (drect), + XGWidth (drect), XGHeight (drect)); + } + + if (dest_im->image == 0) + {//FIXME: Should not happen, + DPS_ERROR (DPSinvalidaccess, @"unable to fetch destination image"); + return; + } + + + // --- get source XImage --------------------------------------------- + + source_im = RGetXImage ((RContext *)context, + GET_XDRAWABLE (source_win), + XGMinX(srect), XGMinY(srect), + XGWidth(srect), XGHeight(srect)); + + // --- create alpha XImage ------------------------------------------- + /* Force creation of our alpha buffer */ + [self _alphaBuffer: dest_win]; + + /* Composite it */ + source_alpha = RGetXImage((RContext *)context, source_win->alpha_buffer, + XGMinX(srect), XGMinY(srect), + XGWidth(srect), XGHeight(srect)); + + if (alpha_buffer) + { + dest_alpha = RGetXImage((RContext *)context, alpha_buffer, + XGMinX(drect), XGMinY(drect), + XGWidth(drect), XGHeight(drect)); + } + else + { + dest_alpha = NULL; + } + + // --- THE REAL WORK IS DONE HERE! ----------------------------------- + + { + XRectangle xdrect = { 0, 0, XGWidth (drect), XGHeight (drect) }; + + _pixmap_combine_alpha((RContext *)context, source_im, source_alpha, + dest_im, dest_alpha, xdrect, + op, [(XGContext *)drawcontext drawMechanism], delta); + } + + + // --- put result back in the drawable ------------------------------- + + RPutXImage((RContext *)context, draw, xgcntxt, dest_im, 0, 0, + XGMinX(drect), XGMinY(drect), XGWidth(drect), XGHeight(drect)); + + if (dest_alpha) + { + RPutXImage((RContext *)context, dest_win->alpha_buffer, + xgcntxt, dest_alpha, 0, 0, + XGMinX(drect), XGMinY(drect), + XGWidth(drect), XGHeight(drect)); + RDestroyXImage((RContext *)context, dest_alpha); + } + + // --- clean up ------------------------------------------------------ + + RDestroyXImage((RContext *)context, dest_im); + RDestroyXImage((RContext *)context, source_im); + if (source_alpha) + RDestroyXImage((RContext *)context, source_alpha); +} + +- (void) compositeGState: (GSGState *)source + fromRect: (NSRect)aRect + toPoint: (NSPoint)aPoint + op: (NSCompositingOperation)op +{ + BOOL do_copy, source_alpha; + XGCValues comp_gcv; + + if (!source) + source = self; + + /* If we have no drawable, we can't proceed. */ + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for composite"); + return; + } + + /* Check alpha */ +#define CHECK_ALPHA \ + do { \ + gswindow_device_t *source_win; \ + source_win = [XGServer _windowWithTag: [(XGGState *)source window]]; \ + source_alpha = (source_win && source_win->alpha_buffer); \ + } while (0) + + do_copy = NO; + switch (op) + { + case NSCompositeClear: + do_copy = YES; + comp_gcv.function = GXclear; + break; + case NSCompositeCopy: + do_copy = YES; + comp_gcv.function = GXcopy; + break; + case NSCompositeSourceOver: + CHECK_ALPHA; + if (source_alpha == NO) + do_copy = YES; + else + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeSourceIn: + CHECK_ALPHA; + if (source_alpha == NO && drawingAlpha == NO) + do_copy = YES; + else + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeSourceOut: + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeSourceAtop: + CHECK_ALPHA; + if (source_alpha == NO && drawingAlpha == NO) + do_copy = YES; + else + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeDestinationOver: + CHECK_ALPHA; + if (drawingAlpha == NO) + return; + else + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeDestinationIn: + CHECK_ALPHA; + if (source_alpha == NO && drawingAlpha == NO) + return; + else + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeDestinationOut: + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeDestinationAtop: + CHECK_ALPHA; + if (source_alpha == NO && drawingAlpha == NO) + return; + else + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeXOR: + do_copy = NO; + comp_gcv.function = GXxor; + break; + case NSCompositePlusDarker: + do_copy = NO; + comp_gcv.function = GXcopy; + break; + case NSCompositeHighlight: + do_copy = NO; + comp_gcv.function = GXxor; + break; + case NSCompositePlusLighter: + do_copy = NO; + comp_gcv.function = GXcopy; + break; + } + + if (comp_gcv.function != GXcopy) + [self setGCValues: comp_gcv withMask: GCFunction]; + + if (shouldDrawAlpha == NO) + do_copy = YES; + + if (do_copy) + { + [self copyBits: (XGGState *)source fromRect: aRect toPoint: aPoint]; + } + else + { + [self _compositeGState: (XGGState *)source + fromRect: aRect + toPoint: aPoint + op: op + fraction: 1]; + } + + + if (comp_gcv.function != GXcopy) + { + comp_gcv.function = GXcopy; + [self setGCValues: comp_gcv withMask: GCFunction]; + } +} + +- (void) dissolveGState: (GSGState *)source + fromRect: (NSRect)aRect + toPoint: (NSPoint)aPoint + delta: (float)delta +{ + /* If we have no drawable, we can't proceed. */ + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for dissolve"); + return; + } + + if (shouldDrawAlpha == NO) + { + /* No alpha buffers */ + [self copyBits: (XGGState *)source fromRect: aRect toPoint: aPoint]; + } + else + { + [self _compositeGState: (XGGState *)source + fromRect: aRect + toPoint: aPoint + op: NSCompositeSourceOver + fraction: delta]; + } + +} + +- (void) compositerect: (NSRect)aRect + op: (NSCompositingOperation)op +{ + float gray; + + [self DPScurrentgray: &gray]; + if (fabs(gray - 0.667) < 0.005) + [self DPSsetgray: 0.333]; + else + [self DPSsetrgbcolor: 0.121 : 0.121 : 0]; + + /* FIXME: Really need alpha dithering to do this right - combine with + XGBitmapImageRep code? */ + switch (op) + { + case NSCompositeClear: + gcv.function = GXclear; + break; + case NSCompositeCopy: + gcv.function = GXcopy; + break; + case NSCompositeSourceOver: + gcv.function = GXcopy; + break; + case NSCompositeSourceIn: + gcv.function = GXcopy; + break; + case NSCompositeSourceOut: + gcv.function = GXcopy; + break; + case NSCompositeSourceAtop: + gcv.function = GXcopy; + break; + case NSCompositeDestinationOver: + gcv.function = GXcopy; + break; + case NSCompositeDestinationIn: + gcv.function = GXcopy; + break; + case NSCompositeDestinationOut: + gcv.function = GXcopy; + break; + case NSCompositeDestinationAtop: + gcv.function = GXcopy; + break; + case NSCompositeXOR: + gcv.function = GXcopy; + break; + case NSCompositePlusDarker: + gcv.function = GXcopy; + break; + case NSCompositeHighlight: + gcv.function = GXxor; + break; + case NSCompositePlusLighter: + gcv.function = GXcopy; + break; + default: + gcv.function = GXcopy; + break; + } + [self setGCValues: gcv withMask: GCFunction]; + [self DPSrectfill: NSMinX(aRect) : NSMinY(aRect) + : NSWidth(aRect) : NSHeight(aRect)]; + + if (gcv.function != GXcopy) + { + gcv.function = GXcopy; + [self setGCValues: gcv withMask: GCFunction]; + } + [self DPSsetgray: gray]; +} + +/* Paint the current path using Xlib calls. All coordinates should already + have been transformed to device coordinates. */ +- (void) _doPath: (XPoint*)pts : (int)count draw: (ctxt_object_t)type +{ + int fill_rule; + + COPY_GC_ON_CHANGE; + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for path"); + return; + } + fill_rule = WindingRule; + switch (type) + { + case path_stroke: + // Hack: Only draw when alpha is not zero + if (drawingAlpha == NO || color.field[AINDEX] != 0.0) + XDrawLines(XDPY, draw, xgcntxt, pts, count, CoordModeOrigin); + if (drawingAlpha) + { + xr_device_color_t old_color; + NSAssert(alpha_buffer, NSInternalInconsistencyException); + + old_color = color; + [self DPSsetgray: color.field[AINDEX]]; + XDrawLines(XDPY, alpha_buffer, xgcntxt, pts, count, CoordModeOrigin); + [self setColor: old_color]; + } + break; + case path_eofill: + gcv.fill_rule = EvenOddRule; + [self setGCValues: gcv withMask: GCFillRule]; + /* NO BREAK */ + case path_fill: + // Hack: Only draw when alpha is not zero + if (drawingAlpha == NO || color.field[AINDEX] != 0.0) + XFillPolygon(XDPY, draw, xgcntxt, pts, count, Complex, + CoordModeOrigin); + if (drawingAlpha) + { + xr_device_color_t old_color; + NSAssert(alpha_buffer, NSInternalInconsistencyException); + + old_color = color; + [self DPSsetgray: color.field[AINDEX]]; + XFillPolygon(XDPY, alpha_buffer, xgcntxt, pts, count, Complex, + CoordModeOrigin); + [self setColor: old_color]; + } + + if (gcv.fill_rule == EvenOddRule) + { + gcv.fill_rule = WindingRule; + [self setGCValues: gcv withMask: GCFillRule]; + } + break; + case path_eoclip: + fill_rule = EvenOddRule; + /* NO BREAK */ + case path_clip: + { + Region region, new_region; + region = XPolygonRegion(pts, count, fill_rule); + if (clipregion) + { + new_region=XCreateRegion(); + XIntersectRegion(clipregion, region, new_region); + XDestroyRegion(region); + XDestroyRegion(clipregion); + } else + new_region = region; + clipregion = new_region; + [self setClipMask]; + } + break; + default: + break; + } +} + +/* fill a complex path. All coordinates should already have been + transformed to device coordinates. */ +- (void) _doComplexPath: (XPoint*)pts + : (int*)types + : (int)count + ll: (XPoint)ll + ur: (XPoint)ur + draw: (ctxt_object_t)type +{ + int x, y, i, j, cnt, nseg = 0; + XSegment segments[count]; + Window root_rtn; + unsigned int width, height, b_rtn, d_rtn; + + COPY_GC_ON_CHANGE; + if (draw == 0) + { + DPS_WARN (DPSinvalidid, @"No Drawable defined for path"); + return; + } + + XGetGeometry (XDPY, draw, &root_rtn, &x, &y, &width, &height, + &b_rtn, &d_rtn); + if (ur.x < x || ll.x > x + (int)width) + { + return; + } + + if (ll.y < y) + { + ll.y = y; + } + if (ur.y > y + height) + { + ur.y = y + height; + } + + /* draw horizontal lines from the bottom to the top of the path */ + for (y = ll.y; y <= ur.y; y++) + { + int x[count], w[count], y0, y1; + int yh = y * 2 + 1; // shift y of horizontal line + XPoint lastP, p1; + + /* intersect horizontal line with path */ + for (i = 0, cnt = 0; i < count - 1; i++) + { + if (types[i] == 0) // move (new subpath) + { + lastP = pts[i]; + } + if (types[i+1] == 0) // last line of subpath + { + if (lastP.y == pts[i].y) + { + continue; + } + p1 = lastP; // close subpath + } + else + { + p1 = pts[i+1]; + } + y0 = pts[i].y * 2; + y1 = p1.y * 2; + if ((y0 < yh && yh < y1) || (y1 < yh && yh < y0) ) + { + int dy = yh - pts[i].y * 2; + int ldy = y1 - y0; + int ldx = (p1.x - pts[i].x) * 2; + + x[cnt] = pts[i].x + (ldx * dy / ldy) / 2; + /* sum up winding directions */ + if (type == path_fill) + { + w[cnt] = ((cnt) ? w[cnt-1] : 0) + (y0 < y1) ? -1 : 1; + } + cnt++; + } + } + + /* sort intersections */ + for (i = 0; i < cnt-1; i++) + { + for (j=i+1; j start line on odd intersection count + * winding fill -> start line on odd winding count + */ + if ((type == path_eofill && !(i%2)) || (type == path_fill && w[i])) + { + segments[nseg].x1 = x[i]; + segments[nseg].x2 = x[i+1]; + segments[nseg].y1 = segments[nseg].y2 = y; + nseg++; + } + } + + // Hack: Only draw when alpha is not zero + if (drawingAlpha == NO || color.field[AINDEX] != 0.0) + XDrawSegments (XDPY, draw, xgcntxt, segments, nseg); + if (drawingAlpha) + { + xr_device_color_t old_color; + NSAssert (alpha_buffer, NSInternalInconsistencyException); + + old_color = color; + [self DPSsetgray: color.field[AINDEX]]; + XDrawSegments (XDPY, alpha_buffer, xgcntxt, segments, nseg); + [self setColor: old_color]; + } + nseg = 0; + } // for y +} + +- (void) _paintPath: (ctxt_object_t) drawType +{ + unsigned count; + NSBezierPath *flatPath; + XPoint ll, ur; + + if (!path) + { + return; + } + + ll.x = ll.y = 0x7FFF; + ur.x = ur.y = 0; + flatPath = [path bezierPathByFlatteningPath]; + count = [flatPath elementCount]; + if (count) + { + XPoint pts[count]; + int ts[count]; + unsigned j, i = 0; + NSBezierPathElement type; + NSPoint points[3]; + BOOL first = YES; + NSPoint p, last_p; + BOOL doit; + BOOL complex = NO; + + for(j = 0; j < count; j++) + { + doit = NO; + type = [flatPath elementAtIndex: j associatedPoints: points]; + switch(type) + { + case NSMoveToBezierPathElement: + if (drawType != path_eofill && drawType != path_fill) + { + if (i > 1) + { + [self _doPath: pts : i draw: drawType]; + } + i = 0; + } + else if (i > 1) + { + complex = YES; + } + last_p = p = points[0]; + ts[i] = 0; + first = NO; + break; + case NSLineToBezierPathElement: + p = points[0]; + ts[i] = 1; + if (first) + { + last_p = points[0]; + first = NO; + } + break; + case NSCurveToBezierPathElement: + // This should not happen, as we flatten the path + p = points[2]; + ts[i] = 1; + if (first) + { + last_p = points[2]; + first = NO; + } + break; + case NSClosePathBezierPathElement: + p = last_p; + ts[i] = 1; + doit = YES; + break; + default: + break; + } + pts[i] = XGWindowPointToX (self, p); + if (pts[i].x < ll.x) + { + ll.x = pts[i].x; + } + if (pts[i].y > ur.x) + { + ur.x = pts[i].x; + } + if (pts[i].y < ll.y) + { + ll.y = pts[i].y; + } + if (pts[i].y > ur.y) + { + ur.y = pts[i].y; + } + i++; + + if (doit && i > 1) + { + if (complex) + { + [self _doComplexPath: pts : ts : i + ll: ll ur: ur draw: drawType]; + } + else + { + [self _doPath: pts : i draw: drawType]; + } + i = 0; + } + } /* for */ + + if (i > 1) + { + if (complex) + { + [self _doComplexPath: pts : ts : i + ll: ll ur: ur draw: drawType]; + } + else + { + [self _doPath: pts : i draw: drawType]; + } + } + } + + /* + * clip does not delete the current path, so we only clear the path if the + * operation was not a clipping operation. + */ + if ((drawType != path_clip) && (drawType != path_eoclip)) + { + [path removeAllPoints]; + } +} + +- (XPoint) viewPointToX: (NSPoint)aPoint +{ + return XGViewPointToX(self, aPoint); +} + +- (XRectangle) viewRectToX: (NSRect)aRect +{ + return XGViewRectToX(self, aRect); +} + +- (XPoint) windowPointToX: (NSPoint)aPoint +{ + return XGWindowPointToX(self, aPoint); +} + +- (XRectangle) windowRectToX: (NSRect)aRect +{ + return XGWindowRectToX(self, aRect); +} + +@end + +@implementation XGGState (Ops) + +- (void) DPScurrentalpha: (float *)alpha +{ + if (alpha) + *alpha = color.field[AINDEX]; +} + +- (void)DPScurrentcmykcolor: (float *)c : (float *)m : (float *)y : (float *)k +{ + xr_device_color_t new = color; + if (new.space != cmyk_colorspace) + new = xrConvertToCMYK(new); + *c = new.field[0]; + *m = new.field[1]; + *y = new.field[2]; + *k = new.field[3]; +} + +- (void)DPSsetcmykcolor: (float)c : (float)m : (float)y : (float)k +{ + color.space = cmyk_colorspace; + color.field[0] = c; + color.field[1] = m; + color.field[2] = y; + color.field[3] = k; + [self setColor:color]; +} + +- (void)DPScurrentgray: (float *)gray +{ + xr_device_color_t gcolor; + gcolor = xrConvertToGray(color); + *gray = gcolor.field[0]; +} + +- (void)DPScurrenthsbcolor: (float *)h : (float *)s : (float *)b +{ + xr_device_color_t gcolor; + gcolor = xrConvertToHSB(color); + *h = gcolor.field[0]; *s = gcolor.field[1]; *b = gcolor.field[2]; +} + +- (void)DPScurrentrgbcolor: (float *)r : (float *)g : (float *)b +{ + xr_device_color_t gcolor; + gcolor = xrConvertToRGB(color); + *r = gcolor.field[0]; *g = gcolor.field[1]; *b = gcolor.field[2]; +} + +- (void) DPSsetalpha: (float)a +{ + gswindow_device_t *gs_win; + color.field[AINDEX] = a; + gs_win = [XGServer _windowWithTag: window]; + if (!gs_win) + return; + if (a < 1.0) + [self _alphaBuffer: gs_win]; +} + +- (void)DPSsetgray: (float)gray +{ + color.space = gray_colorspace; + color.field[0] = gray; + [self setColor: color]; +} + +- (void)DPSsethsbcolor: (float)h : (float)s : (float)b +{ + color.space = hsb_colorspace; + color.field[0] = h; color.field[1] = s; color.field[2] = b; + [self setColor: color]; +} + +- (void)DPSsetrgbcolor: (float)r : (float)g : (float)b +{ + color.space = rgb_colorspace; + color.field[0] = r; color.field[1] = g; color.field[2] = b; + [self setColor: color]; +} + +/* ----------------------------------------------------------------------- */ +/* Text operations */ +/* ----------------------------------------------------------------------- */ +typedef enum { + show_delta, show_array_x, show_array_y, show_array_xy +} show_array_t; + +/* Omnibus show string routine that combines that characteristics of + ashow, awidthshow, widthshow, xshow, xyshow, and yshow */ +- (void) _showString: (const char *)s + xCharAdj: (float)cx + yCharAdj: (float)cy + char: (char)c + adjArray: (const float *)arr + arrType: (show_array_t)type + isRelative: (BOOL)relative; +{ + int i; + int len; + int width; + NSSize scale; + XGFontInfo *font_info = [font fontInfo]; + NSPoint point = [path currentPoint]; + + if (font_info == nil) + { + NSLog(@"DPS (xgps): no font set\n"); + return; + } + + COPY_GC_ON_CHANGE; + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for show"); + return; + } + + /* Use only delta transformations (no offset) */ + len = strlen(s); + scale = [ctm sizeInMatrixSpace: NSMakeSize(1,1)]; + for (i = 0; i < len; i++) + { + NSPoint delta; + XPoint xp; + + // FIXME: We should put this line before the loop + // and do all computation in display space. + xp = XGWindowPointToX(self, point); + width = [font_info widthOf: s+i lenght: 1]; + // Hack: Only draw when alpha is not zero + if (drawingAlpha == NO || color.field[AINDEX] != 0.0) + [font_info draw: s+i lenght: 1 + onDisplay: XDPY drawable: draw + with: xgcntxt at: xp]; + + if (drawingAlpha) + { + xr_device_color_t old_color; + NSAssert(alpha_buffer, NSInternalInconsistencyException); + + old_color = color; + [self DPSsetgray: color.field[AINDEX]]; + [font_info draw: s+i lenght: 1 + onDisplay: XDPY drawable: alpha_buffer + with: xgcntxt at: xp]; + [self setColor: old_color]; + } + /* Note we update the current point according to the current + transformation scaling, although the text isn't currently + scaled (FIXME). */ + if (type == show_array_xy) + { + delta.x = arr[2*i]; delta.y = arr[2*i+1]; + } + else if (type == show_array_x) + { + delta.x = arr[i]; delta.y = 0; + } + else if (type == show_array_y) + { + delta.x = 0; delta.y = arr[i]; + } + else + { + delta.x = arr[0]; delta.y = arr[1]; + } + delta = [ctm deltaPointInMatrixSpace: delta]; + if (relative == YES) + { + delta.x += width * scale.width; + delta.y += [font_info ascender] * scale.height; + } + if (c && *(s+i) == c) + { + NSPoint cdelta; + cdelta.x = cx; cdelta.y = cy; + cdelta = [ctm deltaPointInMatrixSpace: cdelta]; + delta.x += cdelta.x; delta.y += cdelta.y; + } + point.x += delta.x; + if (type != show_delta) + point.y += delta.y; + } + // FIXME: Should we set the current point now? +} + +- (void)DPSashow: (float)x : (float)y : (const char *)s +{ + float arr[2]; + + arr[0] = x; arr[1] = y; + [self _showString: s + xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: arr arrType: show_delta + isRelative: YES]; +} + +- (void)DPSawidthshow: (float)cx : (float)cy : (int)c : (float)ax : (float)ay : (const char *)s +{ + float arr[2]; + + arr[0] = ax; arr[1] = ay; + [self _showString: s + xCharAdj: cx yCharAdj: cy char: c adjArray: arr arrType: show_delta + isRelative: YES]; +} + +- (void)DPSshow: (const char *)s +{ + int len; + int width; + NSSize scale; + XPoint xp; + XGFontInfo *font_info = [font fontInfo]; + + if (font_info == nil) + { + NSLog(@"DPS (xgps): no font set\n"); + return; + } + + COPY_GC_ON_CHANGE; + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for show"); + return; + } + + len = strlen(s); + width = [font_info widthOf: s lenght: len]; + xp = XGWindowPointToX(self, [path currentPoint]); + // Hack: Only draw when alpha is not zero + if (drawingAlpha == NO || color.field[AINDEX] != 0.0) + [font_info draw: s lenght: len + onDisplay: XDPY drawable: draw + with: xgcntxt at: xp]; + + if (drawingAlpha) + { + xr_device_color_t old_color; + NSAssert(alpha_buffer, NSInternalInconsistencyException); + + old_color = color; + [self DPSsetgray: color.field[AINDEX]]; + [font_info draw: s lenght: len + onDisplay: XDPY drawable: alpha_buffer + with: xgcntxt at: xp]; + + [self setColor: old_color]; + } + /* Note we update the current point according to the current + transformation scaling, although the text isn't currently + scaled (FIXME). */ + scale = [ctm sizeInMatrixSpace: NSMakeSize(1, 1)]; + //scale = NSMakeSize(1, 1); + [path relativeMoveToPoint: NSMakePoint(width * scale.width, 0)]; +} + +- (void)DPSwidthshow: (float)x : (float)y : (int)c : (const char *)s +{ + float arr[2]; + + arr[0] = 0; arr[1] = 0; + [self _showString: s + xCharAdj: x yCharAdj: y char: c adjArray: arr arrType: show_delta + isRelative: YES]; +} + +- (void)DPSxshow: (const char *)s : (const float *)numarray : (int)size +{ + [self _showString: s + xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_x + isRelative: NO]; +} + +- (void)DPSxyshow: (const char *)s : (const float *)numarray : (int)size +{ + [self _showString: s + xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_xy + isRelative: NO]; +} + +- (void)DPSyshow: (const char *)s : (const float *)numarray : (int)size +{ + [self _showString: s + xCharAdj: 0 yCharAdj: 0 char: 0 adjArray: numarray arrType: show_array_y + isRelative: NO]; +} + +/* ----------------------------------------------------------------------- */ +/* Gstate operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPScurrentlinecap: (int *)linecap +{ + *linecap = gcv.cap_style - CapButt; +} + +- (void)DPScurrentlinejoin: (int *)linejoin +{ + *linejoin = gcv.join_style - JoinMiter; +} + +- (void)DPScurrentlinewidth: (float *)width +{ + *width = gcv.line_width; +} + +- (void)DPSinitgraphics +{ + [ctm makeIdentityMatrix]; + DESTROY(path); + if (clipregion) + XDestroyRegion(clipregion); + clipregion = 0; + /* FIXME: reset the GC */ + color.space = gray_colorspace; + color.field[0] = 0.0; + [self setColor: color]; + color.field[AINDEX] = 1.0; +} + +- (void)DPSsetdash: (const float *)pat : (int)size : (float)pat_offset +{ + int dash_offset; + char dash_list[size]; + int i; + + gcv.line_style = LineOnOffDash; + [self setGCValues: gcv withMask: GCLineStyle]; + + // FIXME: How to convert those values? + dash_offset = (int)pat_offset; + for (i = 0; i < size; i++) + dash_list[i] = (char)pat[i]; + + // We can only set the dash pattern, if xgcntxt exists. + if (xgcntxt == 0) + return; + XSetDashes(XDPY, xgcntxt, dash_offset, dash_list, size); +} + +- (void)DPSsetlinecap: (int)linecap +{ + gcv.cap_style = linecap + CapButt; + [self setGCValues: gcv withMask: GCCapStyle]; +} + +- (void)DPSsetlinejoin: (int)linejoin +{ + gcv.join_style = linejoin + JoinMiter; + [self setGCValues: gcv withMask: GCJoinStyle]; +} + +- (void)DPSsetlinewidth: (float)width +{ + int w; + + /* + * Evil hack to get drawing to work - with a line thickness of 1, the + * rectangles we draw seem to lose their bottom right corners irrespective + * of the join/cap settings - but with a thickness of zero things work. + */ + if (width < 1.5) + width = 0.0; + + w = (int)width; + if (gcv.line_width != w) + { + gcv.line_width = w; + [self setGCValues: gcv withMask: GCLineWidth]; + } +} + +/* ----------------------------------------------------------------------- */ +/* Paint operations */ +/* ----------------------------------------------------------------------- */ +- (void)DPSclip +{ + [self _paintPath: path_clip]; +} + +- (void)DPSeoclip +{ + [self _paintPath: path_eoclip]; +} + +- (void)DPSeofill +{ + [self _paintPath: path_eofill]; +} + +- (void)DPSfill +{ + [self _paintPath: path_fill]; +} + +- (void)DPSinitclip +{ + if (clipregion) + XDestroyRegion(clipregion); + clipregion = 0; + [self setClipMask]; +} + +- (void)DPSrectclip: (float)x : (float)y : (float)w : (float)h +{ + XRectangle xrect; + + CHECK_GC; + + xrect = XGViewRectToX(self, NSMakeRect(x, y, w, h)); + + if (clipregion == 0) + { + clipregion = XCreateRegion(); + XUnionRectWithRegion(&xrect, clipregion, clipregion); + } + else + { + Region region; + region = XCreateRegion(); + XUnionRectWithRegion(&xrect, region, region); + XIntersectRegion(clipregion, region, clipregion); + XDestroyRegion(region); + } + [self setClipMask]; +} + +- (void)DPSrectfill: (float)x : (float)y : (float)w : (float)h +{ + XRectangle bounds; + + CHECK_GC; + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for drawing"); + return; + } + + bounds = XGViewRectToX(self, NSMakeRect(x, y, w, h)); + // Hack: Only draw when alpha is not zero + if (drawingAlpha == NO || color.field[AINDEX] != 0.0) + XFillRectangle(XDPY, draw, xgcntxt, + bounds.x, bounds.y, bounds.width, bounds.height); + + if (drawingAlpha) + { + /* Fill alpha also */ + xr_device_color_t old_color; + NSAssert(alpha_buffer, NSInternalInconsistencyException); + + old_color = color; + [self DPSsetgray: color.field[AINDEX]]; + XFillRectangle(XDPY, alpha_buffer, xgcntxt, + bounds.x, bounds.y, bounds.width, bounds.height); + [self setColor: old_color]; + } +} + +- (void)DPSrectstroke: (float)x : (float)y : (float)w : (float)h +{ + XRectangle bounds; + + CHECK_GC; + if (draw == 0) + { + DPS_WARN(DPSinvalidid, @"No Drawable defined for drawing"); + return; + } + + bounds = XGViewRectToX(self, NSMakeRect(x, y, w, h)); + if (bounds.width > 0) + bounds.width--; + if (bounds.height > 0) + bounds.height--; + // Hack: Only draw when alpha is not zero + if (drawingAlpha == NO || color.field[AINDEX] != 0.0) + XDrawRectangle(XDPY, draw, xgcntxt, + bounds.x, bounds.y, bounds.width, bounds.height); + + if (drawingAlpha) + { + /* Fill alpha also */ + xr_device_color_t old_color; + NSAssert(alpha_buffer, NSInternalInconsistencyException); + + old_color = color; + [self DPSsetgray: color.field[AINDEX]]; + XDrawRectangle(XDPY, alpha_buffer, xgcntxt, + bounds.x, bounds.y, bounds.width, bounds.height); + [self setColor: old_color]; + } +} + +- (void)DPSstroke +{ + [self _paintPath: path_stroke]; +} + +/* ----------------------------------------------------------------------- */ +/* NSGraphics Ops */ +/* ----------------------------------------------------------------------- */ +- (void)DPSimage: (NSAffineTransform*) matrix : (int) pixelsWide : (int) pixelsHigh + : (int) bitsPerSample : (int) samplesPerPixel + : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar + : (BOOL) hasAlpha : (NSString *) colorSpaceName + : (const unsigned char *const [5]) data +{ + BOOL one_is_black, fast_min; + NSRect rect; + XRectangle sr, dr, cr; + RXImage *dest_im, *dest_alpha; + gswindow_device_t *dest_win; + int cspace; + NSAffineTransform *old_ctm = nil; + + // FIXME for now we hard code the minification behaviour + fast_min = YES; + + rect = NSZeroRect; + one_is_black = NO; + cspace = rgb_colorspace; + rect.size.width = (float) pixelsWide; + rect.size.height = (float) pixelsHigh; + + // default is 8 bit grayscale + if (!bitsPerSample) + bitsPerSample = 8; + if (!samplesPerPixel) + samplesPerPixel = 1; + + // FIXME - does this work if we are passed a planar image but no hints ? + if (!bitsPerPixel) + bitsPerPixel = bitsPerSample * samplesPerPixel; + if (!bytesPerRow) + bytesPerRow = (bitsPerPixel * pixelsWide) / 8; + + /* make sure its sane - also handles row padding if hint missing */ + while((bytesPerRow * 8) < (bitsPerPixel * pixelsWide)) + bytesPerRow++; + + /* get the colour space */ + if (colorSpaceName) + { + if ([colorSpaceName isEqualToString: NSDeviceRGBColorSpace]) + cspace = rgb_colorspace; + else if([colorSpaceName isEqualToString: NSDeviceCMYKColorSpace]) + cspace = cmyk_colorspace; + else if([colorSpaceName isEqualToString: NSDeviceWhiteColorSpace]) + cspace = gray_colorspace; + else if([colorSpaceName isEqualToString: NSDeviceBlackColorSpace]) + { + cspace = gray_colorspace; + one_is_black = YES; + } + else + { + // if we dont recognise the name use RGB or greyscale as appropriate + NSLog(@"XGContext (DPSImage): Unknown colour space %@", colorSpaceName); + if(samplesPerPixel > 2) + cspace = rgb_colorspace; + else + cspace = gray_colorspace; + } + } + + // Apply the additional transformation + if (matrix) + { + old_ctm = [ctm copy]; + [ctm appendTransform: matrix]; + } + + // --- Get our drawable info ----------------------------------------- + dest_win = [XGServer _windowWithTag: window]; + if (!dest_win) + { + DPS_ERROR(DPSinvalidid, @"Invalid image gstate"); + return; + } + + + // --- Determine screen coverage -------------------------------------- + if (viewIsFlipped) + rect.origin.y -= rect.size.height; + sr = [self viewRectToX: rect]; + + // --- Determine region to draw -------------------------------------- + if (clipregion) + XClipBox (clipregion, &cr); + else + cr = sr; + + dr = XGIntersectionRect (sr, cr); + + + // --- If there is nothing to draw return ---------------------------- + if (XGIsEmptyRect (dr)) + { + if (old_ctm != nil) + { + RELEASE(ctm); + // old_ctm is already retained + ctm = old_ctm; + } + return; + } + + if (dest_win->buffer == 0 && dest_win->map_state != IsViewable) + { + if (old_ctm != nil) + { + RELEASE(ctm); + // old_ctm is already retained + ctm = old_ctm; + } + return; + } + + + // --- Get the destination images ------------------------------------ + dest_im = RGetXImage ((RContext *)context, draw, XGMinX (dr), XGMinY (dr), + XGWidth (dr), XGHeight (dr)); + + // Force creation of our alpha buffer + if (hasAlpha) + { + [self _alphaBuffer: dest_win]; + } + + // Composite it + if (alpha_buffer != 0) + { + dest_alpha = RGetXImage ((RContext *)context, alpha_buffer, + XGMinX (dr), XGMinY (dr), + XGWidth (dr), XGHeight (dr)); + } + else + { + dest_alpha = 0; + } + + + if (hasAlpha && alpha_buffer && + (dest_alpha == 0 || dest_alpha->image == 0)) + { + NSLog(@"XGContext (DPSimage): Cannot create alpha image\n"); + if (old_ctm != nil) + { + RELEASE(ctm); + // old_ctm is already retained + ctm = old_ctm; + } + return; + } + + // --- The real work is done HERE ------------------------------------ + _bitmap_combine_alpha((RContext *)context, (unsigned char **)data, + pixelsWide, pixelsHigh, + bitsPerSample, samplesPerPixel, + bitsPerPixel, bytesPerRow, + cspace, one_is_black, + isPlanar, hasAlpha, fast_min, + dest_im, dest_alpha, sr, dr, + 0, [(XGContext *)drawcontext drawMechanism]); + + /* Draw into the window/buffer */ + RPutXImage((RContext *)context, draw, xgcntxt, dest_im, 0, 0, + XGMinX (dr), XGMinY (dr), XGWidth (dr), XGHeight (dr)); + if (dest_alpha) + { + RPutXImage((RContext *)context, dest_win->alpha_buffer, + xgcntxt, dest_alpha, 0, 0, + XGMinX (dr), XGMinY (dr), XGWidth (dr), XGHeight (dr)); + + RDestroyXImage((RContext *)context, dest_alpha); + } + RDestroyXImage((RContext *)context, dest_im); + + if (old_ctm != nil) + { + RELEASE(ctm); + // old_ctm is already retained + ctm = old_ctm; + } +} + +@end + + diff --git a/Source/xlib/XGGeometry.m b/Source/xlib/XGGeometry.m new file mode 100644 index 0000000..928131a --- /dev/null +++ b/Source/xlib/XGGeometry.m @@ -0,0 +1,130 @@ +/* XGGeometry - Utility functions that calculate in device space + + Copyright (C) 2002 Free Software Foundation, Inc. + + Written by: Willem Oudshoorn + + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include "config.h" +#include +#include "xlib/XGGeometry.h" +#include "x11/XGServer.h" + +/** + * Returns the area that is accessible in the underlying drawable + * of win. + * + * Accessible means that we can use XPutPixel and XGetPixel + * on all the points in the result. + * If the window uses a backingstore this will be the size + * of the underlying drawable, but if the window does not + * use backing store and the window is partly outside the screen + * it will be the part of the window that falls inside the screen. + * + * NOTE: + * Unfortunately, the gswindow_device_t does not contain a reference + * to the XDisplay it is displayed on and we need it. + */ +XRectangle +accessibleRectForWindow (gswindow_device_t* win) +{ + Display* xdpy = [XGServer currentXDisplay]; + Window root; + Window ignoreWindow; + int x, y, w, h; + int ignoreInt; + XRectangle winRect; + + if (!XGetGeometry (xdpy, GET_XDRAWABLE (win), + &root, + &x, &y, + &w, &h, + &ignoreInt, + &ignoreInt)) + { + NSDebugLLog (@"XGGeometry", @"invalide Drawable in gswindow_device"); + return XGMakeRect (0, 0, 0, 0); + } + + winRect = XGMakeRect (0, 0, w, h); + + if (win->buffer) + { + return winRect; + } + + // we do not have backing store, so clip it to the screen. + if (!XGetGeometry (xdpy, root, + &root, + &ignoreInt, &ignoreInt, + &w, &h, + &ignoreInt, &ignoreInt)) + { + NSDebugLLog (@"XGGeometry", @"could not determine size of root"); + return XGMakeRect (0, 0, 0, 0); + } + + if (!XTranslateCoordinates (xdpy, + root, + GET_XDRAWABLE (win), + 0, 0, + &x, &y, + &ignoreWindow)) + { + NSDebugLLog (@"XGGeometry", @"could not determine position of device"); + return XGMakeRect (0, 0, 0, 0); + } + + return XGIntersectionRect (winRect, XGMakeRect (x, y, w, h)); +} + + +/** + * + * POST CONDITIONS + * winA and winB are unmodified + * rectA and rectB have the same size + * rectA is an accessible rectangle in winA + * rectB is an accessible rectangle in winB + * rectA is a subrectangle of the argument rectA + * rectB is a subrectangle of the argument rectB + * the size of RectA and rectB are maximal with respect to the conditions above. + * + * USAGE + * typical usage will be in copy operations between one gswindow_device to + * another gswindow_device. This because the result will be the maximal + * region that we are able to copy without generating X-protocol errors + * or segfaults. + */ +void +clipXRectsForCopying (gswindow_device_t* winA, XRectangle* rectA, + gswindow_device_t* winB, XRectangle* rectB) +{ + // First make A smaller. + *rectA = XGIntersectionRect (*rectA, accessibleRectForWindow (winA)); + // update size of B with the size of A + rectB->width = MIN (rectA->width, rectB->width); + rectB->height = MIN (rectA->height, rectB->height); + // now make B smaller + *rectB = XGIntersectionRect (*rectB, accessibleRectForWindow (winB)); + // and update size of A with size of B + rectA->width = rectB->width; + rectA->height = rectB->height; +} diff --git a/Source/xlib/XftFontInfo.m b/Source/xlib/XftFontInfo.m new file mode 100644 index 0000000..89989a3 --- /dev/null +++ b/Source/xlib/XftFontInfo.m @@ -0,0 +1,486 @@ +/* + XftFontInfo + + NSFont helper for GNUstep GUI X/GPS Backend + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Fred Kiefer + Date: July 2001 + + This file is part of the GNUstep GUI X/GPS Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "config.h" +#include "xlib/XGContext.h" +#include "xlib/XGPrivate.h" +#include "xlib/XGGState.h" +#include "x11/XGServer.h" +#include +#include +#include +// For the encoding functions +#include + +#include "xlib/XftFontInfo.h" + +/* + * class global dictionary of existing fonts + */ +static NSMutableDictionary *_globalFontDictionary = nil; + +@interface XftFontInfo (Private) + +- (BOOL) setupAttributes; +- (XGlyphInfo *)xGlyphInfo: (NSGlyph) glyph; + +@end + +@implementation XftFontInfo + +- initWithFontName: (NSString*)name matrix: (const float *)fmatrix +{ + [super init]; + ASSIGN(fontName, name); + memcpy(matrix, fmatrix, sizeof(matrix)); + + if (![self setupAttributes]) + { + RELEASE(self); + return nil; + } + + return self; +} + +- (void) dealloc +{ + if (font_info != NULL) + XftFontClose([XGServer currentXDisplay], (XftFont *)font_info); + [super dealloc]; +} + +- (float) widthOfString: (NSString*)string +{ + XGlyphInfo extents; + int len = [string length]; + XftChar16 str[len]; + + [string getCharacters: (unichar*)str]; + XftTextExtents16 ([XGServer currentXDisplay], + font_info, + str, + len, + &extents); + + return extents.width; +} + +- (NSMultibyteGlyphPacking)glyphPacking +{ + return NSTwoByteGlyphPacking; +} + +- (NSSize) advancementForGlyph: (NSGlyph)glyph +{ + XGlyphInfo *pc = [self xGlyphInfo: glyph]; + + // if per_char is NULL assume max bounds + if (!pc) + return NSMakeSize((float)(font_info)->max_advance_width, 0); + + return NSMakeSize((float)pc->xOff, (float)pc->yOff); +} + +- (NSRect) boundingRectForGlyph: (NSGlyph)glyph +{ + XGlyphInfo *pc = [self xGlyphInfo: glyph]; + + // if per_char is NULL assume max bounds + if (!pc) + return NSMakeRect(0.0, 0.0, + (float)font_info->max_advance_width, + (float)(font_info->ascent + font_info->descent)); + + return NSMakeRect((float)pc->x, (float)-pc->y, + (float)(pc->width), + (float)(pc->height)); +} + +- (BOOL) glyphIsEncoded: (NSGlyph)glyph +{ + return XftGlyphExists([XGServer currentXDisplay], + (XftFont *)font_info, glyph); +} + +- (NSGlyph) glyphWithName: (NSString*)glyphName +{ + // FIXME: There is a mismatch between PS names and X names, that we should + // try to correct here + KeySym k = XStringToKeysym([glyphName cString]); + + if (k == NoSymbol) + return 0; + else + return (NSGlyph)k; +} + +- (NSPoint) positionOfGlyph: (NSGlyph)curGlyph + precededByGlyph: (NSGlyph)prevGlyph + isNominal: (BOOL*)nominal +{ + if (nominal) + *nominal = YES; + + if (curGlyph == NSControlGlyph || prevGlyph == NSControlGlyph) + return NSZeroPoint; + +// if (curGlyph == NSNullGlyph) + { + NSSize advance = [self advancementForGlyph: prevGlyph]; + return NSMakePoint(advance.width, advance.height); + } +} + +/* +- (float) pointSize +{ + Display *xdpy = [XGServer currentXDisplay]; + + return XGFontPointSize(xdpy, font_info); +} +*/ + +- (void) drawString: (NSString*)string + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp +{ + NSData *d = [string dataUsingEncoding: mostCompatibleStringEncoding + allowLossyConversion: YES]; + int length = [d length]; + const char *cstr = (const char*)[d bytes]; + XftDraw *xftdraw; + XftColor xftcolor; + XColor dummyc; + XGCValues values; + XGGState *state = [(XGContext *)GSCurrentContext() currentGState]; + Region xregion = [state xClipRegion]; + int defaultScreen = DefaultScreen(xdpy); + Colormap colmap = DefaultColormap(xdpy, defaultScreen); + + /* ready to draw */ + xftdraw = XftDrawCreate(xdpy, draw, + DefaultVisual(xdpy, defaultScreen), + colmap); + if(xftdraw == NULL) + return; + + /* sort out the drawing colour */ + XGetGCValues(xdpy, xgcntxt, + GCForeground | GCBackground, + &values); + + dummyc.pixel = values.foreground; + XQueryColor(xdpy, colmap, &dummyc); + xftcolor.color.red = dummyc.red; + xftcolor.color.green = dummyc.green; + xftcolor.color.blue = dummyc.blue; + xftcolor.color.alpha = 0xffff; + xftcolor.pixel = values.foreground; + + // set up clipping + if(xregion != None) + { + XftDrawSetClip(xftdraw, xregion); + XDestroyRegion(xregion); + } + + /* do it */ + XftDrawString16(xftdraw, &xftcolor, font_info, + xp.x, xp.y, (XftChar16*)cstr, length); + + /* tidy up */ + XftDrawDestroy(xftdraw); +} + +- (void) draw: (const char*) s lenght: (int) len + onDisplay: (Display*) xdpy drawable: (Drawable) draw + with: (GC) xgcntxt at: (XPoint) xp +{ + int length = strlen(s); + XftDraw *xftdraw; + XftColor xftcolor; + XColor dummyc; + XGCValues values; + XGGState *state = [(XGContext *)GSCurrentContext() currentGState]; + Region xregion = [state xClipRegion]; + int defaultScreen = DefaultScreen(xdpy); + Colormap colmap = DefaultColormap(xdpy, defaultScreen); + + /* ready to draw */ + xftdraw = XftDrawCreate(xdpy, draw, + DefaultVisual(xdpy, defaultScreen), + colmap); + if(xftdraw == NULL) + return; + + /* sort out the drawing colour */ + XGetGCValues(xdpy, xgcntxt, + GCForeground | GCBackground, + &values); + + dummyc.pixel = values.foreground; + XQueryColor(xdpy, colmap, &dummyc); + xftcolor.color.red = dummyc.red; + xftcolor.color.green = dummyc.green; + xftcolor.color.blue = dummyc.blue; + xftcolor.color.alpha = 0xffff; + xftcolor.pixel = values.foreground; + + // set up clipping + if(xregion != None) + { + XftDrawSetClip(xftdraw, xregion); + XDestroyRegion(xregion); + } + + /* do it */ + if (NSUTF8StringEncoding == mostCompatibleStringEncoding) + { + XftDrawStringUtf8(xftdraw, &xftcolor, font_info, + xp.x, xp.y, (XftChar8 *)s, length); + } + else + { + XftDrawString8(xftdraw, &xftcolor, font_info, + xp.x, xp.y, (XftChar8*)s, length); + } + + /* tidy up */ + XftDrawDestroy(xftdraw); +} + +- (float) widthOf: (const char*) s lenght: (int) len +{ + XGlyphInfo extents; + + if (mostCompatibleStringEncoding == NSUTF8StringEncoding) + XftTextExtentsUtf8([XGServer currentXDisplay], + font_info, + (XftChar8 *)s, + len, + &extents); + else + XftTextExtents8([XGServer currentXDisplay], + font_info, + (XftChar8*)s, + len, + &extents); + + return extents.width; +} + +- (void) setActiveFor: (Display*) xdpy gc: (GC) xgcntxt +{ +} + +@end + +@implementation XftFontInfo (Private) + +- (BOOL) setupAttributes +{ + Display *xdpy = [XGServer currentXDisplay]; + int defaultScreen = DefaultScreen(xdpy); + NSString *weightString; + NSString *reg; + long height; + XftPattern *pattern; + XftResult result; + NSString *xfontname; + + char *xftTypeString; + int xftTypeInt; + NSArray *encoding; + + if (!xdpy) + return NO; + + // Retrieve the XLFD matching the given fontName. DPS->X. + xfontname = XGXFontName(fontName, matrix[0]); + + // Load Xft font and get font info structure. + if ((xfontname == nil) || + (font_info = XftFontOpenXlfd(xdpy, defaultScreen, [xfontname cString])) == NULL) + { + NSLog(@"Selected font: %@ (%@) is not available.\n" + @"Using system default font instead", fontName, xfontname); + + if ((font_info = XftFontOpen(xdpy, defaultScreen, 0)) == NULL) + { + NSLog(@"Unable to open fixed font"); + return NO; + } + } + else + NSDebugLog(@"Loaded font: %@", xfontname); + + // Fill the afmDitionary and ivars + [fontDictionary setObject: fontName forKey: NSAFMFontName]; + + pattern = font_info->pattern; + result = XftPatternGetString(pattern, XFT_FAMILY, 0, &xftTypeString); + if (result != XftResultTypeMismatch) + { + ASSIGN(familyName, + [NSString stringWithCString: (const char*)xftTypeString]); + [fontDictionary setObject: familyName forKey: NSAFMFamilyName]; + } + result = XftPatternGetInteger(pattern, XFT_SPACING, 0, &xftTypeInt); + if (result != XftResultTypeMismatch) + { + isFixedPitch = (weight != 0); + } + + isBaseFont = NO; + ascender = font_info->ascent; + [fontDictionary setObject: [NSNumber numberWithFloat: ascender] + forKey: NSAFMAscender]; + descender = -(font_info->descent); + [fontDictionary setObject: [NSNumber numberWithFloat: descender] + forKey: NSAFMDescender]; + fontBBox = NSMakeRect( + (float)(0), + (float)(0 - font_info->ascent), + (float)(font_info->max_advance_width), + (float)(font_info->ascent + font_info->descent)); + maximumAdvancement = NSMakeSize(font_info->max_advance_width, + (font_info->ascent + font_info->descent)); + minimumAdvancement = NSMakeSize(0,0); + + result = XftPatternGetInteger(pattern, XFT_WEIGHT, 0, &xftTypeInt); + if (result != XftResultTypeMismatch) + { + switch (xftTypeInt) + { + case 0: + weight = 3; + weightString = @"light"; + break; + case 100: + weight = 6; + weightString = @"medium"; + break; + case 180: + weight = 7; + weightString = @"demibold"; + break; + case 200: + weight = 9; + weightString = @"bold"; + break; + case 210: + weight = 12; + weightString = @"black"; + break; + default: + // Don't know + weight = 6;; + } + if (weightString != nil) + { + [fontDictionary setObject: weightString forKey: NSAFMWeight]; + } + } + + if (weight >= 9) + traits |= NSBoldFontMask; + else + traits |= NSUnboldFontMask; + + if (isFixedPitch) + traits |= NSFixedPitchFontMask; + + result = XftPatternGetInteger(pattern, XFT_SLANT, 0, &xftTypeInt); + if (result != XftResultTypeMismatch) + { + if (xftTypeInt != 0) + traits |= NSItalicFontMask; + else + traits |= NSUnitalicFontMask; + } + + XftPatternGetString (pattern, XFT_ENCODING, 0, &xftTypeString); + encodingScheme = [NSString stringWithCString: xftTypeString]; + encoding = [encodingScheme componentsSeparatedByString: @"-"]; + reg = [encoding objectAtIndex: 0]; + if (reg != nil) + { + NSString *enc = [encoding lastObject]; + + if (enc != nil) + { + mostCompatibleStringEncoding = [GSFontInfo encodingForRegistry: reg + encoding: enc]; + if (mostCompatibleStringEncoding == NSUnicodeStringEncoding) + mostCompatibleStringEncoding = NSUTF8StringEncoding; + + encodingScheme = [NSString stringWithFormat: @"%@-%@", + reg, enc]; + //NSLog(@"Found encoding %d for %@", mostCompatibleStringEncoding, encodingScheme); + RETAIN(encodingScheme); + [fontDictionary setObject: encodingScheme + forKey: NSAFMEncodingScheme]; + } + } +/* + height = XGFontPropULong(xdpy, font_info, XA_X_HEIGHT); + if (height != 0) + { + xHeight = (float)height; + [fontDictionary setObject: [NSNumber numberWithFloat: xHeight] + forKey: NSAFMXHeight]; + } + + height = XGFontPropULong(xdpy, font_info, XA_CAP_HEIGHT); + if (height != 0) + { + capHeight = (float)height; + [fontDictionary setObject: [NSNumber numberWithFloat: capHeight] + forKey: NSAFMCapHeight]; + } +*/ + // FIXME: italicAngle, underlinePosition, underlineThickness are not set. + // Should use XA_ITALIC_ANGLE, XA_UNDERLINE_POSITION, XA_UNDERLINE_THICKNESS + return YES; +} + +- (XGlyphInfo *)xGlyphInfo: (NSGlyph) glyph +{ + static XGlyphInfo glyphInfo; + + XftTextExtents32 ([XGServer currentXDisplay], + (XftFont *)font_info, + &glyph, + 1, + &glyphInfo); + + return &glyphInfo; +} + +@end diff --git a/Source/xlib/linking.m b/Source/xlib/linking.m new file mode 100644 index 0000000..f92a056 --- /dev/null +++ b/Source/xlib/linking.m @@ -0,0 +1,15 @@ + +#include "xlib/XGContext.h" + +//extern void __objc_xgps_gsbackend_linking (void); + +extern void __objc_xgcontextwindow_linking (void); +extern void __objc_xgcontextevent_linking (void); + + +void __objc_xgps_linking(void) +{ + //__objc_xgps_gsbackend_linking(); + __objc_xgcontextwindow_linking(); + __objc_xgcontextevent_linking(); +} diff --git a/Source/xlib/xrtools.c b/Source/xlib/xrtools.c new file mode 100644 index 0000000..7744c81 --- /dev/null +++ b/Source/xlib/xrtools.c @@ -0,0 +1,262 @@ +/* xrtools - Color conversion routines and other low-level X support + + Copyright (C) 1998 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Oct 1998 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include "xlib/xrtools.h" + +/* Internal conversion of colors to pixels values */ +u_long +xrGrayToPixel(RContext* context, float gray) +{ + XColor cc; + RColor rcolor; + rcolor.red = 255. * gray; + rcolor.green = 255. * gray; + rcolor.blue = 255. * gray; + rcolor.alpha = 0; + RGetClosestXColor(context, &rcolor, &cc); + return cc.pixel; +} + +u_long +xrRGBToPixel(RContext* context, float red, float green, float blue) +{ + XColor cc; + RColor rcolor; + rcolor.red = 255. * red; + rcolor.green = 255. * green; + rcolor.blue = 255. * blue; + rcolor.alpha = 0; + RGetClosestXColor(context, &rcolor, &cc); + return cc.pixel; +} + +u_long +xrHSBToPixel(RContext* context, float h, float s, float v) +{ + int i; + float f, p, q, t; + float red, green, blue; + + if (s == 0) + return xrRGBToPixel(context, v, v, v); + + h = h * 6; + i = (int)h; + f = h - i; + p = v * (1.0 - s); + q = v * (1.0 - s * f); + t = v * (1.0 - s * (1 - f)); + + switch (i) + { + case 0: + red = v; + green = t; + blue = p; + break; + case 1: + red = q; + green = v; + blue = p; + break; + case 2: + red = p; + green = v; + blue = t; + break; + case 3: + red = p; + green = q; + blue = v; + break; + case 4: + red = t; + green = p; + blue = v; + break; + case 5: + red = v; + green = p; + blue = q; + break; + } + return xrRGBToPixel(context, red, green, blue); +} + +/* Not implemented. FIXME */ +u_long +xrCMYKToPixel(RContext* context, float c, float m, float y, float k) +{ + float red, green, blue; + double white = 1 - k; + + if (k == 0) + { + red = 1 - c; + green = 1 - m; + blue = 1 - y; + } + else if (k == 1) + { + red = 0; + green = 0; + blue = 0; + } + else + { + red = (c > white ? 0 : white - c); + green = (m > white ? 0 : white - m); + blue = (y > white ? 0 : white - y); + } + return xrRGBToPixel(context, red, green, blue); +} + +u_long +xrColorToPixel(RContext* context, xr_device_color_t color) +{ + u_long pix; + switch(color.space) + { + case gray_colorspace: + pix = xrGrayToPixel(context, color.field[0]); + break; + case rgb_colorspace: + pix = xrRGBToPixel(context, color.field[0], + color.field[1], color.field[2]); + break; + case hsb_colorspace: + pix = xrHSBToPixel(context, color.field[0], + color.field[1], color.field[2]); + break; + case cmyk_colorspace: + pix = xrCMYKToPixel(context, color.field[0], color.field[1], + color.field[2], color.field[3]); + break; + default: + break; + } + return pix; +} + +xr_device_color_t +xrConvertToGray(xr_device_color_t color) +{ + xr_device_color_t new; + + new.space = gray_colorspace; + switch(color.space) + { + case gray_colorspace: + new = color; + break; + case hsb_colorspace: + case cmyk_colorspace: + color = xrConvertToRGB(color); + /* NO BREAK */ + case rgb_colorspace: + new.field[0] = + ((0.3*color.field[0]) + (0.59*color.field[1]) + (0.11*color.field[2])); + break; + default: + break; + } + return new; +} + +xr_device_color_t +xrConvertToRGB(xr_device_color_t color) +{ + xr_device_color_t new; + + new.space = rgb_colorspace; + switch(color.space) + { + case gray_colorspace: + new.field[0] = color.field[0]; + new.field[1] = color.field[0]; + new.field[2] = color.field[0]; + break; + case rgb_colorspace: + new = color; + break; + case hsb_colorspace: + case cmyk_colorspace: + break; + default: + break; + } + return new; +} + +xr_device_color_t +xrConvertToHSB(xr_device_color_t color) +{ + xr_device_color_t new; + + new.space = hsb_colorspace; + switch(color.space) + { + case gray_colorspace: + break; + case rgb_colorspace: + break; + case hsb_colorspace: + new = color; + break; + case cmyk_colorspace: + break; + default: + break; + } + return new; +} + +xr_device_color_t +xrConvertToCMYK(xr_device_color_t color) +{ + xr_device_color_t new; + + new.space = gray_colorspace; + switch(color.space) + { + case gray_colorspace: + break; + case rgb_colorspace: + break; + case hsb_colorspace: + break; + case cmyk_colorspace: + new = color; + break; + default: + break; + } + return new; +} diff --git a/Tools/.cvsignore b/Tools/.cvsignore new file mode 100644 index 0000000..994437e --- /dev/null +++ b/Tools/.cvsignore @@ -0,0 +1,5 @@ +shared_debug_obj +shared_obj +xdnd.c +xdnd.h +XGCommonFont.m diff --git a/Tools/GNUmakefile b/Tools/GNUmakefile new file mode 100644 index 0000000..2364d72 --- /dev/null +++ b/Tools/GNUmakefile @@ -0,0 +1,57 @@ +# +# Tools level makefile for GNUstep Backend Library +# +# Copyright (C) 1997,1999 Free Software Foundation, Inc. +# +# Author: Scott Christley +# +# This file is part of the GNUstep GUI Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../back.make +include $(GNUSTEP_MAKEFILES)/common.make + +include ../Version +include ../config.make + +# The applications to be compiled +TOOL_NAME = gpbs + +# The source files to be compiled +gpbs_OBJC_FILES = gpbs.m +font_cacher_OBJC_FILES = font_cacher.m + +ifneq ($(BUILD_X11),) +TOOL_NAME += font_cacher +gpbs_OBJC_FILES += xpbs.m +ifeq ($(BACKEND_BUNDLE),yes) +font_cacher_OBJC_FILES += XGCommonFont.m +gpbs_C_FILES += xdnd.c +endif +endif + +-include GNUmakefile.preamble + +-include GNUmakefile.local + +include $(GNUSTEP_MAKEFILES)/tool.make + +-include GNUmakefile.postamble diff --git a/Tools/GNUmakefile.postamble b/Tools/GNUmakefile.postamble new file mode 100644 index 0000000..f45d7d8 --- /dev/null +++ b/Tools/GNUmakefile.postamble @@ -0,0 +1,51 @@ +# +# Makefile.postamble +# +# Project specific makefile rules +# +# Uncomment the targets you want. +# The double colons (::) are important, do not make them single colons +# otherwise the normal makefile rules will not be performed. +# + +# Things to do before compiling +before-all:: + -$(RM) XGCommonFont.m + $(LN_S) ../Source/xlib/XGCommonFont.m . + -$(RM) xdnd.c + $(LN_S) ../Source/x11/xdnd.c . + +# Things to do after compiling +# after-all:: + +# Things to do before installing +# before-install:: + +# Things to do after installing +# after-install:: + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +# after-uninstall:: + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +after-clean:: + -$(RM) XGCommonFont.m + -$(RM) xdnd.c + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +# after-distclean:: + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check:: diff --git a/Tools/GNUmakefile.preamble b/Tools/GNUmakefile.preamble new file mode 100644 index 0000000..2867e39 --- /dev/null +++ b/Tools/GNUmakefile.preamble @@ -0,0 +1,50 @@ +# +# Makefile.preamble +# +# Project specific makefile variables, and additional +# +# Do not put any Makefile rules in this file, instead they should +# be put into Makefile.postamble. +# + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +#ADDITIONAL_CPPFLAGS += + +# Additional flags to pass to the Objective-C compiler +#ADDITIONAL_OBJCFLAGS += + +# Additional flags to pass to the C compiler +#ADDITIONAL_CFLAGS += + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS += -I../Headers -I../Source/$(GNUSTEP_TARGET_DIR) + + +# Additional LDFLAGS to pass to the linker +# ADDITIONAL_LDFLAGS += + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS += -L../Source/$(GNUSTEP_OBJ_DIR) + +# Additional libraries when linking applications +#ADDITIONAL_GUI_LIBS += + +# +# Flags dealing with installing and uninstalling +# + +# Additional directories to be created during installation +ADDITIONAL_INSTALL_DIRS += + +# Flags for when the backend is compiled as a bundle +ifneq ($(BACKEND_BUNDLE),) +ADDITIONAL_TOOL_LIBS += $(GUI_LIBS) $(GRAPHIC_LIBS) $(SYSTEM_LIBS) +ADDITIONAL_INCLUDE_DIRS += $(GRAPHIC_CFLAGS) +ADDITIONAL_LIB_DIRS += $(GRAPHIC_LFLAGS) +else +ADDITIONAL_TOOL_LIBS += -lgnustep-gui -lgnustep-back $(SYSTEM_LIBS) +endif diff --git a/Tools/font_cacher.m b/Tools/font_cacher.m new file mode 100644 index 0000000..10f2607 --- /dev/null +++ b/Tools/font_cacher.m @@ -0,0 +1,553 @@ +/* + Font cacher for GNUstep GUI X/GPS Backend + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Fred Kiefer and Richard Frith-Macdonald + Date: Febuary 2000 + + This file is part of the GNUstep GUI X/GPS Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include +#include +#include +#include +#include +#include + +#define stringify_it(X) #X +#define makever(X) stringify_it(X) + +@interface XFontCacher : NSObject +{ + NSMutableSet *allFontNames; + NSMutableDictionary *allFontFamilies; + NSMutableDictionary *creationDictionary; + NSMutableDictionary *xFontDictionary; + NSMutableSet *knownFonts; + Display *dpy; +} + +- (NSString*) faceNameFromParts: (NSArray*) parts; +- (NSString*) creationNameFromParts: (NSArray*) parts; +- (NSString*) getPathFor: (NSString*) display; +- (BOOL) fontLoop; +- (BOOL) processPattern: (const char *) pattern; +- (void) processFont: (char*) name; +- (void) sortResults; +- (void) writeCacheTo: (NSString*)path; +@end + +@implementation XFontCacher + +- (id) init +{ + allFontNames = RETAIN([NSMutableSet setWithCapacity: 1000]); + allFontFamilies = RETAIN([NSMutableDictionary dictionaryWithCapacity: 1000]); + creationDictionary = RETAIN([NSMutableDictionary dictionaryWithCapacity: 1000]); + xFontDictionary = RETAIN([NSMutableDictionary dictionaryWithCapacity: 1000]); + knownFonts = RETAIN([NSMutableSet setWithCapacity: 1000]); + + return self; +} + +- (void) dealloc +{ + RELEASE(allFontNames); + RELEASE(allFontFamilies); + RELEASE(creationDictionary); + RELEASE(xFontDictionary); + RELEASE(knownFonts); + + if (dpy) + XCloseDisplay(dpy); + + [super dealloc]; +} + +/* + * Find a suitable type face name for a full X font name, which + * has already been split into parts seperated by - + * -sony-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1 + * becomes Normal + */ +- (NSString*) faceNameFromParts: (NSArray*) parts +{ + NSString *faceName; + NSString *face = [[parts objectAtIndex: 3] capitalizedString]; + NSString *slant = [[parts objectAtIndex: 4] capitalizedString]; + NSString *weight = [[parts objectAtIndex: 5] capitalizedString]; + NSString *add = [[parts objectAtIndex: 6] capitalizedString]; + + if ([face length] == 0 || [face isEqualToString: @"Medium"]) + faceName = @""; + else + faceName = face; + + if ([slant isEqualToString: @"I"]) + faceName = [NSString stringWithFormat: @"%@%@", faceName, @"Italic"]; + else if ([slant isEqualToString: @"O"]) + faceName = [NSString stringWithFormat: @"%@%@", faceName, @"Oblique"]; + + if ([weight length] != 0 && ![weight isEqualToString: @"Normal"]) + { + if ([faceName length] != 0) + faceName = [NSString stringWithFormat: @"%@-%@", faceName, weight]; + else + faceName = weight; + } + + if ([add length] != 0) + { + if ([faceName length] != 0) + faceName = [NSString stringWithFormat: @"%@-%@", faceName, add]; + else + faceName = add; + } + + if ([faceName length] == 0) + faceName = @"Normal"; + + return faceName; +} + +/* + * Build up an X font creation string + * -sony-fixed-medium-r-normal--16-150-75-75-c-80-iso8859-1 + * becomes + * -*-fixed-medium-r-normal--%d-*-*-*-c-*-iso8859-1 +*/ +- (NSString*) creationNameFromParts: (NSArray*) parts +{ + NSString *creationName; + + creationName = [NSString stringWithFormat: + @"-%@-%@-%@-%@-%@-%@-%@-%@-%@-%@-%@-%@-%@-%@", + @"*", + [parts objectAtIndex: 2], + [parts objectAtIndex: 3], + [parts objectAtIndex: 4], + [parts objectAtIndex: 5], + [parts objectAtIndex: 6], + @"%d",//[parts objectAtIndex: 7], + @"*", // place holder for integer size (points *10) + @"*",//[parts objectAtIndex: 9], + @"*",//[parts objectAtIndex: 10], + [parts objectAtIndex: 11], + @"*",//[parts objectAtIndex: 12], + [parts objectAtIndex: 13], + [parts objectAtIndex: 14]]; + + return creationName; +} + +- (NSString*) getPathFor: (NSString*) display +{ + NSArray *paths; + NSFileManager *mgr; + NSString *path; + const char *display_name; + BOOL flag; + + if (display != nil) + display_name = [display cString]; + else + { + display = [NSString stringWithCString: XDisplayName(0)]; + display_name = NULL; + } + + dpy = XOpenDisplay(display_name); + if (dpy == 0) + { + NSLog(@"Unable to open X display - no font information available"); + return nil; + } + + paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, + NSUserDomainMask, YES); + if ((paths != nil) && ([paths count] > 0)) + { + path = [paths objectAtIndex: 0]; + } + else + { + NSLog(@" No valid path for cached information exists. You "); + NSLog(@" should create ~/GNUstep/Library by hand"); + return nil; + } + + mgr = [NSFileManager defaultManager]; + if ([mgr fileExistsAtPath: path isDirectory: &flag] == NO || flag == NO) + { + NSLog(@"Library directory '%@' not available!", path); + return nil; + } + path = [path stringByAppendingPathComponent: @"Fonts"]; + if ([mgr fileExistsAtPath: path] == NO) + { + [mgr createDirectoryAtPath: path attributes: nil]; + } + if ([mgr fileExistsAtPath: path isDirectory: &flag] == NO || flag == NO) + { + NSLog(@"Fonts directory '%@' not available!", path); + return nil; + } + path = [path stringByAppendingPathComponent: @"Cache"]; + if ([mgr fileExistsAtPath: path] == NO) + { + [mgr createDirectoryAtPath: path attributes: nil]; + } + if ([mgr fileExistsAtPath: path isDirectory: &flag] == NO || flag == NO) + { + NSLog(@"Fonts directory '%@' not available!", path); + return nil; + } + + return [path stringByAppendingPathComponent: display]; +} + +- (BOOL) fontLoop +{ + NSUserDefaults *defs; + const char *pattern = "*"; + BOOL result; + + defs = [NSUserDefaults standardUserDefaults]; + if (defs == nil) + NSLog(@"Unable to access defaults database!"); + else + { + NSString *font_mask; + + font_mask = [defs stringForKey: @"GSFontMask"]; + if ((font_mask != nil) && [font_mask length]) + // only fonts matching the supplied mask will be cached + pattern = [font_mask lossyCString]; + } + + // In a next step we allow multiple font masks + result = [self processPattern: pattern]; + + // No longer needed + DESTROY(knownFonts); + + return result; +} + +- (BOOL) processPattern: (const char *) pattern +{ + NSAutoreleasePool *loopPool; + int nnames = 10000; + int available = nnames+1; + int i; + char **fonts; + + /* Get list of all fonts */ + for (;;) + { + fonts = XListFonts(dpy, pattern, nnames, &available); + if (fonts == NULL || available < nnames) + break; + /* There are more fonts then we expected, so just start + again and request more */ + XFreeFontNames(fonts); + nnames = available * 2; + } + + if (fonts == NULL) + { + NSLog(@"No X fonts found for pattern %s", pattern); + return NO; + } + + NSDebugFLog(@"Fonts loaded, now the loop. Available: %d", available); + + loopPool = [NSAutoreleasePool new]; + + for (i = 0; i < available; i++) + { + char *name = fonts[i]; + + NS_DURING + [self processFont: name]; + NS_HANDLER + NSLog(@"Problem during processing of font %s", name); + NS_ENDHANDLER + + if (i && i % 500 == 0) + { + NSDebugLog(@"Finished %d", i); + RELEASE (loopPool); + loopPool = [NSAutoreleasePool new]; + } + } + RELEASE (loopPool); + XFreeFontNames(fonts); + NSDebugLog(@"Finished loop"); + + return YES; +} + +- (void) processFont: (char*) name +{ + NSString *alias = [[NSString stringWithCString: name] lowercaseString]; + NSString *fontName; + + /* + * First time we find this font. A font may be found more than + * once, when the XFontPath has the same directory twice. + * Somehow this is the case on my machine. + */ + if ([xFontDictionary objectForKey: alias] == nil) + { + XFontStruct *info = XLoadQueryFont(dpy, name); + NSString *family; + NSString *baseName; + NSString *face; + NSString *creationName; + NSArray *parts; + + if (info == 0) + { + NSDebugLog(@"No information for font %s", name); + return; + } + + fontName = XGFontName(dpy, info); + if (fontName == nil) + { + NSDebugLog(@"No font Name in info for font %s", name); + XFreeFont(dpy, info); + return; + } + + if ([alias isEqualToString: fontName] == NO) + { + // We have got an alias name, store it + [xFontDictionary setObject: fontName forKey: alias]; + } + + // Use the normal function to keep the names consistent + family = XGFontFamily(dpy, info); + + parts = [fontName componentsSeparatedByString: @"-"]; + if ([parts count] == 15) + { + face = [self faceNameFromParts: parts]; + if ([face length] == 0 || [face isEqualToString: @"Normal"]) + { + baseName = family; + } + else + baseName = [NSString stringWithFormat: @"%@-%@", family, face]; + + creationName = [self creationNameFromParts: parts]; + } + else + { + baseName = [fontName capitalizedString]; + face = @"Normal"; + creationName = fontName; + } + + // Store the alias to baseName + [xFontDictionary setObject: baseName forKey: fontName]; + // it might already have been found with another size + if ([knownFonts member: baseName] == nil) + { + int weight; + NSFontTraitMask traits; + NSMutableArray *fontDefs; + NSMutableArray *fontDef; + + // the first time we find that base font. + + // Store the font name + [knownFonts addObject: baseName]; + [allFontNames addObject: baseName]; + [creationDictionary setObject: creationName forKey: baseName]; + + weight = XGWeightOfFont(dpy, info); + traits = XGTraitsOfFont(dpy, info); + + // Store the family name and information + fontDefs = [allFontFamilies objectForKey: family]; + if (fontDefs == nil) + { + fontDefs = [NSMutableArray array]; + [allFontFamilies setObject: fontDefs forKey: family]; + } + // Fill the structure for the font + fontDef = [NSMutableArray arrayWithCapacity: 4]; + [fontDef addObject: baseName]; + [fontDef addObject: face]; + [fontDef addObject: [NSNumber numberWithInt: weight]]; + [fontDef addObject: [NSNumber numberWithUnsignedInt: traits]]; + // Add to the family information + [fontDefs addObject: fontDef]; + } + // Release the font + XFreeFont(dpy, info); + } +} + +static int fontDefSorter(NSArray *el1, NSArray *el2, void *context) +{ + // This is not exactly the order the OpenStep specification states. + NSFontTraitMask t1 = [[el1 objectAtIndex: 3] unsignedIntValue]; + NSFontTraitMask t2 = [[el2 objectAtIndex: 3] unsignedIntValue]; + int w1 = [[el1 objectAtIndex: 2] intValue]; + int w2 = [[el2 objectAtIndex: 2] intValue]; + + if (t1 < t2) + return NSOrderedAscending; + else if (t2 < t1) + return NSOrderedDescending; + else if (w1 < w2) + return NSOrderedAscending; + else if(w2 < w1) + return NSOrderedDescending; + + return NSOrderedSame; +} + +- (void) sortResults +{ + NSEnumerator *enumerator; + id key; + + // Now sort the fonts of each family + enumerator = [allFontFamilies keyEnumerator]; + while ((key = [enumerator nextObject])) + { + NSMutableArray *fontDefs = [allFontFamilies objectForKey: key]; + + [fontDefs sortUsingFunction: fontDefSorter context: nil]; + } + + + // define a creation string for alias names + enumerator = [xFontDictionary keyEnumerator]; + while ((key = [enumerator nextObject])) + { + id name = key; + id creationName; + + while ((name != nil) + && (creationName = [creationDictionary objectForKey: name]) == nil) + { + name = [xFontDictionary objectForKey: name]; + } + + if (creationName != nil) + { + [creationDictionary setObject: creationName forKey: key]; + } + } + // No longer needed + DESTROY(xFontDictionary); +} + +- (void) writeCacheTo: (NSString*)path +{ + NSData *data; + NSMutableDictionary *cache = [NSMutableDictionary dictionaryWithCapacity: 4]; + + [cache setObject: [NSNumber numberWithInt: 2] forKey: @"Version"]; + [cache setObject: allFontNames forKey: @"AllFontNames"]; + [cache setObject: allFontFamilies forKey: @"AllFontFamilies"]; + [cache setObject: creationDictionary forKey: @"CreationDictionary"]; + data = [NSArchiver archivedDataWithRootObject: cache]; + [data writeToFile: path atomically: YES]; +} + +int +main(int argc, char **argv, char **env) +{ + NSArray *args; + NSArray *paths; + NSString *path; + NSString *file_name; + XFontCacher *cacher; + CREATE_AUTORELEASE_POOL(pool); + +#ifdef GS_PASS_ARGUMENTS + [NSProcessInfo initializeWithArguments: argv count: argc environment: env]; +#endif + + args = [[NSProcessInfo processInfo] arguments]; + if ([args containsObject: @"--help"]) + { + paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, + NSUserDomainMask, YES); + if ((paths != nil) && ([paths count] > 0)) + path = [paths objectAtIndex: 0]; + else + path = nil; + + NSLog(@"This tool caches system font information\n"); + if (path != nil) + NSLog(@" Information is cached in %@/Fonts/Cache/", path); + else + { + NSLog(@" No valid path for cached information exists. You "); + NSLog(@" should create ~/GNUstep/Library by hand"); + } + RELEASE(pool); + return 0; + } + if ([args containsObject: @"--version"]) + { + NSLog(@"%@ version %s", [[args objectAtIndex: 0] lastPathComponent], + makever(GNUSTEP_VERSION)); + RELEASE(pool); + return 0; + } + + if ([args count] > 1) + file_name = [args objectAtIndex: 1]; + else + file_name = nil; + + cacher = [[XFontCacher alloc] init]; + path = [cacher getPathFor: file_name]; + if (path == nil) + { + RELEASE(pool); + return 1; + } + + if (![cacher fontLoop]) + { + RELEASE(pool); + return 2; + } + + [cacher sortResults]; + NS_DURING + [cacher writeCacheTo: path]; + NS_HANDLER + NSLog(@"Problem during writing of font cache"); + NS_ENDHANDLER + + RELEASE(cacher); + RELEASE(pool); + return 0; +} + diff --git a/Tools/gpbs.m b/Tools/gpbs.m new file mode 100644 index 0000000..493b8c0 --- /dev/null +++ b/Tools/gpbs.m @@ -0,0 +1,1178 @@ +/* + gpbs.m + + GNUstep pasteboard server + + Copyright (C) 1997,1999 Free Software Foundation, Inc. + + Author: Richard Frith-Macdonald + Date: August 1997 + + This file is part of the GNUstep Project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + You should have received a copy of the GNU General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include +#include + +#include +#include + +@class PasteboardServer; +@class PasteboardObject; + +@protocol XPb ++ (id) ownerByOsPb: (NSString*)p; +@end +static Class xPbClass; + +int debug = 0; +int verbose = 0; + +#define MAXHIST 100 + +PasteboardServer *server = nil; +NSConnection *conn = nil; +NSLock *dictionary_lock = nil; +NSMutableDictionary *pasteboards = nil; + +@interface NSPasteboard (GNULocal) ++ (void) _localServer: (id)s; +@end + +@interface PasteboardData: NSObject +{ + NSData *data; + NSString *type; + id owner; + id pboard; + BOOL wantsChangedOwner; + BOOL hasGNUDataForType; + BOOL hasStdDataForType; +} ++ (PasteboardData*) newWithType: (NSString*)aType + owner: (id)anObject + pboard: (id)anotherObject + wantsChangedOwner: (BOOL)wants + hasStdDataForType: (BOOL)StdData + hasGNUDataForType: (BOOL)GNUData; +- (BOOL) checkConnection: (NSConnection*)c; +- (NSData*) data; +- (NSData*) newDataWithVersion: (int)version; +- (id) owner; +- (id) pboard; +- (void) setData: (NSData*)d; +- (NSString*) type; +- (BOOL) wantsChangedOwner; +@end + +@implementation PasteboardData + ++ (PasteboardData*) newWithType: (NSString*)aType + owner: (id)anObject + pboard: (id)anotherObject + wantsChangedOwner: (BOOL)wants + hasStdDataForType: (BOOL)StdData + hasGNUDataForType: (BOOL)GNUData; +{ + PasteboardData* d = [PasteboardData alloc]; + + if (d) + { + d->type = RETAIN(aType); + d->owner = RETAIN(anObject); + d->pboard = RETAIN(anotherObject); + d->wantsChangedOwner = wants; + d->hasStdDataForType = StdData; + d->hasGNUDataForType = GNUData; + } + return d; +} + +- (BOOL) checkConnection: (NSConnection*)c +{ + BOOL ourConnection = NO; + id o; + + if (owner && [owner isProxy] && [owner connectionForProxy] == c) + { + o = owner; + owner = nil; + RELEASE(o); + o = pboard; + pboard = nil; + RELEASE(o); + ourConnection = YES; + } + if (pboard && [pboard isProxy] && [pboard connectionForProxy] == c) + { + o = owner; + owner = nil; + RELEASE(o); + o = pboard; + pboard = nil; + RELEASE(o); + ourConnection = YES; + } + return ourConnection; +} + +- (void) dealloc +{ + RELEASE(type); + RELEASE(data); + RELEASE(owner); + RELEASE(pboard); + [super dealloc]; +} + +- (NSString*) description +{ + return [NSString stringWithFormat: @"PasteboardData for type '%@'", type]; +} + +- (NSData*) data +{ + if (verbose) + { + NSLog(@"get data for %x\n", (unsigned)self); + } + return data; +} + +- (NSData*) newDataWithVersion: (int)version +{ + /* + * If the owner of this item is an X window - we can't use the data from + * the last time the selection was accessed because the X window may have + * changed it's selection without telling us - isn't X wonderful :-( + */ + if (data != nil && owner != nil + && [owner isProxy] == NO && [owner isKindOfClass: xPbClass] == YES) + { + DESTROY(data); + } + + if (data == nil && (owner && pboard)) + { + if (hasGNUDataForType) + { + [owner pasteboard: pboard + provideDataForType: type + andVersion: version]; + } + else if (hasStdDataForType) + { + [owner pasteboard: pboard + provideDataForType: type]; + } + } + return [self data]; +} + +- (id) owner +{ + return owner; +} + +- (id) pboard +{ + return pboard; +} + +- (void) setData: (NSData*)d +{ + if (verbose) + { + NSLog(@"set data for %x\n", (unsigned)self); + } + ASSIGN(data, d); +} + +- (id) type +{ + return type; +} + +- (BOOL) wantsChangedOwner +{ + return wantsChangedOwner; +} + +@end + + + +@interface PasteboardEntry: NSObject +{ + int refNum; + id owner; + id pboard; + NSMutableArray *items; + BOOL hasBeenFiltered; + BOOL wantsChangedOwner; + BOOL hasGNUDataForType; + BOOL hasStdDataForType; +} ++ (PasteboardEntry*) newWithTypes: (NSArray*)someTypes + owner: (id)anOwner + pboard: (id)aPboard + ref: (int)count; +- (void) addTypes: (NSArray*)types owner: (id)owner pasteboard: (id)pb; +- (BOOL) checkConnection: (NSConnection*)c; +- (BOOL) hasBeenFiltered; +- (PasteboardData*) itemForType: (NSString*)type; +- (void) lostOwnership; +- (id) owner; +- (int) refNum; +- (NSArray*) types; +@end + +@implementation PasteboardEntry + ++ (PasteboardEntry*) newWithTypes: (NSArray*)someTypes + owner: (id)anOwner + pboard: (id)aPboard + ref: (int)count +{ + PasteboardEntry* e = [PasteboardEntry alloc]; + + if (e) + { + int i; + + e->owner = RETAIN(anOwner); + e->pboard = RETAIN(aPboard); + + if (anOwner && [anOwner respondsToSelector: + @selector(pasteboardChangedOwner:)]) + { + e->wantsChangedOwner = YES; + } + if (anOwner && [anOwner respondsToSelector: + @selector(pasteboard:provideDataForType:)]) + { + e->hasStdDataForType = YES; + } + if (anOwner && [anOwner respondsToSelector: + @selector(pasteboard:provideDataForType:andVersion:)]) + { + e->hasGNUDataForType = YES; + } + + e->items = [[NSMutableArray alloc] initWithCapacity: [someTypes count]]; + for (i = 0; i < [someTypes count]; i++) + { + NSString *type = [someTypes objectAtIndex: i]; + PasteboardData *d; + + d = [PasteboardData newWithType: type + owner: anOwner + pboard: aPboard + wantsChangedOwner: e->wantsChangedOwner + hasStdDataForType: e->hasStdDataForType + hasGNUDataForType: e->hasGNUDataForType]; + [e->items addObject: d]; + RELEASE(d); + } + e->refNum = count; + if (verbose > 1) + { + NSLog(@"New PasteboardEntry %d with items - %@", count, e->items); + } + } + return e; +} + +- (void) addTypes: newTypes owner: newOwner pasteboard: pb +{ + int i; + BOOL wants = NO; + BOOL StdData = NO; + BOOL GNUData = NO; + + if (newOwner && [newOwner respondsToSelector: + @selector(pasteboardChangedOwner:)]) + { + wants = YES; + } + if (newOwner && [newOwner respondsToSelector: + @selector(pasteboard:provideDataForType:)]) + { + StdData = YES; + } + if (newOwner && [newOwner respondsToSelector: + @selector(pasteboard:provideDataForType:andVersion:)]) + { + GNUData = YES; + } + + for (i = 0; i < [newTypes count]; i++) + { + NSString *type = (NSString*)[newTypes objectAtIndex: i]; + + if ([self itemForType: type] == nil) + { + PasteboardData* d; + + d = [PasteboardData newWithType: type + owner: newOwner + pboard: pb + wantsChangedOwner: wants + hasStdDataForType: StdData + hasGNUDataForType: GNUData]; + [items addObject: d]; + RELEASE(d); + } + } + if (verbose > 1) + { + NSLog(@"Modified PasteboardEntry %d with items - %@", refNum, items); + } +} + +- (BOOL) checkConnection: (NSConnection*)c +{ + BOOL ourConnection = NO; + unsigned i; + id o; + + if (owner && [owner isProxy] && [owner connectionForProxy] == c) + { + o = owner; + owner = nil; + RELEASE(o); + o = pboard; + pboard = nil; + RELEASE(o); + ourConnection = YES; + } + + if (pboard && [pboard isProxy] && [pboard connectionForProxy] == c) + { + o = owner; + owner = nil; + RELEASE(o); + o = pboard; + pboard = nil; + RELEASE(o); + ourConnection = YES; + } + + for (i = [items count]; i > 0; i--) + { + PasteboardData *d = [items objectAtIndex: i-1]; + + if ([d checkConnection: c] == YES && [d data] == nil && [d owner] == nil) + { + if (verbose > 1) + { + NSLog(@"Removing item from PasteboardEntry %d\n", refNum); + } + [items removeObjectAtIndex: i-1]; + } + } + return ourConnection; +} + +- (void) dealloc +{ + RELEASE(owner); + RELEASE(pboard); + RELEASE(items); + [super dealloc]; +} + +- (BOOL) hasBeenFiltered +{ + return hasBeenFiltered; +} + +- (PasteboardData*) itemForType: (NSString*)type +{ + unsigned i, count; + + count = [items count]; + for (i = 0; i < count; i++) + { + PasteboardData *d = [items objectAtIndex: i]; + + if ([[d type] isEqual: type]) + { + return d; + } + } + return nil; +} + +- (void) lostOwnership +{ + NSMutableArray *a = [NSMutableArray arrayWithCapacity: 4]; + unsigned i; + + NS_DURING + { + if (wantsChangedOwner == YES && owner != nil) + { + [a addObject: owner]; + } + + for (i = 0; i < [items count]; i++) + { + PasteboardData *d = [items objectAtIndex: i]; + + if ([d wantsChangedOwner] == YES && [d owner] != nil + && [a indexOfObjectIdenticalTo: [d owner]] == NSNotFound) + { + [a addObject: [d owner]]; + } + } + + if (wantsChangedOwner == YES) + { + [owner pasteboardChangedOwner: pboard]; + if (owner != nil) + { + [a removeObjectIdenticalTo: owner]; + } + } + + for (i = 0; i < [items count] && [a count] > 0; i++) + { + PasteboardData *d = [items objectAtIndex: i]; + id o = [d owner]; + + if (o != nil && [a containsObject: o]) + { + [o pasteboardChangedOwner: [d pboard]]; + [a removeObjectIdenticalTo: o]; + } + } + } + NS_HANDLER + { + NSLog(@"Error informing objects of ownership change - %@\n", + [localException reason]); + } + NS_ENDHANDLER +} + +- (id) owner +{ + return owner; +} + +- (int) refNum +{ + return refNum; +} + +- (NSArray*) types +{ + NSMutableArray* t = [NSMutableArray arrayWithCapacity: [items count]]; + unsigned int i; + + for (i = 0; i < [items count]; i++) + { + PasteboardData* d = [items objectAtIndex: i]; + [t addObject: [d type]]; + } + return t; +} + +@end + + + +@interface PasteboardObject: NSObject +{ + NSString *name; + int nextCount; + unsigned histLength; + NSMutableArray *history; + PasteboardEntry *current; +} + ++ (PasteboardObject*) pasteboardWithName: (NSString*)name; + +- (int) addTypes: (NSArray*)types + owner: (id)owner + pasteboard: (id)pboard + oldCount: (int)count; +- (NSString*) availableTypeFromArray: (NSArray*)types + changeCount: (int*)count; +- (int) changeCount; +- (BOOL) checkConnection: (NSConnection*)c; +- (NSData*) dataForType: (NSString*)type + oldCount: (int)count + mustBeCurrent: (BOOL)flag; +- (int) declareTypes: (NSArray*)types + owner: (id)owner + pasteboard: (id)pboard; +- (PasteboardEntry*) entryByCount: (int)count; +- (NSString*) name; +- (void) releaseGlobally; +- (BOOL) setData: (NSData*)data + forType: (NSString*)type + isFile: (BOOL)flag + oldCount: (int)count; +- (void) setHistory: (unsigned)length; +- (NSArray*) typesAndChangeCount: (int*)count; + +@end + +@implementation PasteboardObject + ++ (void) initialize +{ + pasteboards = [[NSMutableDictionary alloc] initWithCapacity: 8]; + dictionary_lock = [[NSLock alloc] init]; +} + ++ (PasteboardObject*) pasteboardWithName: (NSString*)aName +{ + static int number = 0; + PasteboardObject* pb; + + [dictionary_lock lock]; + while (aName == nil) + { + aName = [NSString stringWithFormat: @"%dlocalName", number++]; + if ([pasteboards objectForKey: aName] == nil) + { + break; // This name is unique. + } + else + { + aName = nil; // Name already in use - try another. + } + } + + pb = [pasteboards objectForKey: aName]; + if (pb == nil) + { + pb = [PasteboardObject alloc]; + pb->name = RETAIN(aName); + pb->nextCount = 1; + pb->histLength = 1; + pb->history = [[NSMutableArray alloc] initWithCapacity: 2]; + pb->current = nil; + [pasteboards setObject: pb forKey: aName]; + AUTORELEASE(pb); + } + [dictionary_lock unlock]; + return pb; +} + +- (int) addTypes: (NSArray*)types + owner: (id)owner + pasteboard: (NSPasteboard*)pb + oldCount: (int)count +{ + PasteboardEntry *e = [self entryByCount: count]; + + if (e) + { + id x = [xPbClass ownerByOsPb: name]; + + [e addTypes: types owner: owner pasteboard: pb]; + + /* + * If there is an X pasteboard corresponding to this pasteboard, and the + * X system doesn't currently own the pasteboard, we must inform it of + * the change in the types of data supplied by this pasteboard. + * We do this by simulating a change of pasteboard ownership. + */ + if (x != owner && x != nil) + [x pasteboardChangedOwner: pb]; + return count; + } + return 0; +} + +- (NSString*) availableTypeFromArray: (NSArray*)types + changeCount: (int*)count +{ + PasteboardEntry *e = nil; + + if (*count <= 0) + { + e = current; + } + else + { + e = [self entryByCount: *count]; + } + if (e) + { + unsigned i; + + *count = [e refNum]; + for (i = 0; i < [types count]; i++) + { + NSString* key = [types objectAtIndex: i]; + + if ([e itemForType: key] != nil) + { + return key; + } + } + } + return nil; +} + +- (int) changeCount +{ + if (current) + { + return [current refNum]; + } + return 0; +} + +- (BOOL) checkConnection: (NSConnection*)c +{ + unsigned i; + BOOL found = NO; + + for (i = 0; i < [history count]; i++) + { + if ([[history objectAtIndex: i] checkConnection: c] == YES) + { + found = YES; + } + } + return found; +} + +- (NSData*) dataForType: (NSString*)type + oldCount: (int)count + mustBeCurrent: (BOOL)flag +{ + PasteboardEntry *e = nil; + + if (flag) + { + e = current; + } + else + { + e = [self entryByCount: count]; + } + if (verbose) + { + NSLog(@"%@ get data for type '%@' version %d\n", + self, type, e ? [e refNum] : -1); + } + if (e) + { + PasteboardData *d = [e itemForType: type]; + + if (d) + { + return [d newDataWithVersion: [e refNum]]; + } + } + return nil; +} + +- (void) dealloc +{ + RELEASE(name); + RELEASE(history); + [super dealloc]; +} + +- (int) declareTypes: (bycopy NSArray*)types + owner: (id)owner + pasteboard: (NSPasteboard*)pb +{ + PasteboardEntry *old = RETAIN(current); + id x = [xPbClass ownerByOsPb: name]; + + /* + * If neither the new nor the old owner of the pasteboard is the X + * pasteboard owner corresponding to this pasteboard, we will need + * to inform the X owner of the change of ownership. + */ + if (x == owner) + x = nil; + else if (x == [old owner]) + x = nil; + + current = [PasteboardEntry newWithTypes: types + owner: owner + pboard: pb + ref: nextCount++]; + [history addObject: current]; + RELEASE(current); + if ([history count] > histLength) + { + [history removeObjectAtIndex: 0]; + } + [old lostOwnership]; + RELEASE(old); + /* + * If there is an interested X pasteboard - inform it of the ownership + * change. + */ + if (x != nil) + [x pasteboardChangedOwner: pb]; + if (verbose) + { + NSLog(@"%@ declare types '%@' version %d\n", + self, types, [current refNum]); + } + return [current refNum]; +} + +- (PasteboardEntry*) entryByCount: (int)count +{ + if (current == nil) + { + return nil; + } + else if ([current refNum] == count) + { + return current; + } + else + { + int i; + + for (i = 0; i < [history count]; i++) + { + if ([[history objectAtIndex: i] refNum] == count) + { + return (PasteboardEntry*)[history objectAtIndex: i]; + } + } + return nil; + } +} + +- (NSString*) name +{ + return name; +} + +- (void) releaseGlobally +{ + if ([name isEqual: NSDragPboard]) return; + if ([name isEqual: NSFindPboard]) return; + if ([name isEqual: NSFontPboard]) return; + if ([name isEqual: NSGeneralPboard]) return; + if ([name isEqual: NSRulerPboard]) return; + [pasteboards removeObjectForKey: name]; +} + +- (BOOL) setData: (NSData*)data + forType: (NSString*)type + isFile: (BOOL)flag + oldCount: (int)count +{ + PasteboardEntry *e; + + if (verbose) + { + NSLog(@"%@ set data for type '%@' version %d\n", self, type, count); + } + e = [self entryByCount: count]; + if (e) + { + PasteboardData *d; + + if (flag) + { + d = [e itemForType: NSFileContentsPboardType]; + if (d) + { + [d setData: data]; + } + else + { + return NO; + } + if (type && [type isEqual: NSFileContentsPboardType] == NO) + { + d = [e itemForType: type]; + if (d) + { + [d setData: data]; + } + else + { + return NO; + } + } + return YES; + } + else if (type) + { + d = [e itemForType: type]; + if (d) + { + [d setData: data]; + return YES; + } + else + { + return NO; + } + } + else + { + return NO; + } + } + else + { + return NO; + } +} + +- (void) setHistory: (unsigned)length +{ + if (length < 1) length = 1; + if (length > MAXHIST) length = MAXHIST; + + histLength = length; + if (length < histLength) + { + while ([history count] > histLength) + { + [history removeObjectAtIndex: 0]; + } + } +} + +- (NSArray*) typesAndChangeCount: (int*)count +{ + PasteboardEntry *e = nil; + + if (*count <= 0) + { + e = current; + } + else + { + e = [self entryByCount: *count]; + } + if (e) + { + *count = [e refNum]; + return [e types]; + } + return nil; +} + +@end + + + + + +@interface PasteboardServer : NSObject +{ + NSMutableArray *permenant; +} +- (BOOL) connection: (NSConnection*)ancestor + shouldMakeNewConnection: (NSConnection*)newConn; +- (id) connectionBecameInvalid: (NSNotification*)notification; + +- (id) pasteboardByFilteringData: (NSData*)data + ofType: (NSString*)type + isFile: (BOOL)flag; +- (id) pasteboardByFilteringTypesInPasteboard: pb; +- (id) pasteboardWithName: (NSString*)name; +- (id) pasteboardWithUniqueName; +@end + + + +@implementation PasteboardServer + +- (BOOL) connection: (NSConnection*)ancestor + shouldMakeNewConnection: (NSConnection*)newConn; +{ + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(connectionBecameInvalid:) + name: NSConnectionDidDieNotification + object: newConn]; + [newConn setDelegate: self]; + return YES; +} + +- (id) connectionBecameInvalid: (NSNotification*)notification +{ + id connection = [notification object]; + + if (connection == conn) + { + NSLog(@"Help - pasteboard server connection has died!\n"); + exit(1); + } + if ([connection isKindOf: [NSConnection class]]) + { + NSEnumerator *e = [pasteboards objectEnumerator]; + PasteboardObject *o; + + while ((o = [e nextObject]) != nil) + { + [o checkConnection: connection]; + } + } + return self; +} + +- (void) dealloc +{ + RELEASE(permenant); + [super dealloc]; +} + +- (id) init +{ + self = [super init]; + if (self) + { + /* + * Tell the NSPasteboard class to use us as the server so that the X + * pasteboard owners can talk to us directly rather than over D.O. + */ + [NSPasteboard _localServer: (id)self]; + + /* + * Create all the pasteboards which must persist forever and add them + * to a local array. + */ + permenant = [[NSMutableArray alloc] initWithCapacity: 5]; + [permenant addObject: [self pasteboardWithName: NSGeneralPboard]]; + [permenant addObject: [self pasteboardWithName: NSDragPboard]]; + [permenant addObject: [self pasteboardWithName: NSFontPboard]]; + [permenant addObject: [self pasteboardWithName: NSRulerPboard]]; + [permenant addObject: [self pasteboardWithName: NSFindPboard]]; + + /* + * Ensure that the X pasteboard system is initialised. + */ + xPbClass = NSClassFromString(@"XPbOwner"); + } + return self; +} + +- (id) pasteboardByFilteringData: (NSData*)data + ofType: (NSString*)type + isFile: (BOOL)flag +{ + [self notImplemented: _cmd]; + return nil; +} + +- (id) pasteboardByFilteringTypesInPasteboard: pb +{ + [self notImplemented: _cmd]; + return nil; +} + +- (id) pasteboardWithName: (NSString*)name +{ + return [PasteboardObject pasteboardWithName: name]; +} + +- (id) pasteboardWithUniqueName +{ + return [PasteboardObject pasteboardWithName: nil]; +} + +- (NSArray*) typesFilterableTo: (NSString*)type +{ + [self notImplemented: _cmd]; + return nil; +} + +@end + + + +static void +ihandler(int sig) +{ + signal(sig, SIG_DFL); + abort(); +} + +static void +init(int argc, char** argv) +{ + NSArray *args = [[NSProcessInfo processInfo] arguments]; + unsigned count; + + for (count = 1; count < [args count]; count++) + { + NSString *a = [args objectAtIndex: count]; + + if ([a isEqualToString: @"--help"] == YES) + { + printf("gpbs\n\n"); + printf("GNU Pasteboard server\n"); + printf("--help\tfor help\n"); + printf("--no-fork\tavoid fork() to make debugging easy\n"); + printf("--verbose\tMore verbose debug output\n"); + exit(0); + } + else if ([a isEqualToString: @"--no-fork"] == YES) + debug++; + else if ([a isEqualToString: @"--verbose"] == YES) + verbose++; + else if ([a length] > 0) + { + printf("gpbs - GNU Pasteboard server\n"); + printf("I don't understand '%s'\n", [a cString]); + printf("--help for help\n"); + exit(0); + } + } + + for (count = 0; count < 32; count++) + { + signal((int)count, ihandler); + } + signal(SIGPIPE, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGTERM, ihandler); + + if (debug == 0) + { + /* + * Now fork off child process to run in background. + */ + switch (fork()) + { + case -1: + NSLog(@"gpbs - fork failed - bye.\n"); + exit(1); + + case 0: + /* + * Try to run in background. + */ +#ifdef NeXT + setpgrp(0, getpid()); +#else + setsid(); +#endif + break; + + default: + if (verbose) + { + NSLog(@"Process backgrounded (running as daemon)\r\n"); + } + exit(0); + } + } +} + + +int +main(int argc, char** argv, char **env) +{ + CREATE_AUTORELEASE_POOL(pool); + NSString *hostname; + +#ifdef GS_PASS_ARGUMENTS + [NSProcessInfo initializeWithArguments:argv count:argc environment:env]; +#endif + + init(argc, argv); + + // [NSObject enableDoubleReleaseCheck: YES]; + + server = [[PasteboardServer alloc] init]; + + if (server == nil) + { + NSLog(@"Unable to create server object.\n"); + exit(1); + } + + /* Register a connection that provides the server object to the network */ + conn = [NSConnection defaultConnection]; + [conn setRootObject: server]; + [conn setDelegate: server]; + [[NSNotificationCenter defaultCenter] + addObserver: server + selector: @selector(connectionBecameInvalid:) + name: NSConnectionDidDieNotification + object: (id)conn]; + + hostname = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"]; + if ([hostname length] == 0) + { + if ([conn registerName: PBSNAME] == NO) + { + NSLog(@"Unable to register with name server.\n"); + exit(1); + } + } + else + { + NSHost *host = [NSHost hostWithName: hostname]; + NSPort *port = [conn receivePort]; + NSPortNameServer *ns = [NSPortNameServer systemDefaultPortNameServer]; + NSArray *a; + unsigned c; + + if (host == nil) + { + NSLog(@"gdnc - unknown NSHost argument ... %@ - quiting.", hostname); + exit(1); + } + a = [host names]; + c = [a count]; + while (c-- > 0) + { + NSString *name = [a objectAtIndex: c]; + + name = [PBSNAME stringByAppendingFormat: @"-%@", name]; + if ([ns registerPort: port forName: name] == NO) + { + } + } + a = [host addresses]; + c = [a count]; + while (c-- > 0) + { + NSString *name = [a objectAtIndex: c]; + + name = [PBSNAME stringByAppendingFormat: @"-%@", name]; + if ([ns registerPort: port forName: name] == NO) + { + } + } + } + + if (verbose) + { + NSLog(@"GNU pasteboard server startup.\n"); + } + [[NSRunLoop currentRunLoop] run]; + RELEASE(pool); + exit(0); +} + diff --git a/Tools/xpbs.m b/Tools/xpbs.m new file mode 100644 index 0000000..b287e58 --- /dev/null +++ b/Tools/xpbs.m @@ -0,0 +1,1215 @@ +/* + xpbs.m + + GNUstep pasteboard server - X extension + + Copyright (C) 1999 Free Software Foundation, Inc. + + Author: Richard Frith-Macdonald + Date: April 1999 + + This file is part of the GNUstep Project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + You should have received a copy of the GNU General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include +#include + +#include +#include +#include +#include + +static Atom osTypeToX(NSString *t); +static NSString *xTypeToOs(Atom t); + +/* + * Non-predefined atoms that are used in the X selection mechanism + */ +static char* atom_names[] = { + "CHARACTER_POSITION", + "CLIENT_WINDOW", + "HOST_NAME", + "HOSTNAME", + "LENGTH", + "LIST_LENGTH", + "NAME", + "OWNER_OS", + "SPAN", + "TARGETS", + "TIMESTAMP", + "USER", + "TEXT", + "NULL", + "FILE_NAME" +}; +static Atom atoms[sizeof(atom_names)/sizeof(char*)]; + + +/* + * Macros to access elements in atom_names array. + */ +#define XG_CHAR_POSITION atoms[0] +#define XG_CLIENT_WINDOW atoms[1] +#define XG_HOST_NAME atoms[2] +#define XG_HOSTNAME atoms[3] +#define XG_LENGTH atoms[4] +#define XG_LIST_LENGTH atoms[5] +#define XG_NAME atoms[6] +#define XG_OWNER_OS atoms[7] +#define XG_SPAN atoms[8] +#define XG_TARGETS atoms[9] +#define XG_TIMESTAMP atoms[10] +#define XG_USER atoms[11] +#define XG_TEXT atoms[12] +#define XG_NULL atoms[13] +#define XG_FILE_NAME atoms[14] + + + +static Atom +osTypeToX(NSString *t) +{ + if ([t isEqualToString: NSStringPboardType] == YES) + return XA_STRING; + else if ([t isEqualToString: NSColorPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSFileContentsPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSFilenamesPboardType] == YES) + return XG_FILE_NAME; + else if ([t isEqualToString: NSFontPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSRulerPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSPostScriptPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSTabularTextPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSRTFPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSRTFDPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSTIFFPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSDataLinkPboardType] == YES) + return XG_NULL; + else if ([t isEqualToString: NSGeneralPboardType] == YES) + return XG_NULL; + else + return XG_NULL; +} + +static NSString* +xTypeToOs(Atom t) +{ + if (t == XA_STRING) + return NSStringPboardType; + else if (t == XG_TEXT) + return NSStringPboardType; + else if (t == XG_FILE_NAME) + return NSFilenamesPboardType; + else + return nil; +} + + + +static Bool xAppendProperty(Display* display, + Window window, + Atom property, + Atom target, + int format, + unsigned char* data, + int number_items) +{ +// Ensure that the error handler is set up. +// xSetErrorHandler(); + +// Any routine that appends properties can generate a BadAlloc error. +// xResetErrorFlag(); + + if (number_items > 0) + { + XChangeProperty(display, + window, + property, + target, + format, + PropModeAppend, + data, + number_items); + + XSync(display, False); + +// Check if our write to a property generated an X error. +// if (xError()) +// return False; + } + + return True; +} + +// This never gets called! +static unsigned char* +xConvertSelection(Display* display, + Window window, + Atom xTarget, + char* program, + char* text_data, + Atom* new_target, + int* format, + int* number_items) +{ + unsigned char *data = NULL; + int length; + char *user_name; + + *number_items = 0; + *format = 32; // In virtually all cases, format is 32 + + if ((xTarget == XA_STRING) || (xTarget == XG_TEXT)) + { + length = strlen(text_data); + data = (unsigned char*) malloc(length + 1); + + if (data != NULL) + strcpy(data, text_data); + + *format = 8; // Exception to format rule + *number_items = length; + } + else if (xTarget == XG_TIMESTAMP) + { + length = sizeof(int); + data = (unsigned char*) malloc( length ); + *number_items = 1; + } + else if (xTarget == XG_CLIENT_WINDOW) + { + length = sizeof(Window); + data = (unsigned char*) malloc( length ); + *number_items = 1; + } + else if (xTarget == XG_LENGTH) + { + length = sizeof(int); + data = (unsigned char*) malloc( length ); + *number_items = 1; + } + else if (xTarget == XG_NAME) + { + length = strlen(program) + 1; + data = (unsigned char*) malloc( length ); + strcpy(data, program); + *number_items = length; + } + else if (xTarget == XG_USER) + { + user_name = getenv("USER"); + length = strlen(user_name) + 1; + data = (unsigned char*) malloc(length); + strcpy(data, user_name); + *number_items = length; + } + else if ((xTarget == XG_HOSTNAME) || (xTarget == XG_HOST_NAME)) + { + const char *host = [[[NSProcessInfo processInfo] hostName] cString]; + + length = strlen(host) + 1; + data = (unsigned char*) malloc(length); + strcpy(data, host); + *number_items = length; + } + else if (xTarget == XG_CHAR_POSITION) + { + length = sizeof(int) * 2; + data = (unsigned char*) malloc( length ); + *number_items = 2; + } + else if (xTarget == XG_TARGETS) + { + length = sizeof(atoms); + data = (unsigned char*) malloc(length); + } + + return data; +} + +@interface XPbOwner : NSObject +{ + NSPasteboard *_pb; + NSData *_obj; + NSString *_name; + Atom _xPb; + Time _waitingForSelection; + Time _timeOfLastAppend; + BOOL _ownedByOpenStep; +} + ++ (XPbOwner*) ownerByXPb: (Atom)p; ++ (XPbOwner*) ownerByOsPb: (NSString*)p; ++ (void) receivedEvent: (void*)data + type: (RunLoopEventType)type + extra: (void*)extra + forMode: (NSString*)mode; ++ (NSDate*) timedOutEvent: (void*)data + type: (RunLoopEventType)type + forMode: (NSString*)mode; ++ (void) xPropertyNotify: (XPropertyEvent*)xEvent; ++ (void) xSelectionClear: (XSelectionClearEvent*)xEvent; ++ (void) xSelectionNotify: (XSelectionEvent*)xEvent; ++ (void) xSelectionRequest: (XSelectionRequestEvent*)xEvent; + +- (NSData*) data; +- (id) initWithXPb: (Atom)x osPb: (NSPasteboard*)o; +- (BOOL) ownedByOpenStep; +- (NSPasteboard*) osPb; +- (void) pasteboardChangedOwner: (NSPasteboard*)sender; +- (void) pasteboard: (NSPasteboard*)pb provideDataForType: (NSString*)type; +- (void) setData: (NSData*)obj; +- (void) setOwnedByOpenStep: (BOOL)flag; +- (void) setTimeOfLastAppend: (Time)when; +- (void) setWaitingForSelection: (Time)when; +- (Time) timeOfLastAppend; +- (Time) waitingForSelection; +- (Atom) xPb; +- (void) xSelectionClear; +- (void) xSelectionNotify: (XSelectionEvent*)xEvent; +- (void) xSelectionRequest: (XSelectionRequestEvent*)xEvent; +- (BOOL) xProvideSelection: (XSelectionRequestEvent*)xEvent; +- (Time) xTimeByAppending; +- (BOOL) xSendData: (unsigned char*) data format: (int) format + items: (int) numItems type: (Atom) xType + to: (Window) window property: (Atom) property; +@end + + + +// Special subclass for the drag pasteboard +@interface XDragPbOwner : XPbOwner +{ +} +@end + + + +/* + * The display we are using - everything refers to it. + */ +static Display *xDisplay; +static Window xRootWin; +static Window xAppWin; +static NSMapTable *ownByX; +static NSMapTable *ownByO; +static NSString *xWaitMode = @"XPasteboardWaitMode"; + +@implementation XPbOwner + ++ (void) initialize +{ + if (self == [XPbOwner class]) + { + XPbOwner *o; + NSPasteboard *p; + Atom XA_CLIPBOARD; + + ownByO = NSCreateMapTable(NSObjectMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + ownByX = NSCreateMapTable(NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + + xDisplay = XOpenDisplay(NULL); + if (xDisplay == 0) + { + NSLog(@"Unable to open X display - no X interoperation available"); + } + else + { + NSRunLoop *l = [NSRunLoop currentRunLoop]; + int desc; + + /* + * Set up atoms for use in X selection mechanism. + */ + XInternAtoms(xDisplay, atom_names, sizeof(atom_names)/sizeof(char*), + False, atoms); + + xRootWin = RootWindow(xDisplay, DefaultScreen(xDisplay)); + xAppWin = XCreateSimpleWindow(xDisplay, xRootWin, + 0, 0, 100, 100, 1, 1, 0L); + /* + * Add the X descriptor to the run loop so we get callbacks when + * X events arrive. + */ + desc = XConnectionNumber(xDisplay); + + [l addEvent: (void*)(gsaddr)desc + type: ET_RDESC + watcher: (id)self + forMode: NSDefaultRunLoopMode]; + + [l addEvent: (void*)(gsaddr)desc + type: ET_RDESC + watcher: (id)self + forMode: NSConnectionReplyMode]; + + [l addEvent: (void*)(gsaddr)desc + type: ET_RDESC + watcher: (id)self + forMode: xWaitMode]; + + XSelectInput(xDisplay, xAppWin, PropertyChangeMask); + + XFlush(xDisplay); + } + + /* + * According to the new open desktop specification these + * two pasteboards should be switched around. That is, + * general should be XA_CLIPBOARD and selection + * XA_PRIMARY. The problem is that most X programs still + * use the old way. So we do the same for now. + */ + /* + * For the general pasteboard we establish an initial owner that is the + * X selection system. In this way, any X window selection already + * active will be available to the GNUstep system. + * This object is not released! + */ + p = [NSPasteboard generalPasteboard]; + o = [[XPbOwner alloc] initWithXPb: XA_PRIMARY osPb: p]; + [o xSelectionClear]; + + /* + * For the selection pasteboard we establish an initial owner that is the + * X selection system. In this way, any X window selection already + * active will be available to the GNUstep system. + * This object is not released! + */ + XA_CLIPBOARD = XInternAtom(xDisplay, "CLIPBOARD", False); + p = [NSPasteboard pasteboardWithName: @"Selection"]; + o = [[XPbOwner alloc] initWithXPb: XA_CLIPBOARD osPb: p]; + [o xSelectionClear]; + + // Call this to get the class initialisation + [XDragPbOwner class]; + } +} + ++ (XPbOwner*) ownerByOsPb: (NSString*)p +{ + return (XPbOwner*)NSMapGet(ownByO, (void*)(gsaddr)p); +} + ++ (XPbOwner*) ownerByXPb: (Atom)x +{ + return (XPbOwner*)NSMapGet(ownByX, (void*)(gsaddr)x); +} + + +/* + * This is the event handler called by the runloop when the X descriptor + * has data available to read. + */ ++ (void) receivedEvent: (void*)data + type: (RunLoopEventType)type + extra: (void*)extra + forMode: (NSString*)mode +{ + int count; + + NSAssert(type == ET_RDESC, NSInternalInconsistencyException); + + while ((count = XPending(xDisplay)) > 0) + { + while (count-- > 0) + { + XEvent xEvent; + + XNextEvent(xDisplay, &xEvent); + + switch (xEvent.type) + { + case PropertyNotify: + [self xPropertyNotify: (XPropertyEvent*)&xEvent]; + NSDebugLLog(@"Pbs", @"PropertyNotify."); + break; + + case SelectionNotify: + [self xSelectionNotify: (XSelectionEvent*)&xEvent]; + NSDebugLLog(@"Pbs", @"SelectionNotify."); + break; + + case SelectionClear: + [self xSelectionClear: (XSelectionClearEvent*)&xEvent]; + NSDebugLLog(@"Pbs", @"SelectionClear."); + break; + + case SelectionRequest: + [self xSelectionRequest: (XSelectionRequestEvent*)&xEvent]; + NSDebugLLog(@"Pbs", @"SelectionRequest."); + break; + + default: + NSDebugLLog(@"Pbs", @"Unexpected X event."); + break; + } + } + } +} + +/* + * This handler called if an operation times out - never happens 'cos we + * don't supply any timeouts - included for protocol conformance. + */ ++ (NSDate*) timedOutEvent: (void*)data + type: (RunLoopEventType)type + forMode: (NSString*)mode +{ + return nil; +} + +#define FULL_LENGTH 8192L /* Amount to read */ + ++ (void) xSelectionClear: (XSelectionClearEvent*)xEvent +{ + XPbOwner *o; + + o = [self ownerByXPb: xEvent->selection]; + if (o == nil) + { + NSDebugLLog(@"Pbs", @"Selection clear for unknown selection - '%s'.", + XGetAtomName(xDisplay, xEvent->selection)); + return; + } + + if (xEvent->window != (Window)xAppWin) + { + NSDebugLLog(@"Pbs", @"Selection clear for wrong (not our) window."); + return; + } + + [o xSelectionClear]; +} + ++ (void) xPropertyNotify: (XPropertyEvent*)xEvent +{ + XPbOwner *o; + + o = [self ownerByXPb: xEvent->atom]; + if (o == nil) + { + NSDebugLLog(@"Pbs", @"Property notify for unknown property - '%s'.", + XGetAtomName(xDisplay, xEvent->atom)); + return; + } + + if (xEvent->window != (Window)xAppWin) + { + NSDebugLLog(@"Pbs", @"Property notify for wrong (not our) window."); + return; + } + + if (xEvent->time != 0) + { + [o setTimeOfLastAppend: xEvent->time]; + } +} + ++ (void) xSelectionNotify: (XSelectionEvent*)xEvent +{ + XPbOwner *o; + + o = [self ownerByXPb: xEvent->selection]; + if (o == nil) + { + NSDebugLLog(@"Pbs", @"Selection notify for unknown selection - '%s'.", + XGetAtomName(xDisplay, xEvent->selection)); + return; + } + + if (xEvent->requestor != (Window)xAppWin) + { + NSDebugLLog(@"Pbs", @"Selection notify for wrong (not our) window."); + return; + } + + if (xEvent->property == (Atom)None) + { + NSLog(@"Owning program failed to convert data."); + return; + } + else + { + NSDebugLLog(@"Pbs", @"Selection (%s) notify - '%s'.", + XGetAtomName(xDisplay, xEvent->selection), + XGetAtomName(xDisplay, xEvent->property)); + } + + [o xSelectionNotify: xEvent]; +} + ++ (void) xSelectionRequest: (XSelectionRequestEvent*)xEvent +{ + XPbOwner *o; + + o = [self ownerByXPb: xEvent->selection]; + if (o == nil) + { + NSDebugLLog(@"Pbs", @"Selection request for unknown selection - '%s'.", + XGetAtomName(xDisplay, xEvent->selection)); + return; + } + + if (xEvent->requestor == (Window)xAppWin) + { + NSDebugLLog(@"Pbs", @"Selection request for wrong (our) window."); + return; + } + + if (xEvent->property == None) + { + NSDebugLLog(@"Pbs", @"Selection request without reply property set."); + return; + } + + [o xSelectionRequest: xEvent]; +} + +- (NSData*) data +{ + return _obj; +} + +- (void) dealloc +{ + RELEASE(_pb); + RELEASE(_obj); + /* + * Remove self from map of X pasteboard owners. + */ + NSMapRemove(ownByX, (void*)(gsaddr)_xPb); + NSMapRemove(ownByO, (void*)(gsaddr)_name); + [super dealloc]; +} + +- (id) initWithXPb: (Atom)x osPb: (NSPasteboard*)o +{ + _pb = RETAIN(o); + _name = [_pb name]; + _xPb = x; + /* + * Add self to map of all X pasteboard owners. + */ + NSMapInsert(ownByX, (void*)(gsaddr)_xPb, (void*)(gsaddr)self); + NSMapInsert(ownByO, (void*)(gsaddr)_name, (void*)(gsaddr)self); + return self; +} + +- (NSPasteboard*) osPb +{ + return _pb; +} + +- (BOOL) ownedByOpenStep +{ + return _ownedByOpenStep; +} + +- (void) pasteboardChangedOwner: (NSPasteboard*)sender +{ + Window w; + /* + * If this gets called, a GNUstep object has grabbed the pasteboard + * or has changed the types of data available from the pasteboard + * so we must tell the X server that we have the current selection. + * To conform to ICCCM we need to specify an up-to-date timestamp. + */ + XSetSelectionOwner(xDisplay, _xPb, xAppWin, [self xTimeByAppending]); + w = XGetSelectionOwner(xDisplay, _xPb); + if (w != xAppWin) + { + NSLog(@"Failed to set X selection owner to the pasteboard server."); + } + [self setOwnedByOpenStep: YES]; +} + +- (void) pasteboard: (NSPasteboard*)pb provideDataForType: (NSString*)type +{ + [self setData: nil]; + + /* + * If this gets called, a GNUstep object wants the pasteboard contents + * and a plain old X application is providing them, so we must grab + * the info. + */ + if ([type isEqual: NSStringPboardType]) + { + Time whenRequested; + + /* + * Do a nul append to a property to get a timestamp, if it returns the + * 'CurrentTime' constant then we haven't been able to get one. + */ + whenRequested = [self xTimeByAppending]; + if (whenRequested != CurrentTime) + { + NSDate *limit; + + /* + * Ok - we got a timestamp, so we can ask the selection system for + * the pasteboard data that was/is valid for theat time. + * Ask the X system to provide the pasteboard data in the + * appropriate property of our application root window. + */ + XConvertSelection(xDisplay, [self xPb], XA_STRING, + [self xPb], xAppWin, whenRequested); + XFlush(xDisplay); + + /* + * Run an event loop to read X events until we have aquired the + * pasteboard data we need. + */ + limit = [NSDate dateWithTimeIntervalSinceNow: 20.0]; + [self setWaitingForSelection: whenRequested]; + while ([self waitingForSelection] == whenRequested) + { + [[NSRunLoop currentRunLoop] runMode: xWaitMode + beforeDate: limit]; + if ([limit timeIntervalSinceNow] <= 0.0) + break; /* Timeout */ + } + if ([self waitingForSelection] != 0) + { + [self setWaitingForSelection: 0]; + NSLog(@"Timed out waiting for X selection"); + } + } + } + else + { + NSLog(@"Request for non-string info from X pasteboard"); + } + [pb setData: [self data] forType: type]; +} + +- (void) setData: (NSData*)obj +{ + ASSIGN(_obj, obj); +} + +- (void) setOwnedByOpenStep: (BOOL)f +{ + _ownedByOpenStep = f; +} + +- (void) setTimeOfLastAppend: (Time)when +{ + _timeOfLastAppend = when; +} + +- (void) setWaitingForSelection: (Time)when +{ + _waitingForSelection = when; +} + +- (Time) timeOfLastAppend +{ + return _timeOfLastAppend; +} + +- (Time) waitingForSelection +{ + return _waitingForSelection; +} + +- (Atom) xPb +{ + return _xPb; +} + +static BOOL appendFailure; +static int +xErrorHandler(Display *d, XErrorEvent *e) +{ + appendFailure = YES; + return 0; +} + +- (void) xSelectionClear +{ + NSArray *types; + + /* + * Really we should check to see what types of data the selection owner is + * making available, and declare them all - but as a temporary HACK we just + * declare string data. + */ + types = [NSArray arrayWithObject: NSStringPboardType]; + [_pb declareTypes: types owner: self]; + [self setOwnedByOpenStep: NO]; +} + +- (void) xSelectionNotify: (XSelectionEvent*)xEvent +{ + int status; + unsigned char *data; + Atom actual_target; + Atom new_target = XA_STRING; + int actual_format; + unsigned long bytes_remaining; + unsigned long number_items; + + if ([self waitingForSelection] > xEvent->time) + { + NSLog(@"Unexpected selection notify - time %u.", xEvent->time); + return; + } + [self setWaitingForSelection: 0]; + + /* + * Read data from property identified in SelectionNotify event. + */ + status = XGetWindowProperty(xDisplay, + xEvent->requestor, + xEvent->property, + 0L, // offset + FULL_LENGTH, + True, // Delete prop when read. + new_target, + &actual_target, + &actual_format, + &number_items, + &bytes_remaining, + &data); + + if ((status == Success) && (number_items > 0)) + { +// Convert data to text string. +// string = PropertyToString(xDisplay,new_target,number_items,(char*)data); + + if (new_target == XA_STRING) + { + NSData *d; + NSString *s; + + s = [NSString stringWithCString: data]; + d = [NSSerializer serializePropertyList: s]; + [self setData: d]; + } + else + { + NSLog(@"Unsupported data type from X selection."); + } + + if (data) + XFree(data); + } +} + +- (void) xSelectionRequest: (XSelectionRequestEvent*)xEvent +{ + XSelectionEvent notify_event; + BOOL status; + + status = [self xProvideSelection: xEvent]; + + /* + * Set up the selection notify information from the event information + * so we comply with the ICCCM. + */ + notify_event.display = xEvent->display; + notify_event.type = SelectionNotify; + notify_event.requestor = xEvent->requestor; + notify_event.selection = xEvent->selection; + notify_event.target = xEvent->target; + notify_event.time = xEvent->time; + notify_event.property = xEvent->property; + + /* + * If for any reason we cannot provide the data to the requestor, we must + * send a selection notify with a property of 'None' so that the requestor + * knows the request failed. + */ + if (status == NO) + notify_event.property = None; + + XSendEvent(xEvent->display, xEvent->requestor, False, 0L, + (XEvent*)¬ify_event); +} + +- (BOOL) xProvideSelection: (XSelectionRequestEvent*)xEvent +{ + NSArray *types = [_pb types]; + unsigned numOsTypes = [types count]; + NSString *osType = nil; + Atom xType = XG_NULL; + unsigned char *data = 0; + int format = 0; + int numItems = 0; + unsigned i; + + if (xEvent->target == XG_TARGETS) + { + unsigned numTypes = 0; + Atom xTypes[numOsTypes]; + + /* + * The requestor wants a list of the types we can supply it with. + */ + for (i = 0; i < numOsTypes; i++) + { + NSString *type = [types objectAtIndex: i]; + Atom t; + + t = osTypeToX(type); + if (t != XG_NULL) + { + unsigned j; + + for (j = 0; j < numTypes; j++) + { + if (xTypes[j] == t) + break; + } + if (j == numTypes) + { + xTypes[numTypes++] = t; + } + } + } + if (numTypes > 0) + { + /* + * We can supply one or more types of data to the requestor so + * we will give it a list of the types supported. + */ + xType = XA_ATOM; + data = malloc(numTypes*sizeof(Atom)); + memcpy(data, xTypes, numTypes*sizeof(Atom)); + numItems = numTypes; + format = 32; + } + else + { + /* + * No OS types that are convertable to X types. + */ + xType = XG_NULL; + } + } + else + { + if (xEvent->target == AnyPropertyType) + { + /* + * The requestor will accept any type of data - so we use the first + * OpenStep type that corresponds to a known X type. + */ + for (i = 0; i < numOsTypes; i++) + { + NSString *type = [types objectAtIndex: i]; + Atom t = osTypeToX(type); + + if (t != XG_NULL) + { + osType = type; + xType = t; + break; + } + } + } + else + { + /* + * Find an available OpenStep pasteboard type that corresponds + * to the requested X type. + */ + for (i = 0; i < numOsTypes; i++) + { + NSString *type = [types objectAtIndex: i]; + Atom t = osTypeToX(type); + + if (t == xEvent->target) + { + osType = type; + xType = t; + break; + } + } + } + + /* + * Now we know what type of data is required - so get it from the + * pasteboard and convert to a format X can understand. + */ + if (osType != nil) + { + if ([osType isEqualToString: NSStringPboardType]) + { + NSString *s = [_pb stringForType: NSStringPboardType]; + + format = 8; + numItems = [s cStringLength]; + data = malloc(numItems + 1); + if (data) + [s getCString: data]; + } + else + { + NSLog(@"Trying to convert from unsupported type - '%@'", osType); + } + } + } + + return [self xSendData: data format: format items: numItems type: xType + to: xEvent->requestor property: xEvent->property]; +} + +- (BOOL) xSendData: (unsigned char*) data format: (int) format + items: (int) numItems type: (Atom) xType + to: (Window) window property: (Atom) property +{ + BOOL status = NO; + + /* + * If we have managed to convert data of the appropritate type, we must now + * append the data to the property on the requesting window. + * We do this in small chunks, checking for errors, in case the window + * manager puts a limit on the data size we can use. + * This is not thread-safe - but I think that's a general problem with X. + */ + if (data != 0 && numItems != 0 && format != 0) + { + int (*oldHandler)(Display*, XErrorEvent*); + int mode = PropModeReplace; + int pos = 0; + + appendFailure = NO; + oldHandler = XSetErrorHandler(xErrorHandler); + + while (appendFailure == NO && pos < numItems) + { + int maxItems = 4096 * 8 / format; + + if (pos + maxItems > numItems) + maxItems = numItems - pos; + XChangeProperty(xDisplay, window, property, + xType, format, mode, &data[pos*format], maxItems); + mode = PropModeAppend; + pos += maxItems; + XSync(xDisplay, False); + } + XFree(data); + XSetErrorHandler(oldHandler); + if (appendFailure == NO) + status = YES; + } + return status; +} + +- (Time) xTimeByAppending +{ + NSDate *limit; + Time whenRequested; + Atom actualType = 0; + int actualFormat = 0; + unsigned long ni; + unsigned long ba; + unsigned char *pr; + + /* + * Do a nul append to a property to get a timestamp, + * - but first we must determine the property-type and format. + */ + XGetWindowProperty(xDisplay, xAppWin, [self xPb], 0, 0, False, + AnyPropertyType, &actualType, &actualFormat, &ni, &ba, &pr); + if (pr != 0) + XFree(pr); + + if (actualType == None) + { + /* + * The property doesn't exist - so we will be creating a new (empty) + * property. + */ + actualType = XA_STRING; + actualFormat = 8; + } + + XChangeProperty(xDisplay, xAppWin, [self xPb], actualType, actualFormat, + PropModeAppend, 0, 0); + XFlush(xDisplay); + limit = [NSDate dateWithTimeIntervalSinceNow: 3.0]; + [self setTimeOfLastAppend: 0]; + /* + * Run an event loop until we get a notification for our nul append. + * this will give us an up-to-date timestamp as required by ICCCM. + */ + while ([self timeOfLastAppend] == 0) + { + [[NSRunLoop currentRunLoop] runMode: xWaitMode + beforeDate: limit]; + if ([limit timeIntervalSinceNow] <= 0.0) + break; /* Timeout */ + } + if ((whenRequested = [self timeOfLastAppend]) == 0) + { + NSLog(@"Timed out waiting for X append"); + whenRequested = CurrentTime; + } + return whenRequested; +} + +@end + + + +// This are copies of functions from XGContextEvent.m. +// We should create a separate file for them. +static inline +Atom * +mimeTypeForPasteboardType(Display *xDisplay, NSZone *zone, NSArray *types) +{ + Atom *typelist; + int count = [types count]; + int i; + + typelist = NSZoneMalloc(zone, (count+1) * sizeof(Atom)); + for (i = 0; i < count; i++) + { + NSString *mime = [NSPasteboard mimeTypeForPasteboardType: + [types objectAtIndex: i]]; + typelist[i] = XInternAtom(xDisplay, [mime cString], False); + } + typelist[count] = 0; + + return typelist; +} + +static inline +NSArray * +pasteboardTypeForMimeType(Display *xDisplay, NSZone *zone, Atom *typelist) +{ + Atom *type = typelist; + NSMutableArray *newTypes = [[NSMutableArray allocWithZone: zone] init]; + + while(*type != None) + { + char *s = XGetAtomName(xDisplay, *type); + + if (s) + { + [newTypes addObject: [NSPasteboard pasteboardTypeForMimeType: + [NSString stringWithCString: s]]]; + } + } + + return AUTORELEASE(newTypes); +} + +static DndClass dnd; + +@implementation XDragPbOwner + ++ (void) initialize +{ + if (self == [XDragPbOwner class]) + { + NSPasteboard *p; + + xdnd_init(&dnd, xDisplay); + p = [NSPasteboard pasteboardWithName: NSDragPboard]; + [[XDragPbOwner alloc] initWithXPb: dnd.XdndSelection osPb: p]; + } +} + +- (void) pasteboardChangedOwner: (NSPasteboard*)sender +{ + NSArray *types; + Atom *typelist; + + // Some GNUstep application did grap the drag pasteboard. Report this to X. + if (xdnd_set_selection_owner(&dnd, xAppWin, None)) + { + NSLog(@"Failed to set X drag selection owner to the pasteboard server."); + } + [self setOwnedByOpenStep: YES]; + + // We also have to set the supported types for our window + types = [_pb types]; + typelist = mimeTypeForPasteboardType(xDisplay, [self zone], types); + xdnd_set_type_list(&dnd, xAppWin, typelist); + NSZoneFree([self zone], typelist); +} + +- (NSArray*) availableTypes +{ + Window window; + Atom *types; + NSArray *newTypes; + + window = XGetSelectionOwner(xDisplay, dnd.XdndSelection); + if (window == None) + return nil; + xdnd_get_type_list(&dnd, window, &types); + newTypes = pasteboardTypeForMimeType(xDisplay, [self zone], types); + free(types); + return newTypes; +} + +- (void) pasteboard: (NSPasteboard*)pb provideDataForType: (NSString*)type +{ + NSString *mime = [NSPasteboard mimeTypeForPasteboardType: type]; + Atom mType = XInternAtom(xDisplay, [mime cString], False); + Window window; + Time whenRequested = CurrentTime; + NSDate *limit; + + [self setData: nil]; + // How can we get the selection owner? + window = XGetSelectionOwner(xDisplay, dnd.XdndSelection); + + xdnd_convert_selection(&dnd, window, xAppWin, mType); + XFlush(xDisplay); + + /* + * Run an event loop to read X events until we have aquired the + * pasteboard data we need. + */ + limit = [NSDate dateWithTimeIntervalSinceNow: 20.0]; + [self setWaitingForSelection: whenRequested]; + while ([self waitingForSelection] == whenRequested) + { + [[NSRunLoop currentRunLoop] runMode: xWaitMode + beforeDate: limit]; + if ([limit timeIntervalSinceNow] <= 0.0) + break; /* Timeout */ + } + if ([self waitingForSelection] != 0) + { + [self setWaitingForSelection: 0]; + NSLog(@"Timed out waiting for X selection"); + } + [pb setData: [self data] forType: type]; +} + +- (void) xSelectionClear +{ + // Do nothing as we don't know, which new types will be supplied + [self setOwnedByOpenStep: NO]; +} + +@end diff --git a/Version b/Version new file mode 100644 index 0000000..7c62c48 --- /dev/null +++ b/Version @@ -0,0 +1,13 @@ +# This file is included in various Makefile's to get version information. +# Copyright (C) 2002 Free Software Foundation + +# The version number of this release. +GNUSTEP_BACK_MAJOR_VERSION=0 +GNUSTEP_BACK_MINOR_VERSION=7 +GNUSTEP_BACK_SUBMINOR_VERSION=5 +GNUSTEP_BACK_VERSION=${GNUSTEP_BACK_MAJOR_VERSION}.${GNUSTEP_BACK_MINOR_VERSION}.${GNUSTEP_BACK_SUBMINOR_VERSION} +VERSION=${GNUSTEP_BACK_VERSION} + +GNUSTEP_BACK_FTP_MACHINE=ftp.gnustep.org +GNUSTEP_BACK_FTP_DIRECTORY=pub/gnustep/core + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..b749f1f --- /dev/null +++ b/acconfig.h @@ -0,0 +1,16 @@ +/* Macros that may be defined by the aclocal.m4 extentions to `configure' + for GNUstep XGPS Library. */ + +#undef XSHM + +#undef WITH_WRASTER + +#undef HAVE_XFT + +#undef USE_XIM + +#undef BUILD_XLIB +#undef BUILD_XDPS +#undef BUILD_X11 +#undef BUILD_WIN32 +#undef BUILD_WINLIB diff --git a/back.make.in b/back.make.in new file mode 100644 index 0000000..611a59a --- /dev/null +++ b/back.make.in @@ -0,0 +1,44 @@ +# -*-makefile-*- +# back.make +# +# Makefile flags and configs to build with the back library. +# +# Copyright (C) 2001 Free Software Foundation, Inc. +# +# Author: Nicola Pero +# Based on code originally in the gnustep make package +# +# This file is part of the GNUstep Back Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# You should have received a copy of the GNU General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +ifeq ($(BACK_MAKE_LOADED),) +BACK_MAKE_LOADED=yes + +ifeq ($(BACKEND_BUNDLE),) + GRAPHIC_LIBS=@GRAPHIC_LIBS@ + GRAPHIC_CFLAGS=@GRAPHIC_CFLAGS@ + GRAPHIC_LFLAGS=@GRAPHIC_LFLAGS@ + X_PRE_LIBS=@X_PRE_LIBS@ + + BACKEND_LDFLAGS = + BACKEND_LIBS = -lgnustep-back + BACKEND_DEFINE = -DBACKEND_LIBRARY=1 + + SYSTEM_INCLUDES = $(CONFIG_SYSTEM_INCL) $(GRAPHIC_CFLAGS) + SYSTEM_LDFLAGS = + SYSTEM_LIB_DIR = $(GRAPHIC_LFLAGS) + SYSTEM_LIBS = $(GRAPHIC_LIBS) +endif + +endif # BACK_MAKE_LOADED + + diff --git a/config.h b/config.h new file mode 100644 index 0000000..b0ed160 --- /dev/null +++ b/config.h @@ -0,0 +1,28 @@ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if the X Window System is missing or not being used. */ +/* #undef X_DISPLAY_MISSING */ + +#define XSHM 1 + +#define WITH_WRASTER 1 + +#define HAVE_XFT 1 + +/* #undef USE_XIM */ + +/* #undef BUILD_XLIB */ +#define BUILD_XDPS 1 +#define BUILD_X11 1 +/* #undef BUILD_WIN32 */ +/* #undef BUILD_WINLIB */ + +/* Define if you have the header file. */ +#define HAVE_DPS_DPSNXARGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_DPS_DPSCLIENT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_WRASTER_H */ diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..5f8c3c7 --- /dev/null +++ b/config.h.in @@ -0,0 +1,27 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +#undef XSHM + +#undef WITH_WRASTER + +#undef HAVE_XFT + +#undef USE_XIM + +#undef BUILD_XLIB +#undef BUILD_XDPS +#undef BUILD_X11 +#undef BUILD_WIN32 +#undef BUILD_WINLIB + +/* Define if you have the header file. */ +#undef HAVE_DPS_DPSNXARGS_H + +/* Define if you have the header file. */ +#undef HAVE_DPS_DPSCLIENT_H + +/* Define if you have the header file. */ +#undef HAVE_WRASTER_H diff --git a/config.make.in b/config.make.in new file mode 100644 index 0000000..7b9021e --- /dev/null +++ b/config.make.in @@ -0,0 +1,17 @@ +# -*-makefile-*- +# Extra make variables for backend library +# + +WITH_WRASTER=@WITH_WRASTER@ +WITH_XFT=@WITH_XFT@ + +GRAPHIC_LIBS=@GRAPHIC_LIBS@ +GRAPHIC_CFLAGS=@GRAPHIC_CFLAGS@ +GRAPHIC_LFLAGS=@GRAPHIC_LFLAGS@ +X_PRE_LIBS=@X_PRE_LIBS@ + +BUILD_XLIB=@BUILD_XLIB@ +BUILD_XDPS=@BUILD_XDPS@ +BUILD_X11=@BUILD_X11@ +BUILD_WIN32=@BUILD_WIN32@ +BUILD_WINLIB=@BUILD_WINLIB@ diff --git a/configure b/configure new file mode 100755 index 0000000..df7c038 --- /dev/null +++ b/configure @@ -0,0 +1,3146 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-wraster=PREFIX get-wraster-flags directory prefix" +ac_help="$ac_help + --with-x use the X Window System" +ac_help="$ac_help + --with-dps-library=DIR DPS library file are in DIR" +ac_help="$ac_help + --with-dps-include=DIR DPS include files are in DIR" +ac_help="$ac_help + --enable-xim Enable XIM support" +ac_help="$ac_help + --disable-xim Disable XIM support" +ac_help="$ac_help + --with-jpeg-library=DIR JPEG library file are in DIR" +ac_help="$ac_help + --with-jpeg-include=DIR JPEG include files are in DIR" +ac_help="$ac_help + --with-tiff-library=DIR TIFF library file are in DIR" +ac_help="$ac_help + --with-tiff-include=DIR TIFF include files are in DIR" +ac_help="$ac_help + --enable-xlib Build xlib graphics context" +ac_help="$ac_help + --enable-xdps Build xdps graphics context" +ac_help="$ac_help + --enable-x11 Build x11 server" +ac_help="$ac_help + --enable-win32 Build win32 server" +ac_help="$ac_help + --enable-winlib Build win32 graphics context" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=back.make.in + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +if test -z "$GNUSTEP_SYSTEM_ROOT"; then + { echo "configure: error: You must run the GNUstep.sh script before configuring" 1>&2; exit 1; } +fi + +#-------------------------------------------------------------------- +# Use config.guess, config.sub and install-sh provided by gnustep-make +#-------------------------------------------------------------------- +ac_aux_dir= +for ac_dir in $GNUSTEP_SYSTEM_ROOT/Makefiles $srcdir/$GNUSTEP_SYSTEM_ROOT/Makefiles; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $GNUSTEP_SYSTEM_ROOT/Makefiles $srcdir/$GNUSTEP_SYSTEM_ROOT/Makefiles" 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + + + +#-------------------------------------------------------------------- +# Determine the host, build, and target systems +#-------------------------------------------------------------------- + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:616: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:637: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:655: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +#-------------------------------------------------------------------- +# The following is so that headers and custom libraries +# in the GNUstep root are used before the standard ones +#-------------------------------------------------------------------- +# Set location of GNUstep dirs for later use +GNUSTEP_HDIR=$GNUSTEP_SYSTEM_ROOT/Headers +if test "$GNUSTEP_FLATTENED" = yes; then + GNUSTEP_LDIR=$GNUSTEP_SYSTEM_ROOT/Libraries +else + clean_target_os=`$GNUSTEP_SYSTEM_ROOT/Makefiles/clean_os.sh $target_os` + clean_target_cpu=`$GNUSTEP_SYSTEM_ROOT/Makefiles/clean_cpu.sh $target_cpu` + obj_dir=$clean_target_cpu/$clean_target_os + GNUSTEP_LDIR=$GNUSTEP_SYSTEM_ROOT/Libraries/$obj_dir +fi +CPPFLAGS="$CPPFLAGS -I$GNUSTEP_HDIR" +LDFLAGS="$LDFLAGS -L$GNUSTEP_LDIR/$LIBRARY_COMBO -L$GNUSTEP_LDIR" + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:698: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:728: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:779: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:811: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 822 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:827: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:853: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:858: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:886: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + +#-------------------------------------------------------------------- +# Look for WindowMaker's wraster library +#-------------------------------------------------------------------- +# Check whether --with-wraster or --without-wraster was given. +if test "${with_wraster+set}" = set; then + withval="$with_wraster" + : +fi + +if test "x$with_wraster" = "x"; then + wprefix="" +else + wprefix=${with_wraster}/ +fi + +GRAPHIC_LIBS=`${wprefix}get-wraster-flags --libs` +GRAPHIC_CFLAGS=`${wprefix}get-wraster-flags --cflags` +GRAPHIC_LFLAGS=`${wprefix}get-wraster-flags --ldflags` + + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:940: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:961: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:978: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:995: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for current libwraster support""... $ac_c" 1>&6 +echo "configure:1020: checking for current libwraster support" >&5 +if eval "test \"`echo '$''{'gs_cv_have_wraster'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + wraster_check_save_header=${CPPFLAGS} +wraster_check_save_libs=${LIBS} +CPPFLAGS="${GRAPHIC_CFLAGS} ${GRAPHIC_LFLAGS} ${CPPFLAGS}" +LIBS="${GRAPHIC_LIBS} $LIBS" + +# Check for RFillImage which is only in version 2.0 or libwraster +echo $ac_n "checking for RFillImage in -lwraster""... $ac_c" 1>&6 +echo "configure:1031: checking for RFillImage in -lwraster" >&5 +ac_lib_var=`echo wraster'_'RFillImage | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lwraster $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + gs_cv_have_wraster=yes +else + echo "$ac_t""no" 1>&6 +gs_cv_have_wraster=no +fi + +if test "$gs_cv_have_wraster" = yes; then + for ac_hdr in wraster.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1076: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1086: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +gs_cv_have_wraster=no +fi +done + +fi +CPPFLAGS="${wraster_check_save_header}" +LIBS="${wraster_check_save_libs}" + +fi + +echo "$ac_t""$gs_cv_have_wraster" 1>&6 + +if test $gs_cv_have_wraster = no; then + GRAPHIC_LIBS= + GRAPHIC_CFLAGS= + GRAPHIC_LFLAGS= +fi + +#-------------------------------------------------------------------- +# Find for X windows +#-------------------------------------------------------------------- +# If the user specifically set x_include/x_libs, then assume we're +# using a special X system and discard any previous GRAPHIC_flags +set_x_paths=no +if test $gs_cv_have_wraster = no -o $x_includes != NONE; then + set_x_paths=yes +fi +# If we find X, set shell vars x_includes and x_libraries to the +# paths, otherwise set no_x=yes. +# Uses ac_ vars as temps to allow command line to override cache and checks. +# --without-x overrides everything else, but does not touch the cache. +echo $ac_n "checking for X""... $ac_c" 1>&6 +echo "configure:1141: checking for X" >&5 + +# Check whether --with-x or --without-x was given. +if test "${with_x+set}" = set; then + withval="$with_x" + : +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else +if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=NO ac_x_libraries=NO +rm -fr conftestdir +if mkdir conftestdir; then + cd conftestdir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat > Imakefile <<'EOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case "$ac_im_incroot" in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; + esac + case "$ac_im_usrlibdir" in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; + esac + fi + cd .. + rm -fr conftestdir +fi + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1208: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + # We can compile using X headers with no special include directory. +ac_x_includes= +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + # Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done +fi +rm -f conftest* +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries= +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \ + /usr/X11/lib \ + /usr/X11R6/lib \ + /usr/X11R5/lib \ + /usr/X11R4/lib \ + \ + /usr/lib/X11 \ + /usr/lib/X11R6 \ + /usr/lib/X11R5 \ + /usr/lib/X11R4 \ + \ + /usr/local/X11/lib \ + /usr/local/X11R6/lib \ + /usr/local/X11R5/lib \ + /usr/local/X11R4/lib \ + \ + /usr/local/lib/X11 \ + /usr/local/lib/X11R6 \ + /usr/local/lib/X11R5 \ + /usr/local/lib/X11R4 \ + \ + /usr/X386/lib \ + /usr/x386/lib \ + /usr/XFree86/lib/X11 \ + \ + /usr/lib \ + /usr/local/lib \ + /usr/unsupported/lib \ + /usr/athena/lib \ + /usr/local/x11r5/lib \ + /usr/lpp/Xamples/lib \ + /lib/usr/lib/X11 \ + \ + /usr/openwin/lib \ + /usr/openwin/share/lib \ + ; \ +do + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f conftest* +fi # $ac_x_libraries = NO + +if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi +fi + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + echo "$ac_t""$have_x" 1>&6 + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6 +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + cat >> confdefs.h <<\EOF +#define X_DISPLAY_MISSING 1 +EOF + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + case "`(uname -sr) 2>/dev/null`" in + "SunOS 5"*) + echo $ac_n "checking whether -R must be followed by a space""... $ac_c" 1>&6 +echo "configure:1390: checking whether -R must be followed by a space" >&5 + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_R_nospace=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_R_nospace=no +fi +rm -f conftest* + if test $ac_R_nospace = yes; then + echo "$ac_t""no" 1>&6 + X_LIBS="$X_LIBS -R$x_libraries" + else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_R_space=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_R_space=no +fi +rm -f conftest* + if test $ac_R_space = yes; then + echo "$ac_t""yes" 1>&6 + X_LIBS="$X_LIBS -R $x_libraries" + else + echo "$ac_t""neither works" 1>&6 + fi + fi + LIBS="$ac_xsave_LIBS" + esac + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And karl@cs.umb.edu says + # the Alpha needs dnet_stub (dnet does not exist). + echo $ac_n "checking for dnet_ntoa in -ldnet""... $ac_c" 1>&6 +echo "configure:1455: checking for dnet_ntoa in -ldnet" >&5 +ac_lib_var=`echo dnet'_'dnet_ntoa | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldnet $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + echo $ac_n "checking for dnet_ntoa in -ldnet_stub""... $ac_c" 1>&6 +echo "configure:1496: checking for dnet_ntoa in -ldnet_stub" >&5 +ac_lib_var=`echo dnet_stub'_'dnet_ntoa | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldnet_stub $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to dickey@clark.net. + echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 +echo "configure:1544: checking for gethostbyname" >&5 +if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) +choke me +#else +gethostbyname(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1572: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_gethostbyname=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_gethostbyname=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_gethostbyname = no; then + echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 +echo "configure:1593: checking for gethostbyname in -lnsl" >&5 +ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says simon@lia.di.epfl.ch: it contains + # gethostby* variants that don't use the nameserver (or something). + # -lsocket must be given before -lnsl if both are needed. + # We assume that if connect needs -lnsl, so does gethostbyname. + echo $ac_n "checking for connect""... $ac_c" 1>&6 +echo "configure:1642: checking for connect" >&5 +if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_connect) || defined (__stub___connect) +choke me +#else +connect(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1670: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_connect=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_connect=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_connect = no; then + echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6 +echo "configure:1691: checking for connect in -lsocket" >&5 +ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX. + echo $ac_n "checking for remove""... $ac_c" 1>&6 +echo "configure:1734: checking for remove" >&5 +if eval "test \"`echo '$''{'ac_cv_func_remove'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char remove(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_remove) || defined (__stub___remove) +choke me +#else +remove(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1762: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_remove=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_remove=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'remove`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_remove = no; then + echo $ac_n "checking for remove in -lposix""... $ac_c" 1>&6 +echo "configure:1783: checking for remove in -lposix" >&5 +ac_lib_var=`echo posix'_'remove | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lposix $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + echo $ac_n "checking for shmat""... $ac_c" 1>&6 +echo "configure:1826: checking for shmat" >&5 +if eval "test \"`echo '$''{'ac_cv_func_shmat'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shmat(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shmat) || defined (__stub___shmat) +choke me +#else +shmat(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1854: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_shmat=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_shmat=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'shmat`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_shmat = no; then + echo $ac_n "checking for shmat in -lipc""... $ac_c" 1>&6 +echo "configure:1875: checking for shmat in -lipc" >&5 +ac_lib_var=`echo ipc'_'shmat | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lipc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +else + echo "$ac_t""no" 1>&6 +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS="$LDFLAGS" + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # --interran@uluru.Stanford.EDU, kb@cs.umb.edu. + echo $ac_n "checking for IceConnectionNumber in -lICE""... $ac_c" 1>&6 +echo "configure:1927: checking for IceConnectionNumber in -lICE" >&5 +ac_lib_var=`echo ICE'_'IceConnectionNumber | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +else + echo "$ac_t""no" 1>&6 +fi + + LDFLAGS="$ac_save_LDFLAGS" + +fi + + +if test $set_x_paths = yes; then + GRAPHIC_CFLAGS="$X_CFLAGS" + GRAPHIC_LFLAGS="$X_LIBS" + GRAPHIC_LIBS="$X_EXTRA_LIBS" + + lib_save_header=${CPPFLAGS} + lib_save_libs=${LIBS} + CPPFLAGS="${GRAPHIC_CFLAGS} ${GRAPHIC_LFLAGS} ${CPPFLAGS}" + LIBS="${GRAPHIC_LIBS} ${LIBS}" + echo $ac_n "checking for main in -lXext""... $ac_c" 1>&6 +echo "configure:1981: checking for main in -lXext" >&5 +ac_lib_var=`echo Xext'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lXext $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + have_xext=1 +else + echo "$ac_t""no" 1>&6 +have_xext=0 +fi + + if test $have_xext = 1; then + GRAPHIC_LIBS="-lX11 -lXext ${GRAPHIC_LIBS}" + else + GRAPHIC_LIBS="-lX11 ${GRAPHIC_LIBS}" + fi + LIBS="${GRAPHIC_LIBS} ${LIBS}" + echo $ac_n "checking for main in -lXmu""... $ac_c" 1>&6 +echo "configure:2024: checking for main in -lXmu" >&5 +ac_lib_var=`echo Xmu'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lXmu $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + have_xmu=1 +else + echo "$ac_t""no" 1>&6 +have_xmu=0 +fi + + CPPFLAGS="${lib_save_header}" + LIBS="${lib_save_libs}" + if test $have_xmu = 1; then + GRAPHIC_LIBS="-lXmu ${GRAPHIC_LIBS}" + fi +fi +if test -r $x_includes/X11/DPS; then + GRAPHIC_CFLAGS="-I$x_includes/X11 $GRAPHIC_CFLAGS" +fi + + +#-------------------------------------------------------------------- +# Find for DPS +#-------------------------------------------------------------------- +# Check whether --with-dps_library or --without-dps_library was given. +if test "${with_dps_library+set}" = set; then + withval="$with_dps_library" + : +else + with_dps_library= +fi + +# Check whether --with-dps_include or --without-dps_include was given. +if test "${with_dps_include+set}" = set; then + withval="$with_dps_include" + : +else + with_dps_include= +fi + + +# Add the target header file directory as an include path so that the +# check for dpsNXargs.h below looks at the appropriate target includes +ORIG_CPPFLAGS=${CPPFLAGS} +if test -n "$with_dps_include"; then + GRAPHIC_CFLAGS="-I$with_dps_include $GRAPHIC_CFLAGS" +fi +if test -n "$with_dps_library"; then + GRAPHIC_LFLAGS="-L$with_dps_library $GRAPHIC_LFLAGS" +fi +CPPFLAGS="${CPPFLAGS} ${GRAPHIC_CFLAGS}" + +for ac_hdr in DPS/dpsclient.h DPS/dpsNXargs.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2106: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2116: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +# Restore back to the original +CPPFLAGS=${ORIG_CPPFLAGS} + + + +#-------------------------------------------------------------------- +# XIM support +#-------------------------------------------------------------------- +# Check whether --enable-xim or --disable-xim was given. +if test "${enable_xim+set}" = set; then + enableval="$enable_xim" + : +else + enable_xim=no +fi + +if test "x$enable_xim" = "xyes"; then + cat >> confdefs.h <<\EOF +#define USE_XIM 1 +EOF + +fi + +#-------------------------------------------------------------------- +# Extended font support +#-------------------------------------------------------------------- +WITH_XFT=no +save_header=${CPPFLAGS} +save_libs=${LIBS} +CPPFLAGS="${GRAPHIC_CFLAGS} ${GRAPHIC_LFLAGS} ${CPPFLAGS}" +LIBS="${GRAPHIC_LIBS} ${LIBS}" +echo $ac_n "checking for XftFontOpen in -lXft""... $ac_c" 1>&6 +echo "configure:2175: checking for XftFontOpen in -lXft" >&5 +ac_lib_var=`echo Xft'_'XftFontOpen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lXft $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + have_xft=yes +else + echo "$ac_t""no" 1>&6 +have_xft=no +fi + +ac_safe=`echo "X11/Xft/Xft.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for X11/Xft/Xft.h""... $ac_c" 1>&6 +echo "configure:2217: checking for X11/Xft/Xft.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2227: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + +if test "$have_xft" = yes -a "$ac_cv_header_X11_Xft_Xft_h" = yes; then + GRAPHIC_LIBS="-lXft ${GRAPHIC_LIBS}" + WITH_XFT=yes + cat >> confdefs.h <<\EOF +#define HAVE_XFT 1 +EOF + +fi +CPPFLAGS="${save_header}" +LIBS="${save_libs}" + + +#-------------------------------------------------------------------- +# XIM support +#-------------------------------------------------------------------- +# Check whether --enable-xim or --disable-xim was given. +if test "${enable_xim+set}" = set; then + enableval="$enable_xim" + : +else + enable_xim=yes +fi + +if test "x$enable_xim" = "xyes"; then + cat >> confdefs.h <<\EOF +#define USE_XIM 1 +EOF + +fi + +#-------------------------------------------------------------------- +# Find for JPEG +#-------------------------------------------------------------------- +# Check whether --with-jpeg_library or --without-jpeg_library was given. +if test "${with_jpeg_library+set}" = set; then + withval="$with_jpeg_library" + : +else + with_jpeg_library=/usr/local/lib +fi + +# Check whether --with-jpeg_include or --without-jpeg_include was given. +if test "${with_jpeg_include+set}" = set; then + withval="$with_jpeg_include" + : +else + with_jpeg_include=/usr/local/include +fi + + + + +if test $gs_cv_have_wraster = no -o $set_x_paths = yes; then + jpeg_check_lib_save_header=${CPPFLAGS} +CPPFLAGS="-L${with_jpeg_library} -I${with_jpeg_include} ${CPPFLAGS}" + +echo $ac_n "checking for jpeg_destroy_decompress in -ljpeg""... $ac_c" 1>&6 +echo "configure:2305: checking for jpeg_destroy_decompress in -ljpeg" >&5 +ac_lib_var=`echo jpeg'_'jpeg_destroy_decompress | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ljpeg $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + jpeg_ok=yes +else + echo "$ac_t""no" 1>&6 +jpeg_ok=no +fi + +if test "$jpeg_ok" = yes; then + echo $ac_n "checking for jpeglib.h""... $ac_c" 1>&6 +echo "configure:2347: checking for jpeglib.h" >&5 + cat > conftest.$ac_ext < + #undef PACKAGE + #undef VERSION + #undef HAVE_STDLIB_H + #include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2358: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + jpeg_ok=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + jpeg_ok=no +fi +rm -f conftest* + echo "$ac_t""$jpeg_ok" 1>&6 + + if test "$jpeg_ok" = yes; then + GRAPHIC_LFLAGS="-L${with_jpeg_library} $GRAPHIC_LFLAGS" + GRAPHIC_CFLAGS="-I${with_jpeg_library} $GRAPHIC_CFLAGS" + fi +fi +CPPFLAGS="${jpeg_check_lib_save_header}" +fi + +#-------------------------------------------------------------------- +# Find for TIFF +#-------------------------------------------------------------------- +# Check whether --with-tiff_library or --without-tiff_library was given. +if test "${with_tiff_library+set}" = set; then + withval="$with_tiff_library" + : +else + with_tiff_library=/usr/local/lib +fi + +# Check whether --with-tiff_include or --without-tiff_include was given. +if test "${with_tiff_include+set}" = set; then + withval="$with_tiff_include" + : +else + with_tiff_include=/usr/local/include +fi + + + + +if test $gs_cv_have_wraster = no -o $set_x_paths = yes; then + tiff_check_lib_save_header=${CPPFLAGS} +tiff_check_lib_save_libs=${LIBS} +CPPFLAGS="-L${with_tiff_library} ${JPEG_LIB} -I${with_tiff_include} ${JPEG_INCLUDE} ${CPPFLAGS}" +echo $ac_n "checking for main in -lz""... $ac_c" 1>&6 +echo "configure:2408: checking for main in -lz" >&5 +ac_lib_var=`echo z'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lz $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LIBZ=1 +else + echo "$ac_t""no" 1>&6 +HAVE_LIBZ=0 +fi + + +echo $ac_n "checking for -ltiff without -ljpeg nor -lz""... $ac_c" 1>&6 +echo "configure:2446: checking for -ltiff without -ljpeg nor -lz" >&5 +LIBS="-ltiff -lm $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + jpeg_notneeded=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + jpeg_notneeded=no +fi +rm -f conftest* +echo "$ac_t""$jpeg_notneeded" 1>&6 +LIBS=${tiff_check_lib_save_libs} +JPEG= +if test "$jpeg_notneeded" = no; then + JPEG=-ljpeg +fi + +if test $HAVE_LIBZ = 1; then + echo $ac_n "checking for -ltiff without -lz""... $ac_c" 1>&6 +echo "configure:2475: checking for -ltiff without -lz" >&5 + LIBS="-ltiff $JPEG -lm $LIBS" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + libz_notneeded=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + libz_notneeded=no +fi +rm -f conftest* + echo "$ac_t""$libz_notneeded" 1>&6 + LIBS=${tiff_check_lib_save_libs} + if test "$libz_notneeded" = no; then + JPEG="$JPEG -lz" + fi +fi + +echo $ac_n "checking for TIFFReadScanline in -ltiff""... $ac_c" 1>&6 +echo "configure:2503: checking for TIFFReadScanline in -ltiff" >&5 +ac_lib_var=`echo tiff'_'TIFFReadScanline | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ltiff $JPEG -lm $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + tiff_ok=yes +else + echo "$ac_t""no" 1>&6 +tiff_ok=no + echo "configure: warning: Cannot find libtiff" 1>&2 + echo "* The GUI library reqiures the TIFF library" + echo "* Use --with-tiff-library to specify the tiff library" + echo "* directory if it is not in the usual place(s)" + echo "* You may also have to specify --with-jpeg-library if the jpeg" + echo "* Library is needed by tiff" + if test "x$CONFIGURING_CORE_LIBRARIES" != x; then + { echo "configure: error: You must have proper libraries installed to compile core" 1>&2; exit 1; } + fi +fi + +if test "$tiff_ok" = yes; then + ac_safe=`echo "tiffio.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for tiffio.h""... $ac_c" 1>&6 +echo "configure:2555: checking for tiffio.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2565: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + tiff_ok=yes +else + echo "$ac_t""no" 1>&6 +tiff_ok=no +fi + + if test "$tiff_ok" = yes; then + GRAPHIC_LFLAGS="-L${with_tiff_library} $GRAPHIC_LFLAGS" + GRAPHIC_CFLAGS="-I${with_tiff_library} $GRAPHIC_CFLAGS" + GRAPHIC_LIBS="-ltiff $JPEG $GRAPHIC_LIBS" + else + echo "configure: warning: Cannot find libtiff header tiffio" 1>&2 + echo "* The GUI library requres the TIFF library" + echo "* Use --with-tiff-include to specify the tiff header directory" + echo "* if it is not in the usual place(s)" + if test "x$CONFIGURING_CORE_LIBRARIES" != x; then + { echo "configure: error: You must have proper libraries installed to compile core" 1>&2; exit 1; } + fi + fi +fi +CPPFLAGS="${tiff_check_lib_save_header}" +fi + +save_CPPFLAGS=${CPPFLAGS} +CPPFLAGS="$CPPFLAGS $GRAPHIC_CFLAGS" +ac_safe=`echo "X11/extensions/XShm.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for X11/extensions/XShm.h""... $ac_c" 1>&6 +echo "configure:2608: checking for X11/extensions/XShm.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2618: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define XSHM 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +CPPFLAGS="$save_CPPFLAGS" + +WITH_WRASTER=no +if test $gs_cv_have_wraster = yes -a $set_x_paths = no; then + cat >> confdefs.h <<\EOF +#define WITH_WRASTER 1 +EOF + + WITH_WRASTER=yes +fi + + + + + +#-------------------------------------------------------------------- +# Which projects should we build? +#-------------------------------------------------------------------- +exlib=no +exdps=no +ex11=no +ewin32=no +ewinlib=no +if test $gs_cv_have_wraster = yes -o $x_includes != NONE; then + exlib=yes + ex11=yes +fi + +# Check whether --enable-xlib or --disable-xlib was given. +if test "${enable_xlib+set}" = set; then + enableval="$enable_xlib" + : +else + enable_xlib=$exlib +fi + +# Check whether --enable-xdps or --disable-xdps was given. +if test "${enable_xdps+set}" = set; then + enableval="$enable_xdps" + : +else + enable_xdps=$exdps +fi + +# Check whether --enable-x11 or --disable-x11 was given. +if test "${enable_x11+set}" = set; then + enableval="$enable_x11" + : +else + enable_x11=$ex11 +fi + +# Check whether --enable-win32 or --disable-win32 was given. +if test "${enable_win32+set}" = set; then + enableval="$enable_win32" + : +else + enable_xwin32=$exwin32 +fi + +# Check whether --enable-winlib or --disable-winlib was given. +if test "${enable_winlib+set}" = set; then + enableval="$enable_winlib" + : +else + enable_xwinlib=$exwinlib +fi + + +echo $ac_n "checking Backend Server""... $ac_c" 1>&6 +echo "configure:2712: checking Backend Server" >&5 +if test "x$enable_win32" = "xyes"; then + BUILD_WIN32=yes + + cat >> confdefs.h <<\EOF +#define BUILD_WIN32 1 +EOF + + echo "$ac_t""win32" 1>&6 + # Only one server allowed + enable_x11=no +fi +if test "x$enable_x11" = "xyes"; then + BUILD_X11=yes + + cat >> confdefs.h <<\EOF +#define BUILD_X11 1 +EOF + + echo "$ac_t""x11" 1>&6 +fi + +echo $ac_n "checking Backend Graphics""... $ac_c" 1>&6 +echo "configure:2735: checking Backend Graphics" >&5 +if test "x$enable_winlib" = "xyes"; then + BUILD_WINLIB=yes + + cat >> confdefs.h <<\EOF +#define BUILD_WINLIB 1 +EOF + + echo "$ac_t""win32" 1>&6 + enable_xdps=no + enable_xlib=no +fi +if test "x$enable_xdps" = "xyes"; then + BUILD_XDPS=yes + + cat >> confdefs.h <<\EOF +#define BUILD_XDPS 1 +EOF + + echo "$ac_t""xdps" 1>&6 + GRAPHIC_LIBS="-ldpstk -ldps -lpsres -lXt $X_PRE_LIBS $GRAPHIC_LIBS" + enable_xlib=no +fi +if test "x$enable_xlib" = "xyes"; then + BUILD_XLIB=yes + + cat >> confdefs.h <<\EOF +#define BUILD_XLIB 1 +EOF + + echo "$ac_t""xlib" 1>&6 +fi + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "back.make config.make config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@X_CFLAGS@%$X_CFLAGS%g +s%@X_PRE_LIBS@%$X_PRE_LIBS%g +s%@X_LIBS@%$X_LIBS%g +s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g +s%@DPS_DEFINE@%$DPS_DEFINE%g +s%@WITH_XFT@%$WITH_XFT%g +s%@WITH_WRASTER@%$WITH_WRASTER%g +s%@GRAPHIC_LIBS@%$GRAPHIC_LIBS%g +s%@GRAPHIC_CFLAGS@%$GRAPHIC_CFLAGS%g +s%@GRAPHIC_LFLAGS@%$GRAPHIC_LFLAGS%g +s%@BUILD_WIN32@%$BUILD_WIN32%g +s%@BUILD_X11@%$BUILD_X11%g +s%@BUILD_WINLIB@%$BUILD_WINLIB%g +s%@BUILD_XDPS@%$BUILD_XDPS%g +s%@BUILD_XLIB@%$BUILD_XLIB%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + + + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..d1afcbd --- /dev/null +++ b/configure.in @@ -0,0 +1,414 @@ +# configure.in for GNUstep GUI Backend +# Process this file with autoconf to produce a configure script. +# +# Copyright (C) 1996-2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. +# If not, write to the Free Software Foundation, +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +AC_INIT(back.make.in) + +if test -z "$GNUSTEP_SYSTEM_ROOT"; then + AC_MSG_ERROR(You must run the GNUstep.sh script before configuring) +fi + +#-------------------------------------------------------------------- +# Use config.guess, config.sub and install-sh provided by gnustep-make +#-------------------------------------------------------------------- +AC_CONFIG_AUX_DIR($GNUSTEP_SYSTEM_ROOT/Makefiles) + +AC_CONFIG_HEADER(config.h) + +#-------------------------------------------------------------------- +# Determine the host, build, and target systems +#-------------------------------------------------------------------- +AC_CANONICAL_SYSTEM + +#-------------------------------------------------------------------- +# The following is so that headers and custom libraries +# in the GNUstep root are used before the standard ones +#-------------------------------------------------------------------- +# Set location of GNUstep dirs for later use +GNUSTEP_HDIR=$GNUSTEP_SYSTEM_ROOT/Headers +if test "$GNUSTEP_FLATTENED" = yes; then + GNUSTEP_LDIR=$GNUSTEP_SYSTEM_ROOT/Libraries +else + clean_target_os=`$GNUSTEP_SYSTEM_ROOT/Makefiles/clean_os.sh $target_os` + clean_target_cpu=`$GNUSTEP_SYSTEM_ROOT/Makefiles/clean_cpu.sh $target_cpu` + obj_dir=$clean_target_cpu/$clean_target_os + GNUSTEP_LDIR=$GNUSTEP_SYSTEM_ROOT/Libraries/$obj_dir +fi +CPPFLAGS="$CPPFLAGS -I$GNUSTEP_HDIR" +LDFLAGS="$LDFLAGS -L$GNUSTEP_LDIR/$LIBRARY_COMBO -L$GNUSTEP_LDIR" + +AC_PROG_CC + +#-------------------------------------------------------------------- +# Look for WindowMaker's wraster library +#-------------------------------------------------------------------- +AC_ARG_WITH(wraster, + [ --with-wraster=PREFIX get-wraster-flags directory prefix]) +if test "x$with_wraster" = "x"; then + wprefix="" +else + wprefix=${with_wraster}/ +fi + +GRAPHIC_LIBS=`${wprefix}get-wraster-flags --libs` +GRAPHIC_CFLAGS=`${wprefix}get-wraster-flags --cflags` +GRAPHIC_LFLAGS=`${wprefix}get-wraster-flags --ldflags` + +AC_DEFUN(AC_CHECK_WRASTER, +[dnl +AC_MSG_CHECKING(for current libwraster support) +AC_CACHE_VAL(gs_cv_have_wraster, +[wraster_check_save_header=${CPPFLAGS} +wraster_check_save_libs=${LIBS} +CPPFLAGS="$1 $2 ${CPPFLAGS}" +LIBS="$3 $LIBS" + +# Check for RFillImage which is only in version 2.0 or libwraster +AC_CHECK_LIB(wraster, RFillImage, gs_cv_have_wraster=yes, gs_cv_have_wraster=no) +if test "$gs_cv_have_wraster" = yes; then + AC_CHECK_HEADERS(wraster.h, gs_cv_have_wraster=yes, gs_cv_have_wraster=no) +fi +CPPFLAGS="${wraster_check_save_header}" +LIBS="${wraster_check_save_libs}" +]) +AC_MSG_RESULT($gs_cv_have_wraster) +]) + +AC_CHECK_WRASTER(${GRAPHIC_CFLAGS}, ${GRAPHIC_LFLAGS}, ${GRAPHIC_LIBS}) +if test $gs_cv_have_wraster = no; then + GRAPHIC_LIBS= + GRAPHIC_CFLAGS= + GRAPHIC_LFLAGS= +fi + +#-------------------------------------------------------------------- +# Find for X windows +#-------------------------------------------------------------------- +# If the user specifically set x_include/x_libs, then assume we're +# using a special X system and discard any previous GRAPHIC_flags +set_x_paths=no +if test $gs_cv_have_wraster = no -o $x_includes != NONE; then + set_x_paths=yes +fi +AC_PATH_XTRA + +if test $set_x_paths = yes; then + GRAPHIC_CFLAGS="$X_CFLAGS" + GRAPHIC_LFLAGS="$X_LIBS" + GRAPHIC_LIBS="$X_EXTRA_LIBS" + + lib_save_header=${CPPFLAGS} + lib_save_libs=${LIBS} + CPPFLAGS="${GRAPHIC_CFLAGS} ${GRAPHIC_LFLAGS} ${CPPFLAGS}" + LIBS="${GRAPHIC_LIBS} ${LIBS}" + AC_CHECK_LIB(Xext, main, have_xext=1, have_xext=0) + if test $have_xext = 1; then + GRAPHIC_LIBS="-lX11 -lXext ${GRAPHIC_LIBS}" + else + GRAPHIC_LIBS="-lX11 ${GRAPHIC_LIBS}" + fi + LIBS="${GRAPHIC_LIBS} ${LIBS}" + AC_CHECK_LIB(Xmu, main, have_xmu=1, have_xmu=0) + CPPFLAGS="${lib_save_header}" + LIBS="${lib_save_libs}" + if test $have_xmu = 1; then + GRAPHIC_LIBS="-lXmu ${GRAPHIC_LIBS}" + fi +fi +if test -r $x_includes/X11/DPS; then + GRAPHIC_CFLAGS="-I$x_includes/X11 $GRAPHIC_CFLAGS" +fi +AC_SUBST(X_PRE_LIBS) + +#-------------------------------------------------------------------- +# Find for DPS +#-------------------------------------------------------------------- +AC_ARG_WITH(dps_library, + [ --with-dps-library=DIR DPS library file are in DIR], , + with_dps_library=) +AC_ARG_WITH(dps_include, + [ --with-dps-include=DIR DPS include files are in DIR], , + with_dps_include=) + +# Add the target header file directory as an include path so that the +# check for dpsNXargs.h below looks at the appropriate target includes +ORIG_CPPFLAGS=${CPPFLAGS} +if test -n "$with_dps_include"; then + GRAPHIC_CFLAGS="-I$with_dps_include $GRAPHIC_CFLAGS" +fi +if test -n "$with_dps_library"; then + GRAPHIC_LFLAGS="-L$with_dps_library $GRAPHIC_LFLAGS" +fi +CPPFLAGS="${CPPFLAGS} ${GRAPHIC_CFLAGS}" + +AC_HAVE_HEADERS(DPS/dpsclient.h DPS/dpsNXargs.h) + +# Restore back to the original +CPPFLAGS=${ORIG_CPPFLAGS} + +AC_SUBST(DPS_DEFINE) + +#-------------------------------------------------------------------- +# XIM support +#-------------------------------------------------------------------- +AC_ARG_ENABLE(xim, + [ --enable-xim Enable XIM support],, + enable_xim=no) +if test "x$enable_xim" = "xyes"; then + AC_DEFINE(USE_XIM) +fi + +#-------------------------------------------------------------------- +# Extended font support +#-------------------------------------------------------------------- +WITH_XFT=no +save_header=${CPPFLAGS} +save_libs=${LIBS} +CPPFLAGS="${GRAPHIC_CFLAGS} ${GRAPHIC_LFLAGS} ${CPPFLAGS}" +LIBS="${GRAPHIC_LIBS} ${LIBS}" +AC_CHECK_LIB(Xft, XftFontOpen, have_xft=yes, have_xft=no) +AC_CHECK_HEADER(X11/Xft/Xft.h) +if test "$have_xft" = yes -a "$ac_cv_header_X11_Xft_Xft_h" = yes; then + GRAPHIC_LIBS="-lXft ${GRAPHIC_LIBS}" + WITH_XFT=yes + AC_DEFINE(HAVE_XFT) +fi +CPPFLAGS="${save_header}" +LIBS="${save_libs}" +AC_SUBST(WITH_XFT) + +#-------------------------------------------------------------------- +# XIM support +#-------------------------------------------------------------------- +AC_ARG_ENABLE(xim, + [ --disable-xim Disable XIM support],, + enable_xim=yes) +if test "x$enable_xim" = "xyes"; then + AC_DEFINE(USE_XIM) +fi + +#-------------------------------------------------------------------- +# Find for JPEG +#-------------------------------------------------------------------- +AC_ARG_WITH(jpeg_library, + [ --with-jpeg-library=DIR JPEG library file are in DIR], , + with_jpeg_library=/usr/local/lib) +AC_ARG_WITH(jpeg_include, + [ --with-jpeg-include=DIR JPEG include files are in DIR], , + with_jpeg_include=/usr/local/include) + +AC_DEFUN(AC_CHECK_JPEGLIB, +[jpeg_check_lib_save_header=${CPPFLAGS} +CPPFLAGS="-L$1 -I$2 ${CPPFLAGS}" + +AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, + jpeg_ok=yes, + jpeg_ok=no) +if test "$jpeg_ok" = yes; then + AC_MSG_CHECKING([for jpeglib.h]) + AC_TRY_CPP([#include + #undef PACKAGE + #undef VERSION + #undef HAVE_STDLIB_H + #include ], + jpeg_ok=yes, + jpeg_ok=no) + AC_MSG_RESULT($jpeg_ok) + + if test "$jpeg_ok" = yes; then + GRAPHIC_LFLAGS="-L$1 $GRAPHIC_LFLAGS" + GRAPHIC_CFLAGS="-I$1 $GRAPHIC_CFLAGS" + fi +fi +CPPFLAGS="${jpeg_check_lib_save_header}"]) + +if test $gs_cv_have_wraster = no -o $set_x_paths = yes; then + AC_CHECK_JPEGLIB(${with_jpeg_library}, ${with_jpeg_include}) +fi + +#-------------------------------------------------------------------- +# Find for TIFF +#-------------------------------------------------------------------- +AC_ARG_WITH(tiff_library, + [ --with-tiff-library=DIR TIFF library file are in DIR], , + with_tiff_library=/usr/local/lib) +AC_ARG_WITH(tiff_include, + [ --with-tiff-include=DIR TIFF include files are in DIR], , + with_tiff_include=/usr/local/include) + +AC_DEFUN(AC_CHECK_TIFFLIB, +[tiff_check_lib_save_header=${CPPFLAGS} +tiff_check_lib_save_libs=${LIBS} +CPPFLAGS="-L$1 ${JPEG_LIB} -I$2 ${JPEG_INCLUDE} ${CPPFLAGS}" +AC_CHECK_LIB(z, main, HAVE_LIBZ=1, HAVE_LIBZ=0) + +AC_MSG_CHECKING(for -ltiff without -ljpeg nor -lz) +LIBS="-ltiff -lm $LIBS" +AC_TRY_LINK([char TIFFReadScanline();], [TIFFReadScanline()], + jpeg_notneeded=yes, + jpeg_notneeded=no) +AC_MSG_RESULT($jpeg_notneeded) +LIBS=${tiff_check_lib_save_libs} +JPEG= +if test "$jpeg_notneeded" = no; then + JPEG=-ljpeg +fi + +if test $HAVE_LIBZ = 1; then + AC_MSG_CHECKING(for -ltiff without -lz) + LIBS="-ltiff $JPEG -lm $LIBS" + AC_TRY_LINK([char TIFFReadScanline();], [TIFFReadScanline()], + libz_notneeded=yes, + libz_notneeded=no) + AC_MSG_RESULT($libz_notneeded) + LIBS=${tiff_check_lib_save_libs} + if test "$libz_notneeded" = no; then + JPEG="$JPEG -lz" + fi +fi + +AC_CHECK_LIB(tiff, TIFFReadScanline, + tiff_ok=yes, + tiff_ok=no + AC_MSG_WARN(Cannot find libtiff) + echo "* The GUI library reqiures the TIFF library" + echo "* Use --with-tiff-library to specify the tiff library" + echo "* directory if it is not in the usual place(s)" + echo "* You may also have to specify --with-jpeg-library if the jpeg" + echo "* Library is needed by tiff" + if test "x$CONFIGURING_CORE_LIBRARIES" != x; then + AC_MSG_ERROR(You must have proper libraries installed to compile core) + fi, + $JPEG -lm) +if test "$tiff_ok" = yes; then + AC_CHECK_HEADER(tiffio.h, + tiff_ok=yes, + tiff_ok=no) + if test "$tiff_ok" = yes; then + GRAPHIC_LFLAGS="-L$1 $GRAPHIC_LFLAGS" + GRAPHIC_CFLAGS="-I$1 $GRAPHIC_CFLAGS" + GRAPHIC_LIBS="-ltiff $JPEG $GRAPHIC_LIBS" + else + AC_MSG_WARN(Cannot find libtiff header tiffio) + echo "* The GUI library requres the TIFF library" + echo "* Use --with-tiff-include to specify the tiff header directory" + echo "* if it is not in the usual place(s)" + if test "x$CONFIGURING_CORE_LIBRARIES" != x; then + AC_MSG_ERROR(You must have proper libraries installed to compile core) + fi + fi +fi +CPPFLAGS="${tiff_check_lib_save_header}"]) + +if test $gs_cv_have_wraster = no -o $set_x_paths = yes; then + AC_CHECK_TIFFLIB(${with_tiff_library}, ${with_tiff_include}) +fi + +save_CPPFLAGS=${CPPFLAGS} +CPPFLAGS="$CPPFLAGS $GRAPHIC_CFLAGS" +AC_CHECK_HEADER(X11/extensions/XShm.h, AC_DEFINE(XSHM)) +CPPFLAGS="$save_CPPFLAGS" + +WITH_WRASTER=no +if test $gs_cv_have_wraster = yes -a $set_x_paths = no; then + AC_DEFINE(WITH_WRASTER) + WITH_WRASTER=yes +fi +AC_SUBST(WITH_WRASTER) +AC_SUBST(GRAPHIC_LIBS) +AC_SUBST(GRAPHIC_CFLAGS) +AC_SUBST(GRAPHIC_LFLAGS) + +#-------------------------------------------------------------------- +# Which projects should we build? +#-------------------------------------------------------------------- +exlib=no +exdps=no +ex11=no +ewin32=no +ewinlib=no +if test $gs_cv_have_wraster = yes -o $x_includes != NONE; then + exlib=yes + ex11=yes +fi + +AC_ARG_ENABLE(xlib, + [ --enable-xlib Build xlib graphics context],, + enable_xlib=$exlib) +AC_ARG_ENABLE(xdps, + [ --enable-xdps Build xdps graphics context],, + enable_xdps=$exdps) +AC_ARG_ENABLE(x11, + [ --enable-x11 Build x11 server],, + enable_x11=$ex11) +AC_ARG_ENABLE(win32, + [ --enable-win32 Build win32 server],, + enable_xwin32=$exwin32) +AC_ARG_ENABLE(winlib, + [ --enable-winlib Build win32 graphics context],, + enable_xwinlib=$exwinlib) + +AC_MSG_CHECKING(Backend Server) +if test "x$enable_win32" = "xyes"; then + BUILD_WIN32=yes + AC_SUBST(BUILD_WIN32) + AC_DEFINE(BUILD_WIN32) + AC_MSG_RESULT(win32) + # Only one server allowed + enable_x11=no +fi +if test "x$enable_x11" = "xyes"; then + BUILD_X11=yes + AC_SUBST(BUILD_X11) + AC_DEFINE(BUILD_X11) + AC_MSG_RESULT(x11) +fi + +AC_MSG_CHECKING(Backend Graphics) +if test "x$enable_winlib" = "xyes"; then + BUILD_WINLIB=yes + AC_SUBST(BUILD_WINLIB) + AC_DEFINE(BUILD_WINLIB) + AC_MSG_RESULT(win32) + enable_xdps=no + enable_xlib=no +fi +if test "x$enable_xdps" = "xyes"; then + BUILD_XDPS=yes + AC_SUBST(BUILD_XDPS) + AC_DEFINE(BUILD_XDPS) + AC_MSG_RESULT(xdps) + GRAPHIC_LIBS="-ldpstk -ldps -lpsres -lXt $X_PRE_LIBS $GRAPHIC_LIBS" + enable_xlib=no +fi +if test "x$enable_xlib" = "xyes"; then + BUILD_XLIB=yes + AC_SUBST(BUILD_XLIB) + AC_DEFINE(BUILD_XLIB) + AC_MSG_RESULT(xlib) +fi + +AC_OUTPUT(back.make config.make) + + diff --git a/gnustep-back-debug.spec.in b/gnustep-back-debug.spec.in new file mode 100644 index 0000000..683ed3c --- /dev/null +++ b/gnustep-back-debug.spec.in @@ -0,0 +1,8 @@ +Summary: The GNUstep backend library - debugging version +Release: 1 +Copyright: LGPL +Group: Development/Libraries +Source: ftp://ftp.gnustep.org/pub/gnustep/core/%{gs_name}-%{gs_version}.tar.gz + +%description +This package contains the debuggable version of the GNUstep backend library. diff --git a/gnustep-back.spec.in b/gnustep-back.spec.in new file mode 100644 index 0000000..45fd9fd --- /dev/null +++ b/gnustep-back.spec.in @@ -0,0 +1,13 @@ +Summary: The GNUstep backend library +Release: 1 +Copyright: LGPL +Group: Development/Libraries +Source: ftp://ftp.gnustep.org/pub/gnustep/core/%{gs_name}-%{gs_version}.tar.gz +Requires: gnustep-gui + +%description +This is a backend for the GNUstep gui Library which allows you to use +the GNUstep gui Library on an X Windows System (other backends will +be added later to allow you to use the GNUstep gui Library in other windowing +environments). This package includes development headers too. + diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..240d8f4 --- /dev/null +++ b/install-sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$cpprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0