diff options
author | Elliot Lee <sopwith@src.gnome.org> | 1997-11-24 22:37:52 +0000 |
---|---|---|
committer | Elliot Lee <sopwith@src.gnome.org> | 1997-11-24 22:37:52 +0000 |
commit | 9508b76bd2401b6b9e289b5c8ec9fc0e08909283 (patch) | |
tree | 53c88a9e5ac09e1a027e56df33bdaa66d670901b | |
download | gtk+-9508b76bd2401b6b9e289b5c8ec9fc0e08909283.tar.gz |
Initial revision
322 files changed, 132552 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000000..0858b3946f --- /dev/null +++ b/.cvsignore @@ -0,0 +1,10 @@ +*.lo +config.log +config.h +libtool +config.status +stamp-h +Makefile +gtk+.xconfig +config.cache + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..f1adbf18ab --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +Peter Mattis (petm@xcf.berkeley.edu) +Spencer Kimball (spencer@xcf.berkeley.edu) +Josh MacDonald (jmacd@xcf.berkeley.edu) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..eb685a5ec9 --- /dev/null +++ b/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +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 compile 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) 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. + + c) 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. + + d) 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 source code 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 to +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 Library 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 + + Appendix: 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. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + +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. + + <signature of Ty Coon>, 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 0000000000..a065ebef50 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter <jpaint@serv.net> + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter <jpaint@serv.net> + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter <jpaint@serv.net> + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter <jpaint@serv.net> + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter <jpaint@serv.net> + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik <timj@psynet.net> + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's <johannes@nada.kth.se> patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer <mvo@zagadka.ping.de> + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik <timj@psynet.net> + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer <mvo@zagadka.ping.de> + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis <pmattis@localhost> + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis <pmattis@localhost> + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: A path which ends in "<nothing>" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis <pmattis@localhost> + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis <pmattis@localhost> + + * gtkcolorsel.c: Add "#include <math.h>" to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis <pmattis@localhost> + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis <pmattis@localhost> + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis <pmattis@localhost> + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang <davidm@azstarnet.com> + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis <pmattis@localhost> + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis <pmattis@localhost> + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis <pmattis@localhost> + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis <pmattis@localhost> + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis <pmattis@localhost> + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis <pmattis@localhost> + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis <pmattis@localhost> + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis <pmattis@localhost> + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis <pmattis@localhost> + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis <pmattis@localhost> + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis <pmattis@localhost> + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis <pmattis@localhost> + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis <pmattis@localhost> + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 new file mode 100644 index 0000000000..a065ebef50 --- /dev/null +++ b/ChangeLog.pre-2-0 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter <jpaint@serv.net> + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter <jpaint@serv.net> + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter <jpaint@serv.net> + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter <jpaint@serv.net> + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter <jpaint@serv.net> + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik <timj@psynet.net> + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's <johannes@nada.kth.se> patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer <mvo@zagadka.ping.de> + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik <timj@psynet.net> + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer <mvo@zagadka.ping.de> + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis <pmattis@localhost> + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis <pmattis@localhost> + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: A path which ends in "<nothing>" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis <pmattis@localhost> + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis <pmattis@localhost> + + * gtkcolorsel.c: Add "#include <math.h>" to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis <pmattis@localhost> + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis <pmattis@localhost> + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis <pmattis@localhost> + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang <davidm@azstarnet.com> + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis <pmattis@localhost> + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis <pmattis@localhost> + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis <pmattis@localhost> + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis <pmattis@localhost> + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis <pmattis@localhost> + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis <pmattis@localhost> + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis <pmattis@localhost> + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis <pmattis@localhost> + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis <pmattis@localhost> + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis <pmattis@localhost> + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis <pmattis@localhost> + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis <pmattis@localhost> + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis <pmattis@localhost> + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 new file mode 100644 index 0000000000..a065ebef50 --- /dev/null +++ b/ChangeLog.pre-2-10 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter <jpaint@serv.net> + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter <jpaint@serv.net> + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter <jpaint@serv.net> + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter <jpaint@serv.net> + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter <jpaint@serv.net> + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik <timj@psynet.net> + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's <johannes@nada.kth.se> patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer <mvo@zagadka.ping.de> + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik <timj@psynet.net> + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer <mvo@zagadka.ping.de> + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis <pmattis@localhost> + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis <pmattis@localhost> + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: A path which ends in "<nothing>" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis <pmattis@localhost> + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis <pmattis@localhost> + + * gtkcolorsel.c: Add "#include <math.h>" to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis <pmattis@localhost> + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis <pmattis@localhost> + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis <pmattis@localhost> + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang <davidm@azstarnet.com> + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis <pmattis@localhost> + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis <pmattis@localhost> + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis <pmattis@localhost> + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis <pmattis@localhost> + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis <pmattis@localhost> + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis <pmattis@localhost> + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis <pmattis@localhost> + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis <pmattis@localhost> + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis <pmattis@localhost> + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis <pmattis@localhost> + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis <pmattis@localhost> + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis <pmattis@localhost> + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis <pmattis@localhost> + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 new file mode 100644 index 0000000000..a065ebef50 --- /dev/null +++ b/ChangeLog.pre-2-2 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter <jpaint@serv.net> + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter <jpaint@serv.net> + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter <jpaint@serv.net> + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter <jpaint@serv.net> + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter <jpaint@serv.net> + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik <timj@psynet.net> + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's <johannes@nada.kth.se> patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer <mvo@zagadka.ping.de> + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik <timj@psynet.net> + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer <mvo@zagadka.ping.de> + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis <pmattis@localhost> + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis <pmattis@localhost> + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: A path which ends in "<nothing>" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis <pmattis@localhost> + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis <pmattis@localhost> + + * gtkcolorsel.c: Add "#include <math.h>" to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis <pmattis@localhost> + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis <pmattis@localhost> + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis <pmattis@localhost> + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang <davidm@azstarnet.com> + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis <pmattis@localhost> + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis <pmattis@localhost> + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis <pmattis@localhost> + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis <pmattis@localhost> + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis <pmattis@localhost> + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis <pmattis@localhost> + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis <pmattis@localhost> + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis <pmattis@localhost> + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis <pmattis@localhost> + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis <pmattis@localhost> + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis <pmattis@localhost> + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis <pmattis@localhost> + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis <pmattis@localhost> + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 new file mode 100644 index 0000000000..a065ebef50 --- /dev/null +++ b/ChangeLog.pre-2-4 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter <jpaint@serv.net> + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter <jpaint@serv.net> + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter <jpaint@serv.net> + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter <jpaint@serv.net> + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter <jpaint@serv.net> + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik <timj@psynet.net> + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's <johannes@nada.kth.se> patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer <mvo@zagadka.ping.de> + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik <timj@psynet.net> + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer <mvo@zagadka.ping.de> + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis <pmattis@localhost> + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis <pmattis@localhost> + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: A path which ends in "<nothing>" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis <pmattis@localhost> + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis <pmattis@localhost> + + * gtkcolorsel.c: Add "#include <math.h>" to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis <pmattis@localhost> + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis <pmattis@localhost> + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis <pmattis@localhost> + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang <davidm@azstarnet.com> + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis <pmattis@localhost> + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis <pmattis@localhost> + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis <pmattis@localhost> + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis <pmattis@localhost> + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis <pmattis@localhost> + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis <pmattis@localhost> + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis <pmattis@localhost> + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis <pmattis@localhost> + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis <pmattis@localhost> + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis <pmattis@localhost> + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis <pmattis@localhost> + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis <pmattis@localhost> + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis <pmattis@localhost> + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 new file mode 100644 index 0000000000..a065ebef50 --- /dev/null +++ b/ChangeLog.pre-2-6 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter <jpaint@serv.net> + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter <jpaint@serv.net> + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter <jpaint@serv.net> + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter <jpaint@serv.net> + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter <jpaint@serv.net> + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik <timj@psynet.net> + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's <johannes@nada.kth.se> patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer <mvo@zagadka.ping.de> + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik <timj@psynet.net> + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer <mvo@zagadka.ping.de> + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis <pmattis@localhost> + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis <pmattis@localhost> + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: A path which ends in "<nothing>" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis <pmattis@localhost> + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis <pmattis@localhost> + + * gtkcolorsel.c: Add "#include <math.h>" to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis <pmattis@localhost> + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis <pmattis@localhost> + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis <pmattis@localhost> + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang <davidm@azstarnet.com> + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis <pmattis@localhost> + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis <pmattis@localhost> + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis <pmattis@localhost> + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis <pmattis@localhost> + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis <pmattis@localhost> + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis <pmattis@localhost> + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis <pmattis@localhost> + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis <pmattis@localhost> + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis <pmattis@localhost> + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis <pmattis@localhost> + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis <pmattis@localhost> + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis <pmattis@localhost> + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis <pmattis@localhost> + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 new file mode 100644 index 0000000000..a065ebef50 --- /dev/null +++ b/ChangeLog.pre-2-8 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter <jpaint@serv.net> + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter <jpaint@serv.net> + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter <jpaint@serv.net> + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter <jpaint@serv.net> + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter <jpaint@serv.net> + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter <jpaint@serv.net> + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter <jpaint@serv.net> + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik <timj@psynet.net> + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's <johannes@nada.kth.se> patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer <mvo@zagadka.ping.de> + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik <timj@psynet.net> + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik <timj@psynet.net> + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena <federico@bananoid.nuclecu.unam.mx> + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis <pmattis@bjork.inktomi.com> + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer <mvo@zagadka.ping.de> + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User <pmattis@bjork.inktomi.com> + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis <pmattis@localhost> + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis <pmattis@localhost> + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: A path which ends in "<nothing>" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis <pmattis@localhost> + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis <pmattis@localhost> + + * gtkcolorsel.c: Add "#include <math.h>" to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis <pmattis@localhost> + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis <pmattis@localhost> + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis <pmattis@localhost> + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang <davidm@azstarnet.com> + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis <pmattis@localhost> + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis <pmattis@localhost> + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis <pmattis@localhost> + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis <pmattis@localhost> + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis <pmattis@localhost> + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis <pmattis@localhost> + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis <pmattis@localhost> + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis <pmattis@localhost> + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis <pmattis@localhost> + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis <pmattis@localhost> + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis <pmattis@localhost> + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis <pmattis@localhost> + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis <pmattis@localhost> + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis <pmattis@localhost> + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis <pmattis@localhost> + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis <pmattis@localhost> + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis <pmattis@localhost> + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis <pmattis@localhost> + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis <pmattis@localhost> + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis <pmattis@localhost> + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis <pmattis@localhost> + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis <pmattis@localhost> + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis <pmattis@localhost> + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis <pmattis@localhost> + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis <pmattis@localhost> + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/INSTALL diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000..8f24c51eb2 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +SRC_SUBDIRS = glib gdk gtk +SUBDIRS = $(SRC_SUBDIRS) docs + +EXTRA_DIST = gtk+.prj makecopyright TODO + +.PHONY: files populate checkin release + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done + @for subdir in $(SUBDIRS); do \ + files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \ + for file in $$files; do \ + echo $$subdir/$$file; \ + done; \ + done + +populate: + @echo "populating project" + @files=`$(MAKE) files | grep -v "make\[[1-9]\]"`; prcs populate -d gtk+.prj $$files + +checkin: populate + @echo "checking in project" + @prcs checkin + +release: + $(MAKE) dist distdir=$(PACKAGE)`date +"%y%m%d"` diff --git a/README b/README new file mode 100644 index 0000000000..728cf38a54 --- /dev/null +++ b/README @@ -0,0 +1,17 @@ + +The official ftp site is: + ftp://ftp.gimp.org/pub/gtk + +Patches can be uploaded to: + ftp://ftp.gimp.org/incoming + +Anonymous CVS access for gtk+ (as well as 'gimp', 'gimp-data', and +'gnome') is available via + CVSROOT=:pserver:anonymous@cvs.gnome.org:/home/cvs +with an empty password. + +A mailing list is located at: + gtk-list@redhat.com + +To subscribe: mail -s subscribe gtk-list-request@redhat.com < /dev/null +(Send mail to gtk-list-request@redhat.com with the subject "subscribe") @@ -0,0 +1,36 @@ +Now +--- + +3. Fix focus activation of list items. Does list item activation have to be + completely reorganized? + +4. Lists should scroll to center the recently selected item if it isn't + visible. + + +The Future +---------- + +-Documentation + +-Tree widget + +-Text widget (needs to be finished) + +-Widget redrawing when the window resizes sometimes messes up. + +-Make sure a widget added to a list is a list item and a widget added + to a menu is a menu item, etc... + +-More dialogs? Print, font, etc? + +-Multiple document interface (MDI)? + +-Support another widget style? Should be possible using GtkStyle's, but + there may be some work needed to remove any style dependencies in widget + code. Maybe GtkStyle's should have 'draw_push_button', 'draw_check_button', + etc, functions to draw the various widgets. + +-OffiX drag and drop support + +-Make all widget attributes configurable after the widget is created. diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000000..be2cb542cd --- /dev/null +++ b/acconfig.h @@ -0,0 +1,47 @@ +/* acconfig.h + This file is in the public domain. + + Descriptive text for the C preprocessor macros that + the distributed Autoconf macros can define. + No software package will use all of them; autoheader copies the ones + your configure.in uses into your configuration header file templates. + + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). Although this order + can split up related entries, it makes it easier to check whether + a given entry is in the file. + + Leave the following blank line there!! Autoheader needs it. */ + + +/* Other stuff */ +#undef HAVE_IPC_H +#undef HAVE_SHM_H +#undef HAVE_XPM +#undef HAVE_XSHM_H +#undef HAVE_SYS_SELECT_H + +#undef IPC_RMID_DEFERRED_RELEASE + +#undef NO_FD_SET + +#undef RESOURCE_BASE + +#undef XINPUT_NONE +#undef XINPUT_GXI +#undef XINPUT_XFREE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Most machines will be happy with int or void. IRIX requires '...' */ +#undef SIGNAL_ARG_TYPE + +/* #undef PACKAGE */ +/* #undef VERSION */ + + +/* Leave that blank line there!! Autoheader needs it. + If you're adding to this file, keep in mind: + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). */ diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000000..9f99ab8e72 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,395 @@ +dnl aclocal.m4 generated automatically by aclocal 1.2 + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AM_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") +AC_DEFINE_UNQUOTED(VERSION, "$VERSION")) +AM_SANITY_CHECK +AC_ARG_PROGRAM +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_PROG_MAKE_SET]) + + +# serial 1 + +AC_DEFUN(AM_PROG_INSTALL, +[AC_REQUIRE([AC_PROG_INSTALL]) +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl +]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$@" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<<am_indx=1 +for am_file in <<$1>>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +# serial 17 AM_PROG_LIBTOOL +AC_DEFUN(AM_PROG_LIBTOOL, +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_RANLIB]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AM_PROG_LD]) +AC_REQUIRE([AM_PROG_NM]) +AC_REQUIRE([AC_PROG_LN_S]) + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL) + +dnl Allow the --disable-shared flag to stop us from building shared libs. +AC_ARG_ENABLE(shared, +[ --enable-shared build shared libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_shared=no +else + libtool_enable_shared=yes +fi]) +test -n "$libtool_enable_shared" && enable_shared="$libtool_enable_shared" +libtool_shared= +test "$enable_shared" = no && libtool_shared=" --disable-shared" + +dnl Allow the --disable-static flag to stop us from building static libs. +AC_ARG_ENABLE(static, +[ --enable-static build static libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_static=no +else + libtool_enable_static=yes +fi]) +test -n "$libtool_enable_static" && enable_static="$libtool_enable_static" +libtool_static= +test "$enable_static" = no && libtool_static=" --disable-static" + +libtool_flags="$libtool_shared$libtool_static" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +[case "$host" in +*-*-irix6*) + ac_save_CFLAGS="$CFLAGS" + flag_passed=no + for f in -32 -64 -n32 ABI -cckr -mips1 -mips2 -mips3 -mips4; do + case "$f" in + ABI) + test -n "$SGI_ABI" && flag_passed=yes + if test "$flag_passed" = no && test "$ac_cv_prog_gcc" = yes; then + # Choose the ABI flag according to GCC's specs. + if $CC -dumpspecs 2>&1 | sed '/^\*link:$/,/^$/!d' | egrep -e '[ ]-32' >/dev/null; then + LD="${LD-ld} -32" + else + LD="${LD-ld} -n32" + fi + fi + ;; + + *) + if echo " $CC $CFLAGS " | egrep -e "[ ]$f[ ]" > /dev/null; then + flag_passed=yes + LD="${LD-ld} $f" + fi + ;; + esac + done + CFLAGS="$ac_save_CFLAGS" + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + CFLAGS="$CFLAGS -belf" + ;; +esac] + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) +]) + +# AM_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AM_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC]) +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_SUBST(LD) +AM_PROG_LD_GNU +]) + +AC_DEFUN(AM_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AM_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AM_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[case "$NM" in +/*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +AC_SUBST(NM) +]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# serial 1 + +AC_DEFUN(AM_MAINTAINER_MODE, +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT($USE_MAINTAINER_MODE) + if test $USE_MAINTAINER_MODE = yes; then + MAINT= + else + MAINT='#M#' + fi + AC_SUBST(MAINT)dnl +] +) + + +# serial 1 + +# @defmac AC_PROG_CC_STDC +# @maindex PROG_CC_STDC +# @ovindex CC +# If the C compiler in not in ANSI C mode by default, try to add an option +# to output variable @code{CC} to make it so. This macro tries various +# options that select ANSI C on some system or another. It considers the +# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and +# handles function prototypes correctly. +# +# If you use this macro, you should check after calling it whether the C +# compiler has been set to accept ANSI C; if not, the shell variable +# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source +# code in ANSI C, you can make an un-ANSIfied copy of it by using the +# program @code{ansi2knr}, which comes with Ghostscript. +# @end defmac + +AC_DEFUN(AM_PROG_CC_STDC, +[AC_REQUIRE([AC_PROG_CC]) +AC_BEFORE([$0], [AC_C_INLINE]) +AC_BEFORE([$0], [AC_C_CONST]) +AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C) +AC_CACHE_VAL(am_cv_prog_cc_stdc, +[am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + AC_TRY_COMPILE( +[#if !defined(__STDC__) || __STDC__ != 1 +choke me +#endif +/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */ +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/stat.h> +#endif +], [ +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);};], +[am_cv_prog_cc_stdc="$ac_arg"; break]) +done +CC="$ac_save_CC" +]) +if test -z "$am_cv_prog_cc_stdc"; then + AC_MSG_RESULT([none needed]) +else + AC_MSG_RESULT($am_cv_prog_cc_stdc) +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac +]) + diff --git a/config.guess b/config.guess new file mode 100755 index 0000000000..413ed41c0f --- /dev/null +++ b/config.guess @@ -0,0 +1,883 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# +# This file 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. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner <bothner@cygnus.com>. +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <<EOF >dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[3478]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;; + 9000/8?? ) HP_ARCH=hppa1.0 ;; + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo i386-pc-cygwin32 + exit 0 ;; + i*:MINGW*:*) + echo i386-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <<EOF >dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c <<EOF +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c <<EOF +#include <features.h> +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000000..d190ec4fe9 --- /dev/null +++ b/config.h.in @@ -0,0 +1,36 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +/* Other stuff */ +#undef HAVE_IPC_H +#undef HAVE_SHM_H +#undef HAVE_XPM +#undef HAVE_XSHM_H +#undef HAVE_SYS_SELECT_H + +#undef IPC_RMID_DEFERRED_RELEASE + +#undef NO_FD_SET + +#undef RESOURCE_BASE + +#undef XINPUT_NONE +#undef XINPUT_GXI +#undef XINPUT_XFREE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* #undef PACKAGE */ +/* #undef VERSION */ diff --git a/config.sub b/config.sub new file mode 100755 index 0000000000..213a6d47d6 --- /dev/null +++ b/config.sub @@ -0,0 +1,954 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[3456]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[3456]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/configure.in b/configure.in new file mode 100644 index 0000000000..faa57edc80 --- /dev/null +++ b/configure.in @@ -0,0 +1,214 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(gdk/gdktypes.h) + +# Configure glib +AC_CONFIG_SUBDIRS(glib) + +dnl Initialize automake stuff +AM_INIT_AUTOMAKE(gtk+, 971109) + +# Specify a configuration file +AM_CONFIG_HEADER(config.h) + +dnl Initialize libtool +AM_PROG_LIBTOOL + +dnl Initialize maintainer mode +AM_MAINTAINER_MODE + +AC_CANONICAL_HOST + +AC_ARG_ENABLE(shm, [ --enable-shm support shared memory if available [default=yes]], + echo $enable_shm, enable_shm="yes") +AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]], +if eval "test x$enable_debug = xyes"; then + DEBUGFLAG="-g" +fi) +AC_ARG_ENABLE(ansi, [ --enable-ansi turn on strict ansi [default=no]], + , enable_ansi=no) + +AC_ARG_WITH(xinput, [ --with-xinput[=no/gxi/xfree] support XInput ]) + +if test -n "$DEBUGFLAG"; then + CFLAGS="$DEBUGFLAG" +else + CFLAGS="$CFLAGS -DNDEBUG" +fi + +# Build time sanity check... +AM_SANITY_CHECK + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_STDC +AC_PROG_INSTALL +AC_PROG_MAKE_SET + +if eval "test x$GCC = xyes"; then + test `echo "$CFLAGS" | grep "\-Wall" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -Wall" + fi + + if eval "test x$enable_ansi = xyes"; then + test `echo "$CFLAGS" | grep "\-ansi" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -ansi" + fi + + test `echo "$CFLAGS" | grep "\-pedantic" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -pedantic" + fi + fi +fi + +# Find the X11 include and library directories +AC_PATH_X +AC_PATH_XTRA + +if test "x$x_includes" = "x"; then + x_includes="/usr/include" +fi + +saved_cflags="$CFLAGS" +saved_ldflags="$LDFLAGS" + +CFLAGS="$X_CFLAGS" +LDFLAGS="$X_LDFLAGS $X_LIBS" + +# Checks for libraries. +# Check for the X11 library +AC_CHECK_LIB(X11, XOpenDisplay, x_libs="-lX11 $X_EXTRA_LIBS", no_x11_lib=yes, $X_EXTRA_LIBS) + +if eval "test x$enable_shm = xyes"; then + # Check for the Xext library (needed for XShm extention) + AC_CHECK_LIB(Xext, XShmAttach, x_libs="-lXext $x_libs", no_xext_lib=yes, $x_libs) +fi + +x_cflags="$X_CFLAGS" +x_ldflags="$X_LDFLAGS $X_LIBS" + +# set up things for XInput + +if eval "test x$with_xinput = xgxi -o x$with_xinput = xyes"; then + AC_DEFINE(XINPUT_GXI) + xinput_progs=gxid + x_libs="-lXi $x_libs" +elif eval "test x$with_xinput = xxfree"; then + AC_DEFINE(XINPUT_XFREE) + x_libs="-lXi $x_libs" +else + AC_DEFINE(XINPUT_NONE) +fi + + +AC_SUBST(x_cflags) +AC_SUBST(x_includes) +AC_SUBST(x_ldflags) +AC_SUBST(x_libs) +AC_SUBST(xinput_progs) + +CFLAGS="$saved_cflags" +LDFLAGS="$saved_ldflags" + +if eval "test x$enable_shm = xyes"; then + # Check for shared memory + AC_CHECK_HEADER(sys/ipc.h, AC_DEFINE(HAVE_IPC_H), no_sys_ipc=yes) + AC_CHECK_HEADER(sys/shm.h, AC_DEFINE(HAVE_SHM_H), no_sys_shm=yes) + + # Check whether shmctl IPC_RMID allowes subsequent attaches + if test "$ac_cv_header_sys_shm_h" = "yes"; then + AC_MSG_CHECKING(whether shmctl IPC_RMID allowes subsequent attaches) + AC_TRY_RUN([ + #include <sys/types.h> + #include <sys/ipc.h> + #include <sys/shm.h> + int main() + { + int id; + char *shmaddr; + id = shmget (IPC_PRIVATE, 4, IPC_CREAT | 0777); + if (id == -1) + exit (2); + shmaddr = shmat (id, 0, 0); + shmctl (id, IPC_RMID, 0); + if ((char*) shmat (id, 0, 0) == (char*) -1) + { + shmdt (shmaddr); + exit (1); + } + shmdt (shmaddr); + shmdt (shmaddr); + exit (0); + } + ], + AC_DEFINE(IPC_RMID_DEFERRED_RELEASE) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no), + AC_MSG_RESULT(assuming no)) + fi + + # Check for the X shared memory extension header file + AC_MSG_CHECKING(X11/extensions/XShm.h) + if eval "test x$no_ext_lib = xyes"; then + AC_MSG_RESULT(no) + no_xshm=yes + else + if eval "test -f $x_includes/X11/extensions/XShm.h"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XSHM_H) + else + AC_MSG_RESULT(no) + no_xshm=yes + fi + fi +fi + +# Check for private display resource base variable +AC_MSG_CHECKING(resource base field in XDisplay) +AC_CACHE_VAL(gtk_cv_display_resource_base, +[AC_TRY_RUN([ +#define XLIB_ILLEGAL_ACCESS +#include <X11/Xlib.h> + +int +main () +{ + Display *display; + + return 0; + + display->resource_base; +}], +gtk_cv_display_resource_base="resource_base", +gtk_cv_display_resource_base="private3")]) +AC_MSG_RESULT($gtk_cv_display_resource_base) +AC_DEFINE_UNQUOTED(RESOURCE_BASE, gdk_display->$gtk_cv_display_resource_base) + +# Checks for header files. +AC_HEADER_STDC + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +# Checks for library functions. +AC_TYPE_SIGNAL + +# Check for sys/select.h + +AC_MSG_CHECKING([fd_set and sys/select]) +AC_TRY_COMPILE([#include <sys/types.h>], + [fd_set readMask, writeMask;], gtk_ok=yes, gtk_ok=no) +if test $gtk_ok = no; then + AC_HEADER_EGREP(fd_mask, sys/select.h, gtk_ok=yes) + if test $gtk_ok = yes; then + AC_DEFINE(HAVE_SYS_SELECT_H) + fi +fi +AC_MSG_RESULT($gtk_ok) +if test $gtk_ok = no; then + AC_DEFINE(NO_FD_SET) +fi + +AC_OUTPUT(Makefile gtk+.xconfig docs/Makefile gdk/Makefile gtk/Makefile) diff --git a/docs/.cvsignore b/docs/.cvsignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/docs/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 0000000000..f4df2f3e3c --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1,10 @@ +## Process this file with automake to produce Makefile.in + +info_TEXINFOS = gdk.texi gtk.texi + +EXTRA_DIST = texinfo.tex macros.texi + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done diff --git a/docs/gdk.texi b/docs/gdk.texi new file mode 100644 index 0000000000..4942fe29b1 --- /dev/null +++ b/docs/gdk.texi @@ -0,0 +1,326 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename gdk.info +@settitle GDK +@setchapternewpage odd +@c %**end of header + +@set edition 1.0 +@set update-date 16 May 1996 +@set update-month May 1996 + +@ifinfo +This file documents GDK, the General Drawing Kit + +Copyright (C) 1996 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies + +@ignore +Permission is granted to process this file throught TeX and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end ifinfo + +@titlepage +@title The General Drawing Kit +@subtitle Version 1.0 +@subtitle @value{update-month} +@author by Peter Mattis + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1996 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end titlepage + +@dircategory User Interface Toolkit +@direntry +* GDK: (gdk). The General Drawing Kit +@end direntry + +@node Top, Copying, (dir), (dir) +@top The General Drawing Kit +@ifinfo +This is edition @value{edition} of the GDK documentation, +@w{@value{update-date}}. +@end ifinfo + +@menu +* Copying:: Your rights. +* Overview:: What is GDK? +* Initialization:: Initialization and exit. +* Events:: Event handling. +* Visuals:: Understanding and using visuals. +* Windows:: Creating and using windows. +* Graphics Contexts:: Creating and modifying GCs. +* Pixmaps:: Creating pixmaps. +* Images:: Creating images. +* Color:: Specifying color. +* Fonts:: Creating fonts. +* Drawing:: Drawing commands. +* XInput Support:: Using extended devices. +* Miscellany:: Other stuff. +* Examples:: Using GDK. +* Function Index:: Index of functions +* Concept Index:: Index of concepts +@end menu + +@node Copying, Overview, Top, Top +@comment node-name, next, previous, up +@chapter Copying + +GDK is @dfn{free}; this means that everyone is free to use it and free +to redestribute it on a free basis. GDK is not in the public domain; it +is copyrighted and there are restrictions on its distribution, but these +restrictions are designed to permit everything that a good cooperating +citizen would want to do. What is not allowed is to try to prevent +others from further sharing any version of GDK that they might get from +you. + +Specifically, we want to make sure that you have the right to give away +copies of GDK, that you receive source code or else can get it if you +want it, that you can change GDK or use pieces of it in new free +programs, and that you know you can do these things. + +To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of GDK, you must give the recipients all the rights that you +have. You must make sure that they, too, receive or can get the source +code. And you must tell them their rights. + +Also, for my own protection, we must make certain that everyone finds +out that there is no warranty for GDK. If GDK is modified by someone +else and passed on, we want their recipients to know that what they have +is not what we distributed, so that any problems introduced by others +will no reflect on our reputation. + +The precise conditions of the licenses for GDK are found in the General +Public Licenses that accompanies it. + + +@node Overview, Initialization, Copying, Top +@comment node-name, next, previous, up +@chapter What is GDK? +@cindex Overview + +GDK is designed as a wrapper library that lies on top of Xlib. It +performs many common and desired operations for a programmer instead +of the programmer having to explicitly ask for such functionality from +Xlib directly. For example, GDK provides a common interface to both +regular and shared memory XImage types. By doing so, an application +can nearly transparently use the fastest image type available. GDK +also provides routines for determining the best available color depth +and the best available visual which is not always the default visual +for a screen. + +@node Initialization, Events, Overview, Top +@comment node-name, next, previous, up +@chapter Initialization and exit +@cindex Initialization +@cindex Exit + +Initializing GDK is easy. Simply call @code{gdk_init} passing in the +@var{argc} and @var{argv} parameters. Exit is similarly easy. Just +call @code{gdk_exit}. + +@deftypefun void gdk_init (int *@var{argc}, char ***@var{argv}) +Initializes the GDK library. The arguments @var{argc} and @var{argv} +are scanned and any arguments that GDK recognizes are handled and +removed. The @var{argc} and @var{argv} parameters are the values +passed to @code{main} upon program invocation. +@end deftypefun + +@deftypefun void gdk_exit (int @var{errorcode}) +Exit GDK and perform any necessary cleanup. @code{gdk_exit} will call +the systems @code{exit} function passing @var{errorcode} as the +parameter. +@end deftypefun + +@example +int +main (int argc, char *argv[]) +@{ + /* Initialize GDK. */ + gdk_init (&argc, &argv); + + /* Exit from GDK...this call will never return. */ + gdk_exit (0); + + /* Keep compiler from issuing a warning */ + return 0; +@} +@end example + + +@node Events, Visuals, Initialization, Top +@comment node-name, next, previous, up +@chapter Event handling +@cindex Events + +Events are the means by which GDK lets the programmer know of user +interaction. An event is normally a button or key press or some other +indirect user action, such as a the mouse cursor entering or leaving a +window. + +There exist only a few functions for getting events and event +information. These are @code{gdk_events_pending}, +@code{gdk_event_get}, @code{gdk_events_record} and +@code{gdk_events_playback}. The latter two functions are useful for +automatic testing of a software package and should normally not be +needed in a program. + +@deftypefun gint gdk_events_pending (void) +Returns the number of events pending on the event queue. +@end deftypefun + +@deftypefun gint gdk_event_get (GdkEvent *@var{event}) +Return the next available event in the @var{event} +structure. @code{gdk_event_get} will return @code{TRUE} on success and +@code{FALSE} on failure. Success and failure is determined by whether +an event arrived before the timeout period expired. +@end deftypefun + +@deftypefun void gdk_events_record (char *@var{filename}) +Turn on recording of events. User events and certain system events will +be saved in the file named by the variable @var{filename}. This stream +of events can later be played back and ``should'' produce the same +results as when the original events were handled. However, the +programmer does need to be careful in that the state of the program must +be the same when @code{gdk_events_record} is called and when +@code{gdk_events_playback} is called. For this reason, +@code{gdk_events_record} is normally not called directly, but is instead +invoked indirectly by specifying the ``-record'' command line option. +@end deftypefun + +@deftypefun void gdk_events_playback (char *@var{filename}) +Start playback of events from a file. (See the above description of +@code{gdk_events_record}). Normally this function is not called directly +but is invoked by the ``-playback'' command line option. +@end deftypefun + +@deftypefun void gdk_events_stop (void) +Stop recording and playback of events. +@end deftypefun + +@example +void +handle_event () +@{ + GdkEvent event; + + if (gdk_event_get (&event)) + @{ + switch (event.type) + @{ + @dots{} + @} + @} +@} +@end example + + +@node Visuals, Windows, Events, Top +@comment node-name, next, previous, up +@chapter Understanding and using visuals +@cindex Visuals + +@node Windows, Graphics Contexts, Visuals, Top +@comment node-name, next, previous, up +@chapter Creating and using windows +@cindex Windows + +@node Graphics Contexts, Pixmaps, Windows, Top +@comment node-name, next, previous, up +@chapter Creating and modifying GCs +@cindex Graphics Contexts +@cindex GC + +@node Pixmaps, Images, Graphics Contexts, Top +@comment node-name, next, previous, up +@chapter Creating pixmaps +@cindex Pixmaps + +@node Images, Color, Pixmaps, Top +@comment node-name, next, previous, up +@chapter Creating images +@cindex Images + +@node Color, Fonts, Images, Top +@comment node-name, next, previous, up +@chapter Specifying color +@cindex Color + +@node Fonts, Drawing, Color, Top +@comment node-name, next, previous, up +@chapter Creating Fonts +@cindex Fonts + +@node Drawing, XInput Support, Fonts, Top +@comment node-name, next, previous, up +@chapter Drawing Commands +@cindex Drawing + +@node XInput Support, Miscellany, Drawing, Top +@comment node-name, next, previous, up +@chapter Using extended devices +@cindex Overview +@cindex Using extended device capabilities +@cindex Controlling extended devices + +@node Miscellany, Examples, XInput Support, Top +@comment node-name, next, previous, up +@chapter Other stuff +@cindex Timers +@cindex Debugging +@cindex Miscellaneous + + +@node Examples, Function Index, Miscellany, Top +@comment node-name, next, previous, up +@chapter Using GDK +@cindex Examples + + +@node Function Index, Concept Index, Examples, Top +@comment node-name, next, previous, up +@unnumbered Variable Index + +@printindex fn + +@node Concept Index, , Function Index, Top +@comment node-name, next, previous, up +@unnumbered Concept Index + +@printindex cp + +@summarycontents +@contents +@bye diff --git a/docs/gtk.texi b/docs/gtk.texi new file mode 100644 index 0000000000..93daf5b83a --- /dev/null +++ b/docs/gtk.texi @@ -0,0 +1,3285 @@ +\input texinfo @c -*-texinfo-*- +@c Copyright (C) 1996 by Peter Mattis. All rights reserved. +@c +@c %**start of header +@setfilename gtk.info +@settitle GTK +@setchapternewpage odd +@include macros.texi +@c %**end of header + +@set edition 1.0 +@set update-date 9 April 1997 +@set update-month April 1997 + +@ifinfo +This file documents GTK, the General Toolkit + +Copyright (C) 1996 Peter Mattis +Copyright (C) 1997 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies + +@ignore +Permission is granted to process this file throught TeX and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end ifinfo + +@titlepage +@title The General Toolkit +@subtitle Version @value{edition} +@subtitle @value{update-month} +@author by Peter Mattis + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1996 Peter Mattis +Copyright @copyright{} 1997 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end titlepage + +@dircategory User Interface Toolkit +@direntry +* GTK: (gtk). The General Toolkit +@end direntry + +@node Top, Copying, (dir), (dir) +@top The General Toolkit +@ifinfo +This is edition @value{edition} of the GTK documentation, +@w{@value{update-date}}. +@end ifinfo + +@menu +* Copying:: Your rights. +* Overview:: What is GTK? +* Objects:: Object overview. +* Signals:: Signals overview. +* Widgets:: Widget overview. +* Other Objects:: Utility objects. +* Miscellaneous:: Initialization, exit and other features. +* Examples:: Using GTK. +* Object Implementation:: Object internals. +* Signal Implementation:: Signal internals. +* Widget Implementation:: Widget internals. +* Function Index:: Index of functions. +* Concept Index:: Index of concepts. +@end menu + +@node Copying, Overview, Top, Top +@comment node-name, next, previous, up +@chapter Copying + +GTK is @dfn{free}; this means that everyone is free to use it and free +to redestribute it on a free basis. GTK is not in the public domain; it +is copyrighted and there are restrictions on its distribution, but +these restrictions are designed to permit everything that a good +cooperating citizen would want to do. What is not allowed is to try to +prevent others from further sharing any version of GTK that they might +get from you. + +Specifically, we want to make sure that you have the right to give away +copies of GTK, that you receive source code or else can get it if you +want it, that you can change GTK or use pieces of it in new free +programs, and that you know you can do these things. + +To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of GTK, you must give the recipients all the rights that you +have. You must make sure that they, too, receive or can get the source +code. And you must tell them their rights. + +Also, for my own protection, we must make certain that everyone finds +out that there is no warranty for GTK. If GTK is modified by someone +else and passed on, we want their recipients to know that what they have +is not what we distributed, so that any problems introduced by others +will no reflect on our reputation. + +The precise conditions of the licenses for GTK are found in the General +Public Licenses that accompanies it. + + +@node Overview, Objects, Copying, Top +@comment node-name, next, previous, up +@chapter What is GTK? +@cindex Overview + +GTK is a library for creating graphical user interfaces similar to the +Motif ``look and feel''. It is designed to be small and efficient, but +still flexible enough to allow the programmer freedom in the interfaces +created. GTK allows the programmer to use a variety of standard user +interface widgets (@pxref{Widgets}) such as push, radio and check +buttons, menus, lists and frames. It also provides several ``container'' +widgets which can be used to control the layout of the user interface +elements. + +GTK provides some unique features. (At least, I know of no other widget +library which provides them). For example, a button does not contain a +label, it contains a child widget, which in most instances will be a +label. However, the child widget can also be a pixmap, image or any +combination possible the programmer desires. This flexibility is adhered +to throughout the library. + + +@node Objects, Signals, Overview, Top +@comment node-name, next, previous, up +@chapter Object Overview +@cindex Objects + +GTK implements a semi-simple class mechanism and an associated class +hierarchy for widgets and several other useful objects. The GtkObject +type is the root of the class hierarchy. It provides a few items needed +by all classes, the foundation for the signal (@pxref{Signals}) +mechanism and the ``destroy'' method. + +The class hierarchy is defined by a type hierarchy. This hierarchy +allows queries to be made in regards to a type. The basic query that can +be performed is asking whether a given type has an ``is a'' relation +with another type. For instance, it is common to ask whether a general +widget pointer is a type of specific widget so that runtime sanity +checks can be made. + +@section Type utility functions + +The @code{GtkTypeInfo} structure is used to communicate information to +@code{gtk_type_unique} as opposed to passing in large numbers of +parameters. + +@example +typedef struct _GtkTypeInfo GtkTypeInfo; + +struct _GtkTypeInfo +@{ + gchar *type_name; + guint object_size; + guint class_size; + GtkClassInitFunc class_init_func; + GtkObjectInitFunc object_init_func; + GtkValueInitFunc value_init_func; +@} +@end example + +@itemize @bullet +@item +The @code{type_name} field refers to the name of the type. It is +convention for the type name to be the same as the C structure type. For +example, the type name of the @code{GtkObject} structure is +``GtkObject''. + +@item +The @code{object_size} field refers to the size in bytes of the C +structure. The easiest (and portable) means of computing this size is by +using the C @code{sizeof} operator. For instance, the sizeof of the +@code{GtkObject} structure is computed by doing @code{sizeof +(GtkObject)}. + +@item +The @code{class_size} field refers to the size in bytes of the C +structure for the class. Again, the @code{sizeof} operator should be +used to compute this value. + +@item +The @code{class_init_func} field is a callback which is used by the type +mechanism to initialize class specific fields. The single argument this +function takes is a pointer to a class structure. + +@item +The @code{object_init_func} field is a callback which is used by the +type mechanism to initialize object specific fields. The single argument +this functions takes is a pointer to an object structure. + +@item +The @code{value_init_func} field is a callback which is used by the type +mechanism to initialize object stack value types. (FIXME: unfinished). +@end itemize + +@deftypefun guint gtk_type_unique (guint @var{parent_type}, GtkTypeInfo *@var{type_info}) +The @var{parent_type} is simply the value of the new types parent +type. If @var{parent_type} is 0, then the new type is the root of the +type hierarchy. @var{type_info} is a pointer to a structure which +contains necessary information for construction of the new +type. Specifically, the @code{type_name}, @code{object_size} and +@code{class_size} fields are required. The @code{class_init_func}, +@code{object_init_func} and @code{value_init_func} fields may be NULL. +@end deftypefun + +@deftypefun gchar* gtk_type_name (guint @var{type}) +The returned string is the name of @var{type} as specified to +@code{gtk_type_unique}. +@end deftypefun + +@deftypefun guint gtk_type_from_name (guchar *@var{name}) +Return the type associated with @var{name}. If there is no type +associated with @var{name}, then 0 will be returned. +@end deftypefun + +@deftypefun guint gtk_type_parent (guint @var{type}) +Returns the parent type of @var{type} or 0 if @var{type} is the root of +the type hierarchy. +@end deftypefun + +@deftypefun gpointer gtk_type_class (guint @var{type}) +Returns the initialized class structure for @var{type}. The class +structure is actually created and initialized the first time it is +needed. If creation and initialization occurs, the @code{class_size} +field of the @code{GtkTypeInfo} structure used to initialize this type +is used to determine how large the class structure is. The +@code{class_init_func} field from the @code{GtkTypeInfo} structure is +called for all the members in the types ancestry, including the +type. The order of this invocation proceeds from the root on down. For +example, the @code{GtkWidgetClass} is first initialized as an +@code{GtkObjectClass} by the object class initialization routine and +then by the widget class initialization routine. This allows the widget +class initialization routine to override values set by the object class +initialization routine. The returned structure is shared by all objects +of @var{type} and, as such, should not be modified. +@end deftypefun + +@deftypefun gpointer gtk_type_new (guint @var{type}) +Returns a new instance of an @var{type} object. The object structure is +created and initialized similarly to the class structure (as described +above). The @code{object_size} and @code{object_init_func} fields of the +@code{GtkTypeInfo} structure are used to determine the objects allocated +size and the object specific initialization routine. Similarly to the +class initialization, all the object initialization routines from the +root on down to the particular type being created are invoked. +@end deftypefun + +@deftypefun void gtk_type_describe_heritage (guint @var{type}) +Prints the type heritage for @var{type}. The heritage for a type +includes the type and all its parent types up the type tree. +@end deftypefun + +@deftypefun void gtk_type_describe_tree (guint @var{type}, gint @var{show_size}) +Prints the type tree which starts at @var{type}. @var{show_size} is a +boolean which determines whether type sizes are printed. +@end deftypefun + +@deftypefun gint gtk_type_is_a (guint @var{type}, guint @var{is_a_type}) +A predicate function which determines whether the relation @var{type} +is_a @var{is_a_type} is true. +@end deftypefun + +@section Object functions + +The GtkObject type is the root of the type hierarchy used by GTK. It +provides a minimal set of fields used to implement the actual +object, class and signal mechanisms, as well as several utility routines +which make dealing with objects easier. + +For the adventurous, see @ref{Object Implementation}. + +@deftypefun guint gtk_object_get_type (void) +Returns the @code{GtkObject} type identifier. +@end deftypefun + +@deftypefun void gtk_object_class_add_signals (GtkObjectClass *@var{class}, gint *@var{signals}, gint @var{nsignals}) +Adds @var{signals} to the @code{signals} field in the GtkObjectClass +structure @var{class}. @xref{Signals}. +@end deftypefun + +@deftypefun void gtk_object_destroy (GtkObject *@var{object}) +Performs checks to make sure it is alright to destroy @var{object} and +then emits the @code{destroy} signal. The check which is performed is to +make sure @var{object} is not already processing another signal. If this +were the case then destroying the object immediately would undoubtedly +cause problems as the other signal would not be able to tell the object +was destroyed. The solution is that if @var{object} is processing another +signal we mark @var{object} is needing to be destroyed. When we finish +processing of the other signal we check whether the object needs to be +destroyed. +@end deftypefun + +The GtkObject type provides a mechanism for associating arbitrary +amounts of data with an object. The data is associated with the object +using a character string key. The functions @code{gtk_object_set_data}, +@code{gtk_object_get_data}, and @code{gtk_object_remove_data} are the +interface to this mechanism. Two other routines, +@code{gtk_object_set_user_data} and @code{gtk_object_get_user_data}, +exist as convenience functions which simply use the same mechanism. + +@deftypefun void gtk_object_set_data (GtkObject *@var{object}, const char *@var{key}, gpointer @var{data}) +Associate @var{data} with @var{key} in the data list of @var{object}. +@end deftypefun + +@deftypefun gpointer gtk_object_get_data (GtkObject *@var{object}, const char *@var{key}) +Retrieve the data associated with @var{key} in the data list of @var{object}. +@end deftypefun + +@deftypefun void gtk_object_remove_data (GtkObject *@var{object}, const char *@var{key}) +Remove the data associated with @var{key} in the data list of @var{object}. +@end deftypefun + +@deftypefun void gtk_object_set_user_data (GtkObject *@var{object}, gpointer @var{data}) +Sets @var{data} into the @code{user_data} field of @var{object}. +@end deftypefun + +@deftypefun gpointer gtk_object_get_user_data (GtkObject *@var{object}) +Returns the @code{user_data} field of @var{object}. +@end deftypefun + +The GtkObject type also provides a mechanism for specifying +initialization values for fields. This general mechanism is called +object value stacks. The reason for using value stacks is that they can +simplify the life of the programmer. For instance, by default widgets +are non-visible when created. However, the ``visible'' value for widgets +may be specified so that widgets are made visible when created. (FIXME: +unfinished). + +@deftypefun void gtk_object_value_stack_new (guint @var{object_type}, const gchar *@var{value_id}, GtkParamType @var{value_type}) +@end deftypefun + +@deftypefun void gtk_object_push_value (guint @var{object_type}, const gchar *@var{value_id}, @dots{}) +Push a value on the value stack specified by @var{object_type} and +@var{value_id}. The type of value is implicitly given in the context of +@var{object_type} and @var{value_id}. (That is, it is not specified +explicitly in the function call). Only a single extra argument is +expected which is the data which is to be placed on the stack. +@end deftypefun + +@deftypefun void gtk_object_pop_value (guint @var{object_type}, const gchar *@var{value_id}) +Pop a value of the value stack specified by @var{object_type} and +@var{value_id}. +@end deftypefun + +@deftypefun gint gtk_object_peek_value (guint @var{object_type}, const gchar *@var{value_id}, gpointer @var{data}) +Peek at the value on the top of the value stack specified by +@var{object_type} and @var{value_id}. The @var{data} argument is +interpreted as the location of where to place the ``peeked'' data. For +instance, if the peeked data is of type @code{GTK_PARAM_POINTER}, then +@var{data} will be a pointer to a pointer. If the value stack is empty +or does not exist or an error occurs, @code{gtk_object_peek_value} will +return @code{FALSE}. On success it will return @code{TRUE}. +@end deftypefun + + +@node Signals, Widgets, Objects, Top +@comment node-name, next, previous, up +@chapter Signals Overview +@cindex Signals + +Signals are GTK's method for objects to perform callbacks. A signal is +an event which occurs upon an object. The programmer can connect to a +signal of an object which involves specifying a function to be called +when that signal is emitted in the specified object. + +When a signal is emitted, both the class function associated with the +signal (when it was defined) and all signal handlers installed for that +signal on the particular object emitting the signal are called. The +widget programmer can specify whether the class function is to be called +before after or both before and after the signal handlers installed by +the widget user. The widget user can, however, specify that their signal +handler is to be run after the class function (using the ``_after'' +signal connection routines). Any signal handling function can emit the +same signal on the same object while it is running causing that signal +emittion to either restart or to run recursively. Additionally, signal +emittion can be terminated prematurely. While both such abilities are +rarely used, they do allow for greater flexibility in regards to +signals. For instance, a programmer can attach to the key press event +signal and intercept all tab key presses from a widget. This particular +example is used in the file selection dialog to implement tab completion +of filenames and prevent the entry widget from inserting the tab into +its buffer. + +Signals are selected using either an integer identifier or a character +string name. It is convention to name the signal the same as the class +function which is associated with it. There are two versions of most of +the signal functions, one which takes an integer identifier and one +which takes a character string name for the signal. + +@deftypefun gint gtk_signal_new (gchar *@var{name}, GtkSignalRunType @var{run_type}, gint @var{object_type}, gint @var{function_offset}, GtkSignalMarsahller @var{marshaller}, GtkParamType @var{return_val}, gint @var{nparams}, @dots{}) +Create a new signal and give it the character string identifier +@var{name}. @var{name} needs to be unique in the context of +@var{object_type}'s branch of the class hierarchy. That is, +@var{object_type} cannot create a signal type with the same name as a +signal type created by one of its parent types. + +@var{run_type} specifies whether the class function should be run before +(@code{GTK_RUN_FIRST}), after (@code{GTK_RUN_LAST}) or both before and +after normal signal handlers (@code{GTK_RUN_BOTH}). Additionally, the +@code{GTK_RUN_NO_RECURSE} value can be or'ed with any of those values to +specify that the signal should not be recursive. By default, emitting +the same signal on the same widget will cause the signal to be emitted +twice. However, if the @code{GTK_RUN_NO_RECURSE} flag is specified, +emitting the same signal on the same widget will cause the current +signal emittion to be restarted. This allows the widget programmer to +specify the semantics of signal emittion on a per signal +basis. (The @code{GTK_RUN_NO_RECURSE} flag is used by the GtkAdjustment +widget). + +The @var{function_offset} is the byte offset from the start of the class +structure to the class function field within the class structure. The +easiest means to compute this offset is by using the +@code{GTK_SIGNAL_OFFSET} macro which takes the class structure type as +the first argument and the field as the second argument. For example, +@code{GTK_SIGNAL_OFFSET (GtkObjectClass, destroy)} will give the offset +of the @code{destroy} class function within the +@code{GtkObjectClass}. Note: An offset is specified instead of an +absolute location since there will be multiple instances of a class +structure being referenced. (The @code{GtkWidgetClass} structure ``is +a'' @code{GtkObjectClass} structure, etc.) + +The @var{marshaller} function is used to invoke a signal handler. Since +signal handlers may take different parameters and return values and a +general mechanism for invoking them is not apparent, the approach of +making the signal creator responsible for invoking the signal handler +was taken. (FIXME: unfinished). + +The @var{return_val} and @var{nparams} and the remaining arguments +specify the return value and the arguments to the signal handler +respectively. Note: There is an implicit first argument to every signal +handler which is the widget the signal has been emitted from. The +variable argument list (@var{@dots{}}) specifies the types of the +arguments. These can be one of @code{GTK_PARAM_CHAR}, +@code{GTK_PARAM_SHORT}, @code{GTK_PARAM_INT}, @code{GTK_PARAM_LONG}, +@code{GTK_PARAM_POINTER} or @code{GTK_PARAM_FUNCTION}. It is undefined +to specify @code{GTK_PARAM_NONE} as an argument type, however it is ok +to use @code{GTK_PARAM_NONE} for @var{return_val}. (This corresponds to +returning a @code{void}). + +@code{gtk_signal_new} returns the integer identifier of the newly +created signal. Signal identifiers start numbering at 1 and increase +upwards. A value of -1 will be returned if an error occurs. + +@strong{Note:} @code{gtk_signal_new} is only needed by widget writers. A +normal user of GTK will never needed to invoke this function. +@end deftypefun + +@deftypefun gint gtk_signal_lookup (gchar *@var{name}, gint @var{object_type}) +Returns the integer identifier for the signal referenced by @var{name} +and @var{object_type}. If @var{object_type} does not define the signal +@var{name}, then the signal is looked for in @var{object_type}'s parent +type recursively. +@end deftypefun + +@deftypefun gint gtk_signal_emit (GtkObject *@var{object}, gint @var{signal_type}, @dots{}) +Emit the signal specified by the integer identifier @var{signal_type} +from @var{object}. If an error occurs, @code{gtk_signal_emit} will +return @code{FALSE} and will return @code{TRUE} on success. The signal +definition determines the parameters passed in the variable argument +list (@code{@dots{}}). For example, if the signal is defined as: + +@example + gint (* event) (GtkWidget *widget, GdkEvent *event); +@end example + +Then a call to emit the ``event'' signal would look like: + +@example + GdkEvent event; + gint return_val; + @dots{} + gtk_signal_emit (some_object, + gtk_signal_lookup ("event", + GTK_OBJECT_TYPE (some_object)), + &event, &return_val); +@end example + +Notice that the @code{widget} argument is implicit in that the first +argument to every signal is a type derived from @code{GtkObject}. The +@var{return_val} argument is actually a pointer to the return value type +since the signal mechanism needs to be able to place the return value in +an actual location. And lastly, the @code{gtk_signal_lookup} call is +normally avoided by using the @code{gtk_signal_emit_by_name} function +instead. @code{gtk_signal_emit} is normally used internally by widgets +which know the signal identifier (since they defined the signal) and can +therefore side-step the cost of calling @code{gtk_signal_lookup}. +@end deftypefun + +@deftypefun gint gtk_signal_emit_by_name (GtkObject *@var{object}, gchar *@var{name}, @dots{}) +Similar to @code{gtk_signal_emit} except that the signal is referenced +by @var{name} instead of by its integer identifier. +@end deftypefun + +@deftypefun void gtk_signal_emit_stop (GtkObject *@var{object}, gint @var{signal_type}) +Stop the emission of the signal @var{signal_type} on +@var{object}. @var{signal_type} is the integer identifier for the signal +and can be determined using the function +@code{gtk_signal_lookup}. Alternatively, the function +@code{gtk_signal_emit_stop_by_name} can be used to refer to the signal +by name. Attempting to stop the emission of a signal that isn't being +emitted does nothing. +@end deftypefun + +@deftypefun void gtk_signal_emit_stop_by_name (GtkObject *@var{object}, gchar *@var{name}) +Similar to @code{gtk_signal_emit_stop} except that the signal is +referenced by @var{name} instead of by its integer identifier. +@end deftypefun + +@deftypefun gint gtk_signal_connect (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, gpointer @var{func_data}) +Connects a signal handling function to a signal emitting +object. @var{func} is connected to the signal @var{name} emitted by +@var{object}. The arguments and returns type of @var{func} should match +the arguments and return type of the signal @var{name}. However, +@var{func} may take the extra argument of @var{func_data}. Due to the C +calling convention it is ok to ignore the extra argument. (It is ok to +ignore all the arguments in fact). + +@code{gtk_signal_connect} returns an integer identifier for the +connection which can be used to refer to it in the future. Specifically +it is useful for removing the connection and/or blocking it from being +used. +@end deftypefun + +@deftypefun gint gtk_signal_connect_after (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, gpointer @var{func_data}) +Similar to @code{gtk_signal_connect} except the signal handler is +connected in the ``after'' slot. This allows a signal handler to be +guaranteed to run after other signal handlers connected to the same +signal on the same object and after the class function associated with +the signal. + +Like @code{gtk_signal_connect}, @code{gtk_signal_connect_after} returns +an integer identifier which can be used to refer to the connection. +@end deftypefun + +@deftypefun gint gtk_signal_connect_object (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, GtkObject *@var{slot_object}) +Connects @var{func} to the signal @var{name} emitted by +@var{object}. Similar to @code{gtk_signal_connect} with the difference +that @var{slot_object} is passed as the first parameter to @var{func} +instead of the signal emitting object. This can be useful for connecting +a signal emitted by one object to a signal in another object. A common +usage is to connect the ``destroy'' signal of dialog to the ``clicked'' +signal emitted by a ``close'' button in the dialog. That is, the +``clicked'' signal emitted by the button will caused the ``destroy'' +signal to be emitted for the dialog. This is also the ``right'' way to +handle closing of a dialog since the ``destroy'' signal will be sent if +the dialog is deleted using a window manager function and this enables +the two methods of closing the window to be handled by the same +mechanism. Returns an integer identifier which can be used to refer to +the connection. +@end deftypefun + +@deftypefun gint gtk_signal_connect_object_after (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, GtkObject *@var{slot_object}) +Similar to @code{gtk_signal_connect_object} except the signal handler is +connected in the ``after'' slot. This allows a signal handler to be +guaranteed to run after other signal handlers connected to the same +signal on the same object and after the class function associated with +the signal. Returns an integer identifier which can be used to refer to +the connection. +@end deftypefun + +@deftypefun void gtk_signal_disconnect (GtkObject *@var{object}, gint @var{id}) +Disconnects a signal handler from an object. The signal handler is +identified by the integer @var{id} which is returned by the +@code{gtk_signal_connect*} family of functions. +@end deftypefun + +@deftypefun void gtk_signal_disconnect_by_data (GtkObject *@var{object}, gpointer @var{data}) +Disconnects a signal handler from an object. The signal handler is +identified by the @var{data} argument specified as the @var{func_data} +argument to the @code{gtk_signal_connect*} family of functions. For the +@code{gtk_signal_connect_object*} functions, @var{data} refers to the +@var{slot_object}. + +@strong{Note:} This will remove all signal handlers connected to +@var{object} which were connected using @var{data} as their +@var{func_data} argument. Multiple signal handlers may be disconnected +with this call. +@end deftypefun + +@deftypefun void gtk_signal_handler_block (GtkObject *@var{object}, gint @var{id}) +Blocks calling of a signal handler during signal emission. The signal +handler is identified by the integer @var{id} which is returned by the +@code{gtk_signal_connect*} family of functions. If the signal is already +blocked no change is made. +@end deftypefun + +@deftypefun void gtk_signal_handler_block_by_data (GtkObject *@var{object}, gint @var{data}) +Blocks calling of a signal handler during signal emission. The signal +handler is identified by the @var{data} argument specified as the +@var{func_data} argument to the @code{gtk_signal_connect*} family of +functions. For the @code{gtk_signal_connect_object*} functions, +@var{data} refers to the @var{slot_object}. If the signal is already +blocked no change is made. + +@strong{Note:} This will block all signal handlers connected to +@var{object} which were connected using @var{data} as their +@var{func_data} argument. Multiple signal handlers may be blocked +with this call. +@end deftypefun + +@deftypefun void gtk_signal_handler_unblock (GtkObject *@var{object}, gint @var{id}) +Unblocks calling of a signal handler during signal emission. The signal +handler is identified by the integer @var{id} which is returned by the +@code{gtk_signal_connect*} family of functions. If the signal is already +unblocked no change is made. +@end deftypefun + +@deftypefun void gtk_signal_handler_unblock_by_data (GtkObject *@var{object}, gint @var{data}) +Unblocks calling of a signal handler during signal emission. The signal +handler is identified by the @var{data} argument specified as the +@var{func_data} argument to the @code{gtk_signal_connect*} family of +functions. For the @code{gtk_signal_connect_object*} functions, +@var{data} refers to the @var{slot_object}. If the signal is already +unblocked no change is made. + +@strong{Note:} This will unblock all signal handlers connected to +@var{object} which were connected using @var{data} as their +@var{func_data} argument. Multiple signal handlers may be unblocked +with this call. +@end deftypefun + +@deftypefun void gtk_signal_handlers_destroy (GtkObject *@var{object}) +Destroy all of the signal handlers connected to @var{object}. There +should normally never be reason to call this function as it is called +automatically when @var{object} is destroyed. +@end deftypefun + +@deftypefun void gtk_signal_default_marshaller (GtkObject *@var{object}, GtkSignalFunc @var{func}, gpointer @var{func_data}, GtkSignalParam *@var{params}) +@code{gtk_signal_new} requires a callback in order to actually call a +signal handler for a particular signal. The vast majority of signals are +of the particular form: + +@example + (* std_signal) (gpointer std_arg); +@end example + +@code{gtk_signal_default_marshaller} is a signal marshaller which +marshals arguments for a signal of that form. +@end deftypefun + + +@node Widgets, Other Objects, Signals, Top +@comment node-name, next, previous, up +@chapter Widget Overview +@cindex Widgets + + +Widgets are the general term used to describe user interface objects. A +widget defines a class interface that all user interface objects conform +to. This interface allows a uniform method for dealing with operations +common to all objects such as hiding and showing, size requisition and +allocation and events. + +The common interface that widgets must adhere to is described by the +GtkWidget and GtkWidgetClass structure. For the purposes of using GTK +these structures can be considered read-only and, for the most part, +opaque. + +All widget creation routines in GTK return pointers to GtkWidget +structures. In reality, all widget creation routines create structures +that can be viewed as equivalent to the GtkWidget structure, but often +have contain additional information. @xref{Object Implementation} + +The widgets available for use are implemented in a hierarchy. Several +widgets exist solely as common bases for more specific widgets. For +example, it is not possible to create a ruler widget itself, but the +ruler widget provides a base and functionality common to the horizontal +and vertical rulers. + +The available widgets (in alphabetical order): + +@menu +* GtkAlignment:: The alignment widget. +* GtkArrow:: The arrow widget. +* GtkBin:: The bin widget. +* GtkBox:: The box widget. +* GtkButton:: The button widget. +* GtkCheckButton:: The check button widget. +* GtkCheckMenuItem:: The check menu item widget. +* GtkContainer:: The container widget. +* GtkDialog:: The dialog widget. +* GtkDrawingArea:: The drawing area widget. +* GtkEntry:: The entry widget. +* GtkFileSelection:: The file selection dialog widget. +* GtkFrame:: The frame widget. +* GtkHBox:: The horizontal box widget. +* GtkHRuler:: The horizontal ruler widget. +* GtkHScale:: The horizontal scale widget. +* GtkHScrollbar:: The horizontal scrollbar widget. +* GtkHSeparator:: The horizontal separator widget. +* GtkImage:: The image widget. +* GtkItem:: The item widget. +* GtkLabel:: The label widget. +* GtkList:: The list widget. +* GtkListItem:: The list item widget. +* GtkMenu:: The menu widget. +* GtkMenuBar:: The menu bar widget. +* GtkMenuItem:: The menu item widget. +* GtkMenuShell:: The menu shell widget. +* GtkMisc:: The misc widget. +* GtkNotebook:: The notebook widget. +* GtkOptionMenu:: The option menu widget. +* GtkPixmap:: The pixmap widget. +* GtkPreview:: The preview widget. +* GtkProgressBar:: The progress bar widget. +* GtkRadioButton:: The radio button widget. +* GtkRadioMenuItem:: The radio menu item widget. +* GtkRange:: The range widget. +* GtkRuler:: The ruler widget. +* GtkScale:: The scale widget. +* GtkScrollbar:: The scrollbar widget. +* GtkScrolledWindow:: The scrolled window widget. +* GtkSeparator:: The separator widget. +* GtkTable:: The table widget. +* GtkText:: The text widget. +* GtkToggleButton:: The toggle button widget. +* GtkTree:: The tree widget. +* GtkTreeItem:: The tree item widget. +* GtkVBox:: The vertical box widget. +* GtkViewport:: The viewport widget. +* GtkVRuler:: The vertical ruler widget. +* GtkVScale:: The vertical scale widget. +* GtkVScrollbar:: The vertical scrollbar widget. +* GtkVSeparator:: The vertical separator widget. +* GtkWidget:: The base widget type. +* GtkWindow:: The window widget. +@end menu + + +@node GtkAlignment, GtkArrow, Widgets, Widgets +@comment node-name, next, previous, up +@section The alignment widget + + +@subsection Description + +The alignment widget is a container (@pxref{GtkContainer}) derived from +the bin widget (@pxref{GtkBin}). Its entire purpose is to give the +programmer flexibility in how the child it manages is positioned when a +window is resized. + +Normally, a widget is allocated at least as much size as it +requests. (@pxref{GtkContainer} for a discussion of geometry +management). When a widget is allocated more size than it requests there +is a question of how the widget should expand. By convention, most GTK +widgets expand to fill their allocated space. Sometimes this behavior is +not desired. The alignment widget allows the programmer to specify how a +widget should expand and position itself to fill the area it is +allocated. + +@subsection Options + +@defopt xscale +@defoptx yscale +The @var{xscale} and @var{yscale} options specify how to scale the child +widget. If the scale value is 0.0, the child widget is allocated exactly +the size it requested in that dimension. If the scale value is 1.0, the +child widget is allocated all of the space in a dimension. A scale value +of 1.0 for both x and y is equivalent to not using an alignment widget. +@end defopt + +@defopt xalign +@defoptx yalign +The @var{xalign} and @var{yalign} options specify how to position the +child widget when it is not allocated all the space available to it +(because the @var{xscale} and/or @var{yscale} options are less than +1.0). If an alignment value is 0.0 the widget is positioned to the left +(or top) of its allocated space. An alignment value of 1.0 positions the +widget to the right (or bottom) of its allocated space. A common usage +is to specify @var{xalign} and @var{yalign} to be 0.5 which causes the +widget to be centered within its allocated area. +@end defopt + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_alignment_get_type (void) +Returns the @code{GtkAlignment} type identifier. +@end deftypefun + +@deftypefun GtkWidget* gtk_alignment_new (gfloat @var{xalign}, gfloat @var{yalign}, gfloat @var{xscale}, gfloat @var{yscale}) +Create a new @code{GtkAlignment} object and initialize it with the +values @var{xalign}, @var{yalign}, @var{xscale} and @var{yscale}. The +new widget is returned as a pointer to a @code{GtkWidget} +object. @code{NULL} is returned on failure. +@end deftypefun + +@deftypefun void gtk_alignment_set (GtkAlignment *@var{alignment}, gfloat @var{xalign}, gfloat @var{yalign}, gfloat @var{xscale}, gfloat @var{yscale}) +Set the @var{xalign}, @var{yalign}, @var{xscale} and @var{yscale} options +of an alignment widget. It is important to not set the fields of the +@code{GtkAlignment} structure directly (or, for that matter, any type +derived from @code{GtkObject}). +@end deftypefun + +@gtkstdmacros{Alignment, ALIGNMENT} + + +@page +@node GtkArrow, GtkBin, GtkAlignment, Widgets +@comment node-name, next, previous, up +@section The arrow widget + +@subsection Description + +The arrow widget is derived from the misc widget (@pxref{GtkMisc}) and +is intended for use where a directional arrow (in one of the four +cardinal directions) is desired. As such, it has very limited +functionality and basically only draws itself in a particular direction +and with a particular shadow type. The arrow widget will expand to fill +all the space it is allocated. + +@subsection Options + +@defopt arrow_type +The @var{arrow_type} option specifies which direction the arrow will +point. It can be one of @code{GTK_ARROW_UP}, @code{GTK_ARROW_DOWN}, +@code{GTK_ARROW_LEFT} or @code{GTK_ARROW_RIGHT}. +@end defopt + +@defopt shadow_type +The @var{shadow_type} option specifies how to draw the shadow for the +arrow. Currently, only the @code{GTK_SHADOW_IN} and +@code{GTK_SHADOW_OUT} shadow types are supported for drawing +arrows. Other shadow types will cause nothing to be drawn. +@end defopt + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_arrow_get_type (void) +Returns the @code{GtkArrow} type identifier. +@end deftypefun + +@deftypefun GtkWidget* gtk_arrow_new (GtkArrowType @var{arrow_type}, GtkShadowType @var{shadow_type}) +Create a new @code{GtkArrow} object and initialize it with the values +@var{arrow_type} and @var{shadow_type}. The new widget is returned as a +pointer to a @code{GtkWidget} object. @code{NULL} is returned on +failure. +@end deftypefun + +@deftypefun void gtk_arrow_set (GtkArrow *@var{arrow}, GtkArrowType @var{arrow_type}, GtkShadowType @var{shadow_type}) +Set the @var{arrow_type} and @var{shadow_type} options of an arrow +widget. It is important to not set the fields of the @code{GtkArrow} +structure directly (or, for that matter, any type derived from +@code{GtkObject}). +@end deftypefun + +@gtkstdmacros{Arrow, ARROW} + + +@page +@node GtkBin, GtkBox, GtkArrow, Widgets +@comment node-name, next, previous, up +@section The bin widget + +@subsection Description + +The bin widget is a container (@pxref{GtkContainer}) derived from the +container widget. It is an abstract base class. That is, it is not +possible to create an actual bin widget. It exists only to provide a +base of functionality for other widgets. Specifically, the bin widget +provides a base for several other widgets that contain only a single +child. These widgets include alignments (@pxref{GtkAlignment}), frames +(@pxref{GtkFrame}), items (@pxref{GtkItem}), viewports +(@pxref{GtkViewport}) and windows (@pxref{GtkWindow}) + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_bin_get_type (void) +Returns the @code{GtkBin} type identifier. +@end deftypefun + +@gtkstdmacros{Bin, BIN} + + +@page +@node GtkBox, GtkButton, GtkBin, Widgets +@comment node-name, next, previous, up +@section The box widget + + +@subsection Description + +The box widget is a container (@pxref{GtkContainer}) derived from the +container widget. It is an abstract base class used by the horizontal +box (@pxref{GtkHBox}) and vertical box (@pxref{GtkVBox}) widgets to +provide a base of common functionality. + +A box provides an abstraction for organizing the position and size of +widgets. Widgets in a box are layed out horizontally or vertically. By +using a box widget appropriately, a programmer can control how widgets +are positioned and how they will be allocated space when a window gets +resized. + +The key attribute of boxes is that they position their children in a +single row (horizontal boxes) or column (vertical boxes). In the case of +horizontal boxes, all children are stretched vertically. The vertical +size of the box is determined by the largest vertical requisition of all +of its children. Similarly, a vertical box streches all of its children +horizontally. The horizontal size (of the vertical box) is determined by +the largest horizontal requisition of all of its children. An alignment +widget (@pxref{GtkAlignment}) can be used to control child allocation +more precisely on a per child basis. + +The second attribute of boxes is how they expand children. In the case +of a horizontal box, the main control is over how children are expanded +horizontally to fill the allocated area. (The rest of this discussion +will focus on horizontal boxes but it applies to vertical boxes as +well). + +There are two flags which can be set controlling how a widget is +expanded horizontally in a horizontal box. These are the @code{expand} +and @code{fill}. There operation is fairly simple. If @code{expand} is +set, the childs potentially allocated area will expand to fill available +space. If @code{fill} is set, the childs actual allocated area will be +its potentially allocated area. There is a difference between +the potentially area (which is the area the box widget sets aside for +the child) and the actual allocated area (which is the area the box +widget actual allocates for the widget via +@code{gtk_widget_size_allocate}). + +The allocation of space to children occurs as follows (for horizontal +boxes): +@enumerate +@item +All children are allocated at least their requested size horizontally +and the maximum requested child size vertically. + +@item +Any child with the @code{expand} flag set is allocated @code{extra_width +/ nexpand_children} extra pixels horizontally. If the @code{homogeneous} +flag was set, all children are considered to have the @code{expand} flag +set. That is, all children will be allocated the same area.The +horizontal box is a fair widget and, as such, divides up any extra +allocated space evenly among the ``expand'' children. (Those children +which have the @code{expand} flag set). The exception occurs when +@code{extra_width / nexpand_children} does not divide cleanly. The extra +space is given to the last widget. + +@item +@code{spacing} number of pixels separate each child. Note: The +separation is between the potentially allocated area for each child and +not the actual allocated area. The @code{padding} value associated with +each child causes that many pixels to be left empty to each side of the +child. + +@item +If a child has the @code{fill} flag set it is allocated its potentially +allocated area. If it does not, it is allocated its requested size +horizontally and centered within its potentially allocated area. Its +vertical allocation is still the maximum requested size of any child. + +@item +Children placed at the start of the box are placed in order of addition +to the box from left to right in the boxes allocated area.. Children +placed at the end of the box are placed in order of addition from right +to left in the boxes allocated area. +@end enumerate + +@xref{GtkHBox}, and @ref{GtkVBox}, for code examples of using horizontal +and vertical boxes. + +@subsection Options + +@c FIXME: options for GtkBox + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_box_get_type (void) +Returns the @code{GtkBox} type identifier. +@end deftypefun + +@deftypefun void gtk_box_pack_start (GtkBox *@var{box}, GtkWidget *@var{child}, gint @var{expand}, gint @var{fill}, gint @var{padding}) +Add @var{child} to the front of @var{box}. The flags @var{expand} and +@var{fill} and the padding value of @var{padding} are associated with +@var{child}. +@end deftypefun + +@deftypefun void gtk_box_pack_end (GtkBox *@var{box}, GtkWidget *@var{child}, gint @var{expand}, gint @var{fill}, gint @var{padding}) +Add @var{child} to the end of @var{box}. The flags @var{expand} and +@var{fill} and the padding value of @var{padding} are associated with +@var{child}. +@end deftypefun + +@deftypefun void gtk_box_pack_start_defaults (GtkBox *@var{box}, GtkWidget *@var{widget}) +A convenience function which is equivalent to the following: + +@example + gtk_box_pack_start (@var{box}, @var{widget}, TRUE, TRUE, 0); +@end example +@end deftypefun + +@deftypefun void gtk_box_pack_end_defaults (GtkBox *@var{box}, GtkWidget *@var{widget}) +A convenience function which is equivalent to the following: + +@example + gtk_box_pack_start (@var{box}, @var{widget}, TRUE, TRUE, 0); +@end example +@end deftypefun + +@gtkstdmacros{Box, BOX} + + +@page +@node GtkButton, GtkCheckButton, GtkBox, Widgets +@comment node-name, next, previous, up +@section The button widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkButton::pressed (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::released (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::clicked (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::enter (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::leave (GtkButton *@var{button}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_button_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_button_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_button_pressed (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_released (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_clicked (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_enter (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_leave (GtkButton *@var{button}) +@end deftypefun + +@gtkstdmacros{Button, BUTTON} + + +@page +@node GtkCheckButton, GtkCheckMenuItem, GtkButton, Widgets +@comment node-name, next, previous, up +@section The check button widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_check_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_button_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_button_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun GtkCheckButton* GTK_CHECK_BUTTON (gpointer @var{obj}) +@end deftypefun + +@deftypefun GtkCheckButtonClass* GTK_CHECK_BUTTON_CLASS (gpointer @var{class}) +@end deftypefun + +@deftypefun gint GTK_IS_CHECK_BUTTON (gpointer @var{obj}) +@end deftypefun + +@gtkstdmacros{CheckButton, CHECK_BUTTON} + + +@page +@node GtkCheckMenuItem, GtkContainer, GtkCheckButton, Widgets, +@comment node-name, next, previous, up +@section The check menu item widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkCheckMenuItem::toggled (GtkCheckMenuItem *@var{check_menu_item}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_check_menu_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_menu_item_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_menu_item_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_check_menu_item_set_state (GtkCheckMenuItem *@var{check_menu_item}, gint @var{state}) +@end deftypefun + +@deftypefun void gtk_check_menu_item_toggled (GtkCheckMenuItem *@var{check_menu_item}) +@end deftypefun + +@gtkstdmacros{CheckMenuItem, CHECK_MENU_ITEM} + + +@page +@node GtkContainer, GtkDialog, GtkCheckMenuItem, Widgets +@comment node-name, next, previous, up +@section The container widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkContainer::add (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkContainer::remove (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkContainer::need_resize (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkContainer::foreach (GtkContainer *@var{container}, GtkCallback @var{callback}, gpointer @var{callback_data}) +@end deftypefn + +@deftypefn Signal gint GtkContainer::focus (GtkContainer *@var{container}, GtkDirectionType @var{direction}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_container_get_type (void) +@end deftypefun + +@deftypefun void gtk_container_border_width (GtkContainer *@var{container}, gint @var{border_width}) +@end deftypefun + +@deftypefun void gtk_container_add (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_remove (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_disable_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun void gtk_container_enable_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun void gtk_container_block_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun void gtk_container_unblock_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun gint gtk_container_need_resize (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_check_resize (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_foreach (GtkContainer *@var{container}, GtkCallback @var{callback}, gpointer @var{callback_data}) +@end deftypefun + +@deftypefun void gtk_container_focus (GtkContainer *@var{container}, GtkDirectionType @var{direction}) +@end deftypefun + +@deftypefun GList* gtk_container_children (GtkContainer @var{container}) +@end deftypefun + +@gtkstdmacros{Container, CONTAINER} + + +@page +@node GtkDialog, GtkDrawingArea, GtkContainer, Widgets +@comment node-name, next, previous, up +@section The dialog widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_dialog_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_dialog_new (void) +@end deftypefun + +@gtkstdmacros{Dialog, DIALOG} + + +@page +@node GtkDrawingArea, GtkEntry, GtkDialog, Widgets +@comment node-name, next, previous, up +@section The drawing area widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_drawing_area_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_drawing_area_new (void) +@end deftypefun + +@deftypefun void gtk_drawing_area_size (GtkDrawingArea *@var{darea}, gint @var{width}, gint @var{height}) +@end deftypefun + +@gtkstdmacros{DrawingArea, DRAWING_AREA} + + +@page +@node GtkEntry, GtkFileSelection, GtkDrawingArea, Widgets +@comment node-name, next, previous, up +@section The entry widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkEntry::insert (GtkEntry *@var{entry}, gchar *@var{text}, gint @var{length}, gint *@var{position}) +@end deftypefn + +@deftypefn Signal void GtkEntry::delete (GtkEntry *@var{entry}, gint @var{start_pos}, gint @var{end_pos}) +@end deftypefn + +@deftypefn Signal void GtkEntry::changed (GtkEntry *@var{entry}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_entry_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_entry_new (void) +@end deftypefun + +@deftypefun void gtk_entry_set_text (GtkEntry *@var{entry}, gchar *@var{text}) +@end deftypefun + +@deftypefun void gtk_entry_append_text (GtkEntry *@var{entry}, gchar *@var{text}) +@end deftypefun + +@deftypefun void gtk_entry_prepend_text (GtkEntry *@var{entry}, gchar *@var{text}) +@end deftypefun + +@deftypefun void gtk_entry_set_position (GtkEntry *@var{entry}, gint @var{position}) +@end deftypefun + +@deftypefun gchar* gtk_entry_get_text (GtkEntry *@var{entry}) +@end deftypefun + +@gtkstdmacros{Entry, ENTRY} + + +@page +@node GtkFileSelection, GtkFrame, GtkEntry, Widgets +@comment node-name, next, previous, up +@section The file selection dialog widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_file_selection_get_Type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_file_selection_new (gchar *@var{title}) +@end deftypefun + +@deftypefun void gtk_file_selection_set_filename (GtkFileSelection *@var{filesel}, gchar *@var{filename}) +@end deftypefun + +@deftypefun gchar* gtk_file_selection_get_filename (GtkFileSelection *@var{filesel}) +@end deftypefun + +@gtkstdmacros{FileSelection, FILE_SELECTION} + + +@page +@node GtkFrame, GtkHBox, GtkFileSelection, Widgets +@comment node-name, next, previous, up +@section The frame widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_frame_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_frame_new (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_frame_set_label (GtkFrame *@var{frame}, gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_frame_set_label_align (GtkFrame *@var{frame}, gfloat @var{xalign}, gfloat @var{yalign}) +@end deftypefun + +@deftypefun void gtk_frame_set_shadow_type (GtkFrame *@var{frame}, GtkShadowType @var{type}) +@end deftypefun + +@gtkstdmacros{Frame, FRAME} + + +@page +@node GtkHBox, GtkHRuler, GtkFrame, Widgets +@comment node-name, next, previous, up +@section The horizontal box widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hbox_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hbox_new (gint @var{homogeneous}, gint @var{spacing}) +@end deftypefun + +@gtkstdmacros{HBox, HBOX} + + +@page +@node GtkHRuler, GtkHScale, GtkHBox, Widgets +@comment node-name, next, previous, up +@section The horizontal ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hruler_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hruler_new (void) +@end deftypefun + +@gtkstdmacros{HRuler, HRULER} + + +@page +@node GtkHScale, GtkHScrollbar, GtkHRuler, Widgets +@comment node-name, next, previous, up +@section The horizontal scale widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hscale_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hscale_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{HScale, HSCALE} + + +@page +@node GtkHScrollbar, GtkHSeparator, GtkHScale, Widgets +@comment node-name, next, previous, up +@section The horizontal scrollbar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hscrollbar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hscrollbar_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{HScrollbar, HSCROLLBAR} + + +@page +@node GtkHSeparator, GtkImage, GtkHScrollbar, Widgets +@comment node-name, next, previous, up +@section The horizontal separator widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hseparator_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hseparator_new (void) +@end deftypefun + +@gtkstdmacros{HSeparator, HSEPARATOR} + + +@page +@node GtkImage, GtkItem, GtkHSeparator, Widgets +@comment node-name, next, previous, up +@section The image widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_image_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_image_new (GdkImage *@var{val}) +@end deftypefun + +@deftypefun void gtk_image_set (GtkImage *@var{image}, GdkImage *@var{val}) +@end deftypefun + +@deftypefun void gtk_image_get (GtkImage *@var{image}, GdkImage **@var{val}) +@end deftypefun + +@gtkstdmacros{Image, IMAGE} + + +@page +@node GtkItem, GtkLabel, GtkImage, Widgets +@comment node-name, next, previous, up +@section The item widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkItem::select (GtkItem *@var{item}) +@end deftypefn + +@deftypefn Signal void GtkItem::deselect (GtkItem *@var{item}) +@end deftypefn + +@deftypefn Signal void GtkItem::toggle (GtkItem *@var{toggle}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_item_get_type (void) +@end deftypefun + +@deftypefun void gtk_item_select (GtkItem *@var{item}) +@end deftypefun + +@deftypefun void gtk_item_deselect (GtkItem *@var{item}) +@end deftypefun + +@deftypefun void gtk_item_toggle (GtkItem *@var{item}) +@end deftypefun + +@gtkstdmacros{Item, ITEM} + + +@page +@node GtkLabel, GtkList, GtkItem, Widgets +@comment node-name, next, previous, up +@section The label widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_label_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_label_new (GtkLabel *@var{label}, gchar *@var{str}) +@end deftypefun + +@deftypefun void gtk_label_set (GtkLabel *@var{label}, gchar *@var{str}) +@end deftypefun + +@deftypefun void gtk_label_get (GtkLabel *@var{label}, gchar **@var{str}) +@end deftypefun + +@gtkstdmacros{Label, LABEL} + + +@page +@node GtkList, GtkListItem, GtkLabel, Widgets +@comment node-name, next, previous, up +@section The list widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkList::selection_changed (GtkList *@var{list}) +@end deftypefn + +@deftypefn Signal void GtkList::select_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefn + +@deftypefn Signal void GtkList::unselect_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_list_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_list_new (void) +@end deftypefun + +@deftypefun void gtk_list_insert_items (GtkList *@var{list}, GList *@var{items}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_list_append_items (GtkList *@var{list}, GList *@var{items}) +@end deftypefun + +@deftypefun void gtk_list_prepend_items (GtkList *@var{list}, GList *@var{items}) +@end deftypefun + +@deftypefun void gtk_list_remove_items (GtkList *@var{list}, GList *@var{items}) +@end deftypefun + +@deftypefun void gtk_list_clear_items (GtkList *@var{list}, gint @var{start}, gint @var{end}) +@end deftypefun + +@deftypefun void gtk_list_select_item (GtkList *@var{list}, gint @var{item}) +@end deftypefun + +@deftypefun void gtk_list_unselect_item (GtkList *@var{list}, gint @var{item}) +@end deftypefun + +@deftypefun void gtk_list_select_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_list_unselect_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun gint gtk_list_child_position (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_list_set_selection_mode (GtkList *@var{list}, GtkSelectionMode @var{mode}) +@end deftypefun + +@gtkstdmacros{List, LIST} + + +@page +@node GtkListItem, GtkMenu, GtkList, Widgets +@comment node-name, next, previous, up +@section The list item widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_list_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_list_item_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_list_item_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_list_item_select (GtkListItem *@var{list_item}) +@end deftypefun + +@deftypefun void gtk_list_item_deselect (GtkListItem *@var{list_item}) +@end deftypefun + +@gtkstdmacros{ListItem, LIST_ITEM} + + +@page +@node GtkMenu, GtkMenuBar, GtkListItem, Widgets +@comment node-name, next, previous, up +@section The menu widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_menu_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_new (void) +@end deftypefun + +@deftypefun void gtk_menu_append (GtkMenu *@var{menu}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_prepend (GtkMenu *@var{menu}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_insert (GtkMenu *@var{menu}, GtkWidget *@var{child}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_menu_popup (GtkMenu *@var{menu}, GtkWidget *@var{parent_menu_shell}, GtkWidget *@var{parent_menu_item}, GtkMenuPositionFunc @var{func}, gpointer @var{data}, gint @var{button}) +@end deftypefun + +@deftypefun void gtk_menu_popdown (GtkMenu *@var{menu}) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_get_active (GtkMenu *@var{menu}) +@end deftypefun + +@deftypefun void gtk_menu_set_active (GtkMenu *@var{menu}) +@end deftypefun + +@deftypefun void gtk_menu_set_accelerator_table (GtkMenu *@var{menu}, GtkAcceleratorTable *@var{table}) +@end deftypefun + +@gtkstdmacros{Menu, MENU} + + +@page +@node GtkMenuBar, GtkMenuItem, GtkMenu, Widgets +@comment node-name, next, previous, up +@section The menu bar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_menu_bar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_bar_new (void) +@end deftypefun + +@deftypefun void gtk_menu_bar_append (GtkMenuBar *@var{menu_bar}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_bar_prepend (GtkMenuBar *@var{menu_bar}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_bar_insert (GtkMenuBar *@var{menu_bar}, GtkWidget *@var{child}, gint @var{position}) +@end deftypefun + +@gtkstdmacros{MenuBar, MENU_BAR} + + +@page +@node GtkMenuItem, GtkMenuShell, GtkMenuBar, Widgets +@comment node-name, next, previous, up +@section The menu item widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkMenuItem::activate (GtkMenuItem *@var{menu_item}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_menu_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_item_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_item_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_menu_item_set_submenu (GtkMenuItem *@var{menu_item}, GtkWidget *@var{submenu}) +@end deftypefun + +@deftypefun void gtk_menu_item_set_placement (GtkMenuItem *@var{menu_item}, GtkSubmenuPlacement @var{placement}) +@end deftypefun + +@deftypefun void gtk_menu_item_accelerator_size (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@deftypefun void gtk_menu_item_accelerator_text (GtkMenuItem *@var{menu_item}, gchar *@var{buffer}) +@end deftypefun + +@deftypefun void gtk_menu_item_configure (GtkMenuItem *@var{menu_item}, gint @var{show_toggle_indicator}, gint @var{show_submenu_indicator}) +@end deftypefun + +@deftypefun void gtk_menu_item_select (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@deftypefun void gtk_menu_item_deselect (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@deftypefun void gtk_menu_item_activate (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@gtkstdmacros{MenuItem, MENU_ITEM} + + +@page +@node GtkMenuShell, GtkMisc, GtkMenuItem, Widgets +@comment node-name, next, previous, up +@section The menu shell widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkMenuShell::deactivate (GtkMenuShell *@var{menu_shell}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_menu_shell_get_type (void) +@end deftypefun + +@deftypefun void gtk_menu_shell_append (GtkMenuShell *@var{menu_shell}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_shell_prepend (GtkMenuShell *@var{menu_shell}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_shell_insert (GtkMenuShell *@var{menu_shell}, GtkWidget *@var{child}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_menu_shell_deactivate (GtkMenuShell *@var{menu_shell}) +@end deftypefun + +@gtkstdmacros{MenuShell, MENU_SHELL} + + +@page +@node GtkMisc, GtkNotebook, GtkMenuShell, Widgets +@comment node-name, next, previous, up +@section The misc widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_misc_get_type (void) +@end deftypefun + +@deftypefun void gtk_misc_set_alignment (GtkMisc *@var{misc}, gfloat @var{xalign}, gfloat @var{yalign}) +@end deftypefun + +@deftypefun void gtk_misc_set_padding (GtkMisc *@var{misc}, gint @var{xpad}, gint @var{ypad}) +@end deftypefun + +@gtkstdmacros{Misc, MISC} + + +@page +@node GtkNotebook, GtkOptionMenu, GtkMisc, Widgets +@comment node-name, next, previous, up +@section The notebook widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_notebook_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_notebook_new (void) +@end deftypefun + +@deftypefun void gtk_notebook_append_page (GtkNotebook *@var{notebook}, GtkWidget *@var{child}, GtkWidget *@var{tab_label}) +@end deftypefun + +@deftypefun void gtk_notebook_prepend_page (GtkNotebook *@var{notebook}, GtkWidget *@var{child}, GtkWidget *@var{tab_label}) +@end deftypefun + +@deftypefun void gtk_notebook_insert_page (GtkNotebook *@var{notebook}, GtkWidget *@var{child}, GtkWidget *@var{tab_label}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_notebook_remove_page (GtkNotebook *@var{notebook}, gint @var{page_num}) +@end deftypefun + +@deftypefun void gtk_notebook_set_page (GtkNotebook *@var{notebook}, gint @var{page_num}) +@end deftypefun + +@deftypefun void gtk_notebook_next_page (GtkNotebook *@var{notebook}) +@end deftypefun + +@deftypefun void gtk_notebook_prev_page (GtkNotebook *@var{notebook}) +@end deftypefun + +@deftypefun void gtk_notebook_set_tab_pos (GtkNotebook *@var{notebook}, GtkPositionType @var{pos}) +@end deftypefun + +@deftypefun void gtk_notebook_set_show_tabs (GtkNotebook *@var{notebook}, gint @var{show_tabs}) +@end deftypefun + +@deftypefun void gtk_notebook_set_show_border (GtkNotebook *@var{notebook}, gint @var{show_border}) +@end deftypefun + +@gtkstdmacros{Notebook, NOTEBOOK} + + +@page +@node GtkOptionMenu, GtkPixmap, GtkNotebook, Widgets +@comment node-name, next, previous, up +@section The option menu widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_option_menu_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_option_menu_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_option_menu_get_menu (GtkOptionMenu *@var{option_menu}) +@end deftypefun + +@deftypefun void gtk_option_menu_set_menu (GtkOptionMenu *@var{option_menu}, GtkWidget *@var{menu}) +@end deftypefun + +@deftypefun void gtk_option_menu_remove_menu (GtkOptionMenu *@var{option_menu}) +@end deftypefun + +@deftypefun void gtk_option_menu_set_history (GtkOptionMenu *@var{option_menu}, gint @var{index}) +@end deftypefun + +@gtkstdmacros{OptionMenu, OPTION_MENU} + + +@page +@node GtkPixmap, GtkPreview, GtkOptionMenu, Widgets +@comment node-name, next, previous, up +@section The pixmap widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_pixmap_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_pixmap_new (GdkPixmap *@var{normal}, GdkPixmap *@var{active}, GdkPixmap *@var{prelight}, GdkPixmap *@var{selected}, GdkPixmap *@var{insensitive}) +@end deftypefun + +@deftypefun void gtk_pixmap_set (GtkPixmap *@var{pixmap}, GdkPixmap *@var{val}, GtkStateType @var{state}) +@end deftypefun + +@deftypefun void gtk_pixmap_get (GtkPixmap *@var{pixmap}, GdkPixmap **@var{val}, GtkStateType @var{state}) +@end deftypefun + +@gtkstdmacros{Pixmap, PIXMAP} + + +@page +@node GtkPreview, GtkProgressBar, GtkPixmap, Widgets +@comment node-name, next, previous, up +@section The preview widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_preview_get_type (void) +@end deftypefun + +@deftypefun void gtk_preview_uninit (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_preview_new (GtkPreviewType @var{type}) +@end deftypefun + +@deftypefun void gtk_preview_size (GtkPreview *@var{preview}, gint @var{width}, gint @var{height}) +@end deftypefun + +@deftypefun void gtk_preview_put (GtkPreview *@var{preview}, GdkWindow *@var{window}, GdkGC *@var{gc}, gint @var{srcx}, gint @var{srcy}, gint @var{destx}, gint @var{desty}, gint @var{width}, gint @var{height}) +@end deftypefun + +@deftypefun void gtk_preview_put_row (GtkPreview *@var{preview}, guchar *@var{src}, guchar *@var{dest}, gint @var{x}, gint @var{y}, gint @var{w}) +@end deftypefun + +@deftypefun void gtk_preview_draw_row (GtkPreview *@var{preview}, guchar @var{data}, gint @var{x}, gint @var{y}, gint @var{w}) +@end deftypefun + +@deftypefun void gtk_preview_set_expand (GtkPreview *@var{preview}, gint @var{expand}) +@end deftypefun + +@deftypefun void gtk_preview_set_gamma (double @var{gamma}) +@end deftypefun + +@deftypefun void gtk_preview_set_color_cube (guint @var{nred_shades}, guint @var{ngreen_shades}, guint @var{nblue_shades}, guint @var{ngray_shades}) +@end deftypefun + +@deftypefun void gtk_preview_set_install_cmap (gint @var{install_cmap}) +@end deftypefun + +@deftypefun void gtk_preview_set_reserved (gint @var{nreserved}) +@end deftypefun + +@deftypefun GdkVisual* gtk_preview_get_visual (void) +@end deftypefun + +@deftypefun GdkColormap* gtk_preview_get_cmap (void) +@end deftypefun + +@deftypefun GtkPreviewInfo* gtk_preview_get_info (void) +@end deftypefun + +@gtkstdmacros{Preview, PREVIEW} + + +@page +@node GtkProgressBar, GtkRadioButton, GtkPreview, Widgets +@comment node-name, next, previous, up +@section The progress bar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_progress_bar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_progress_bar_new (void) +@end deftypefun + +@deftypefun void gtk_progress_bar_update (GtkProgressBar *@var{pbar}, gfloat @var{percentage}) +@end deftypefun + +@gtkstdmacros{ProgressBar, PROGRESS_BAR} + + +@page +@node GtkRadioButton, GtkRadioMenuItem, GtkProgressBar, Widgets +@comment node-name, next, previous, up +@section The radio button widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_radio_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_button_new (GSList *@var{group}) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_button_new_with_label (GSList *@var{group}, gchar *@var{label}) +@end deftypefun + +@deftypefun GSList* gtk_radio_button_group (GtkRadioButton *@var{radio_button}) +@end deftypefun + +@gtkstdmacros{RadioButton, RADIO_BUTTON} + + +@page +@node GtkRadioMenuItem, GtkRange, GtkRadioButton, Widgets +@comment node-name, next, previous, up +@section The radio button widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_radio_menu_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_menu_item_new (GSList *@var{group}) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_menu_item_new_with_label (GSList *@var{group}, gchar *@var{label}) +@end deftypefun + +@deftypefun GSList* gtk_radio_menu_item_group (GtkRadioMenuItem *@var{radio_menu_item}) +@end deftypefun + +@gtkstdmacros{RadioMenuItem, RADIO_MENU_ITEM} + + +@page +@node GtkRange, GtkRuler, GtkRadioMenuItem, Widgets +@comment node-name, next, previous, up +@section The range widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_range_get_type (void) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_range_get_adjustment (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_set_update_policy (GtkRange *@var{range}, GtkUpdatePolicy @var{policy}) +@end deftypefun + +@deftypefun void gtk_range_set_adjustment (GtkRange *@var{range}, GtkAdjustment *@var{adjustment}) +@end deftypefun + +@deftypefun void gtk_range_draw_background (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_trough (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_slider (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_step_forw (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_step_back (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_slider_update (GtkRange *@var{range}) +@end deftypefun + +@deftypefun gint gtk_range_trough_click (GtkRange *@var{range}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun void gtk_range_default_hslider_update (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_default_vslider_update (GtkRange *@var{range}) +@end deftypefun + +@deftypefun gint gtk_range_default_htrough_click (GtkRange *@var{range}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun gint gtk_range_default_vtrough_click (GtkRange *@var{range}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun void gtk_range_default_hmotion (GtkRange *@var{range}, gint @var{xdelta}, gint @var{ydelta}) +@end deftypefun + +@deftypefun void gtk_range_default_vmotion (GtkRange *@var{range}, gint @var{xdelta}, gint @var{ydelta}) +@end deftypefun + +@deftypefun gfloat gtk_range_calc_value (GtkRange *@var{ragne}, gint @var{position}) +@end deftypefun + +@gtkstdmacros{Range, RANGE} + + +@page +@node GtkRuler, GtkScale, GtkRange, Widgets +@comment node-name, next, previous, up +@section The ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_ruler_get_type (void) +@end deftypefun + +@deftypefun void gtk_ruler_set_metric (GtkRuler *@var{ruler}, GtkMetricType @var{metric}) +@end deftypefun + +@deftypefun void gtk_ruler_set_range (GtkRuler *@var{ruler}, gfloat @var{lower}, gfloat @var{upper}, gfloat @var{position}, gfloat @var{max_size}) +@end deftypefun + +@deftypefun void gtk_ruler_draw_ticks (GtkRuler *@var{ruler}) +@end deftypefun + +@deftypefun void gtk_ruler_draw_pos (GtkRuler *@var{ruler}) +@end deftypefun + +@gtkstdmacros{Ruler, RULER} + + +@page +@node GtkScale, GtkScrollbar, GtkRuler, Widgets +@comment node-name, next, previous, up +@section The scale widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_scale_get_type (void) +@end deftypefun + +@deftypefun void gtk_scale_set_digits (GtkScale *@var{scale}, gint @var{digits}) +@end deftypefun + +@deftypefun void gtk_scale_set_draw_value (GtkScale *@var{scale}, gint @var{draw_value}) +@end deftypefun + +@deftypefun void gtk_scale_set_value_pos (GtkScale *@var{scale}, gint @var{pos}) +@end deftypefun + +@deftypefun gint gtk_scale_value_width (GtkScale *@var{scale}) +@end deftypefun + +@deftypefun void gtk_scale_draw_value (GtkScale *@var{scale}) +@end deftypefun + +@gtkstdmacros{Scale, SCALE} + + +@page +@node GtkScrollbar, GtkScrolledWindow, GtkScale, Widgets +@comment node-name, next, previous, up +@section The scrollbar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_scrollbar_get_type (void) +@end deftypefun + +@gtkstdmacros{Scrollbar, SCROLLBAR} + + +@page +@node GtkScrolledWindow, GtkSeparator, GtkScrollbar, Widgets +@comment node-name, next, previous, up +@section The scrolled window widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_scrolled_window_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_scrolled_window_new (GtkAdjustment *@var{hadjustment}, GtkAdjustment *@var{vadjustment}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *@var{scrolled_window}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *@var{scrolled_window}) +@end deftypefun + +@deftypefun void gtk_scrolled_window_set_policy (GtkScrolledWindow *@var{scrolled_window}, GtkPolicyType @var{hscrollbar_policy}, GtkPolicyType @var{vscrollbar_policy}) +@end deftypefun + +@gtkstdmacros{ScrolledWindow, SCROLLED_WINDOW} + + +@page +@node GtkSeparator, GtkTable, GtkScrolledWindow, Widgets +@comment node-name, next, previous, up +@section The separator widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_separator_get_type (void) +@end deftypefun + +@gtkstdmacros{Separator, SEPARATOR} + + +@page +@node GtkTable, GtkText, GtkSeparator, Widgets +@comment node-name, next, previous, up +@section The table widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_table_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_table_new (gint @var{rows}, gint @var{columns}, gint @var{homogeneous}) +@end deftypefun + +@deftypefun void gtk_table_attach (GtkTable *@var{table}, GtkWidget *@var{child}, gint @var{left_attach}, gint @var{right_attach}, gint @var{top_attach}, gint @var{bottom_attach}, gint @var{xoptions}, gint @var{yoptions}, gint @var{xpadding}, gint @var{ypadding}) +@end deftypefun + +@deftypefun void gtk_table_attach_defaults (GtkTable *@var{table}, GtkWidget *@var{widget}, gint @var{left_attach}, gint @var{right_attach}, gint @var{top_attach}, gint @var{bottom_attach}) +@end deftypefun + +@deftypefun void gtk_table_set_row_spacing (GtkTable *@var{table}, gint @var{row}, gint @var{spacing}) +@end deftypefun + +@deftypefun void gtk_table_set_col_spacing (GtkTable *@var{table}, gint @var{col}, gint @var{spacing}) +@end deftypefun + +@deftypefun void gtk_table_set_row_spacings (GtkTable *@var{table}, gint @var{spacing}) +@end deftypefun + +@deftypefun void gtk_table_set_col_spacings (GtkTable *@var{table}, gint @var{spacing}) +@end deftypefun + +@gtkstdmacros{Table, TABLE} + + +@page +@node GtkText, GtkToggleButton, GtkTable, Widgets +@comment node-name, next, previous, up +@section The text widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_text_get_type (void) +@end deftypefun + +@gtkstdmacros{Text, TEXT} + + +@page +@node GtkToggleButton, GtkTree, GtkText, Widgets +@comment node-name, next, previous, up +@section The toggle button widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkToggleButton::toggled (GtkToggleButton *@var{toggle_button}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_toggle_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_toggle_button_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_toggle_button_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_toggle_button_set_mode (GtkToggleButton *@var{toggle_button}, gint @var{draw_indicator}) +@end deftypefun + +@deftypefun void gtk_toggle_button_set_state (GtkToggleButton *@var{toggle_button}, gint @var{state}) +@end deftypefun + +@deftypefun void gtk_toggle_button_toggled (GtkToggleButotn *@var{toggle_button}) +@end deftypefun + +@gtkstdmacros{ToggleButton, TOGGLE_BUTTON} + + +@page +@node GtkTree, GtkTreeItem, GtkToggleButton, Widgets +@comment node-name, next, previous, up +@section The tree widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_tree_get_type (void) +@end deftypefun + +@gtkstdmacros{Tree, TREE} + + +@page +@node GtkTreeItem, GtkVBox, GtkTree, Widgets +@comment node-name, next, previous, up +@section The tree item widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_tree_item_get_type (void) +@end deftypefun + +@gtkstdmacros{TreeItem, TREE_ITEM} + + +@page +@node GtkVBox, GtkViewport, GtkTreeItem, Widgets +@comment node-name, next, previous, up +@section The vertical box widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vbox_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vbox_new (gint @var{homogeneous}, gint @var{spacing}) +@end deftypefun + +@gtkstdmacros{VBox, VBOX} + + +@page +@node GtkViewport, GtkVRuler, GtkVBox, Widgets +@comment node-name, next, previous, up +@section The viewport widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_viewport_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_viewport_new (GtkAdjustment *@var{hadjustment}, GtkAdjustment *@var{vadjustment}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_viewport_get_hadjustment (GtkViewport *@var{viewport}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_viewport_get_vadjustment (GtkViewport *@var{viewport}) +@end deftypefun + +@deftypefun void gtk_viewport_set_hadjustment (GtkViewport *@var{viewport}, GtkAdjustment *@var{adjustment}) +@end deftypefun + +@deftypefun void gtk_viewport_set_vadjustment (GtkViewport *@var{viewport}, GtkAdjustment *@var{adjustment}) +@end deftypefun + +@deftypefun void gtk_viewport_set_shadow_type (GtkViewport *@var{viewport}, GtkShadowType @var{type}) +@end deftypefun + +@gtkstdmacros{Viewport, VIEWPORT} + + +@page +@node GtkVRuler, GtkVScale, GtkViewport, Widgets +@comment node-name, next, previous, up +@section The vertical ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vruler_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vruler_new (void) +@end deftypefun + +@gtkstdmacros{VRuler, VRULER} + + +@page +@node GtkVScale, GtkVScrollbar, GtkVRuler, Widgets +@comment node-name, next, previous, up +@section The vertical ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vscale_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vscale_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{VScale, VSCALE} + + +@page +@node GtkVScrollbar, GtkVSeparator, GtkVScale, Widgets +@comment node-name, next, previous, up +@section The vertical scrollbar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vscrollbar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vscrollbar_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{VScrollbar, VSCROLLBAR} + + +@page +@node GtkVSeparator, GtkWidget, GtkVScrollbar, Widgets +@comment node-name, next, previous, up +@section The vertical separator widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vseparator_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vseparator_new (void) +@end deftypefun + +@gtkstdmacros{VSeparator, VSEPARATOR} + + +@page +@node GtkWidget, GtkWindow, GtkVSeparator, Widgets +@comment node-name, next, previous, up +@section The base widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkWidget::show (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::hide (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::map (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::unmap (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::realize (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::unrealize (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::draw (GtkWidget *@var{widget}, GdkRectangle *@var{area}) +@end deftypefn + +@deftypefn Signal void GtkWidget::draw_focus (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::draw_default (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::size_request (GtkWidget *@var{widget}, GtkRequisition *@var{requisition}) +@end deftypefn + +@deftypefn Signal void GtkWidget::size_allocate (GtkWidget *@var{widget}, GtkAllocation *@var{allocation}) +@end deftypefn + +@deftypefn Signal void GtkWidget::state_changed (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::install_accelerator (GtkWidget *@var{widget}, gchar *@var{signal_name}, gchar @var{key}, guint8 @var{modifiers}) +@end deftypefn + +@deftypefn Signal void GtkWidget::remove_accelerator (GtkWidget *@var{widget}, gchar *@var{signal_name}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::event (GtkWidget *@var{widget}, GdkEvent *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::button_press_event (GtkWidget *@var{widget}, GdkEventButton *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::button_release_event (GtkWidget *@var{widget}, GdkEventButton *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::motion_notify_event (GtkWidget *@var{widget}, GdkEventMotion *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::delete_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::destroy_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::expose_event (GtkWidget *@var{widget}, GdkEventExpose *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::key_press_event (GtkWidget *@var{widget}, GdkEventKey *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::key_release_event (GtkWidget *@var{widget}, GdkEventKey *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::enter_notify_event (GtkWidget *@var{widget}, GdkEventCrossing *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::leave_notify_event (GtkWidget *@var{widget}, GdkEventCrossing *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::configure_event (GtkWidget *@var{widget}, GdkEventConfigure *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::focus_in_event (GtkWidget *@var{widget}, GdkEventFocus *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::focus_out_event (GtkWidget *@var{widget}, GdkEventFocus *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::map_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::unmap_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::property_notify_event (GtkWidget *@var{widget}, GdkEventProperty *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::selection_clear_event (GtkWidget *@var{widget}, GdkEventSelection *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::selection_request_event (GtkWidget *@var{widget}, GdkEventSelection *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::selection_notify_event (GtkWidget *@var{widget}, GdkEventSelection *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::drop_event (GtkWidget *@var{widget}, GdkEventDrop *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::drag_begin_event (GtkWidget *@var{widget}, GdkEventDragBegin *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::other_event (GtkWidget *@var{widget}, GdkEventOther *@var{event}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_widget_get_type (void) +@end deftypefun + +@deftypefun void gtk_widget_class_init (GtkWidgetClass *@var{class}) +@end deftypefun + +@deftypefun void gtk_widget_init (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_destroy (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_show (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_hide (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_map (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_unmap (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_realize (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_unrealize (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_draw (GtkWidget *@var{widget}, GdkRectangle *@var{area}) +@end deftypefun + +@deftypefun void gtk_widget_draw_focus (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_draw_children (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_size_request (GtkWidget *@var{widget}, GtkRequisition *@var{requisition}) +@end deftypefun + +@deftypefun void gtk_widget_size_allocate (GtkWidget *@var{widget}, GtkAllocation *@var{allocation}) +@end deftypefun + +@deftypefun void gtk_widget_install_accelerator (GtkWidget *@var{widget}, GtkAcceleratorTable *@var{table}, gchar *@var{signal_name}, gchar @var{key}, guint8 @var{modifiers}) +@end deftypefun + +@deftypefun void gtk_widget_remove_accelerator (GtkWidget *@var{widget}, GtkAcceleratorTable *@var{table}, gchar *@var{signal_name}) +@end deftypefun + +@deftypefun gint gtk_widget_event (GtkWidget *@var{widget}, GdkEvent *@var{event}) +@end deftypefun + +@deftypefun void gtk_widget_reparent (GtkWidget *@var{widget}, GtkWidget *@var{new_parent}) +@end deftypefun + +@deftypefun void gtk_widget_popup (GtkWidget *@var{widget}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun gint gtk_widget_intersect (GtkWidget *@var{widget}, GdkRectangle *@var{area}, GdkRectangle *@var{intersection}) +@end deftypefun + +@deftypefun void gtk_widget_grab_focus (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_grab_default (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_restore_state (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_set_name (GtkWidget *@var{widget}, gchar *@var{name}) +@end deftypefun + +@deftypefun void gtk_widget_set_state (GtkWidget *@var{widget}, GtkStateType @var{state}) +@end deftypefun + +@deftypefun void gtk_widget_set_sensitive (GtkWidget *@var{widget}, gint sensitive) +@end deftypefun + +@deftypefun void gtk_widget_set_parent (GtkWidget *@var{widget}, GtkWidget *@var{parent}) +@end deftypefun + +@deftypefun void gtk_widget_set_style (GtkWidget *@var{widget}, GtkStyle *@var{style}) +@end deftypefun + +@deftypefun void gtk_widget_set_uposition (GtkWidget *@var{widget}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun void gtk_widget_set_usize (GtkWidget *@var{widget}, gint @var{width}, gint @var{height}) +@end deftypefun + +@deftypefun GtkWidget* gtk_widget_get_toplevel (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun GtkWidget* gtk_widget_get_ancestor (GtkWidget *@var{widget}, gint @var{type}) +@end deftypefun + +@deftypefun GdkColormap* gtk_widget_get_colormap (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun GdkVisual* gtk_widget_get_visual (GtkWidget *@var{visual}) +@end deftypefun + +@deftypefun GtkStyle* gtk_widget_get_style (GtkWidget *@var{style}) +@end deftypefun + +@gtkstdmacros{Widget, WIDGET} + + +@page +@node GtkWindow, , GtkWidget, Widgets +@comment node-name, next, previous, up +@section The window widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkWindow::move_resize (GtkWindow *@var{window}, gint *@var{x}, gint *@var{y}, gint @var{width}, gint @var{height}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_window_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_window_new (GtkWindowType @var{type}) +@end deftypefun + +@deftypefun void gtk_window_set_title (GtkWindow *@var{window}, gchar *@var{title}) +@end deftypefun + +@deftypefun void gtk_window_set_focus (GtkWindow *@var{window}, GtkWidget *@var{focus}) +@end deftypefun + +@deftypefun void gtk_window_set_default (GtkWindow *@var{window}, GtkWidget *@var{defaultw}) +@end deftypefun + +@deftypefun void gtk_window_set_policy (GtkWindow *@var{window}, gint @var{allow_shrink}, gint @var{allow_grow}, gint @var{auto_shrink}) +@end deftypefun + +@deftypefun void gtk_window_add_accelerator_table (GtkWindow *@var{window}, GtkAcceleratorTable *@var{table}) +@end deftypefun + +@deftypefun void gtk_window_remove_accelerator_table (GtkWindow *@var{window}, GtkAcceleratorTable *@var{table}) +@end deftypefun + +@deftypefun void gtk_window_position (GtkWindow *@var{window}, GtkWindowPosition @var{position}) +@end deftypefun + +@gtkstdmacros{Window, WINDOW} + + +@node Other Objects, Miscellaneous, Widgets, Top +@comment node-name, next, previous, up +@chapter Utility objects + + +@menu +* GtkAdjustment:: The adjustment object. +* GtkData:: The data object. +@end menu + + +@node GtkAdjustment, GtkData, Other Objects, Other Objects +@comment node-name, next, previous, up +@section The adjustment object + + +@node GtkData, , GtkAdjustment, Other Objects +@comment node-name, next, previous, up +@section The data object + + +@node Miscellaneous, Examples, Other Objects, Top +@comment node-name, next, previous, up +@chapter Initialization, exit and other features + + +@menu +* Initialization and exit:: Initializing and exiting GTK. +* Menu Factories:: Simplified menu creation. +* Tree Factories:: Simplified tree creation. +* Tool Tips:: Pop up help mechanism. +* Resource Files:: Resource files. +* Standard Macros:: Macros defined by all objects. +@end menu + + +@node Initialization and exit, Menu Factories, Miscellaneous, Miscellaneous +@comment node-name, next, previous, up +@section Initializing and exiting GTK + + +@node Menu Factories, Tree Factories, Initialization and exit, Miscellaneous +@comment node-name, next, previous, up +@section Simplified menu creation + + +@node Tree Factories, Tool Tips, Menu Factories, Miscellaneous +@comment node-name, next, previous, up +@section Simplified tree creation + + +@node Tool Tips, Resource Files, Tree Factories, Miscellaneous +@comment node-name, next, previous, up +@section Pop up help mechanism + + +@node Resource Files, Standard Macros, Tool Tips, Miscellaneous +@comment node-name, next, previous, up +@section Pop up help mechanism + + +@node Standard Macros, , Resource Files, Miscellaneous +@comment node-name, next, previous, up +@section Macros defined by all objects + +There are three macros that are defined by all object types. The first +two are used for performing casts and the last is for querying whether +an object is of a particular type. These macros are both conveniences +and debugging tools. If the GTK library was compiled with @code{NDEBUG} +defined as a preprocessor symbol (via the -DNDEBUG to cc), then the +macros check the object type and emit a warning if the cast is +invalid. Doing such checking is fairly expensive since the cast macros +are used everywhere in GTK and would normally be turned off in a public +release of a product. Note: The functions below are indeed macros, but +they may be considered functions for most purposes. + +@deftypefun Gtk<ObjectType>* GTK_<OBJECT_TYPE> (gpointer @var{obj}) +Cast a generic pointer to @code{Gtk<ObjectType>*}. This function is +provided in order to be able to provide checking during development +stages of code development since it is possible to examine the actual +type of object (using @code{gtk_type_is_a}) before performing the cast. +@end deftypefun + +@deftypefun Gtk<ObjectType>Class* GTK_<OBJECT_TYPE>_CLASS (gpointer @var{class}) +Cast a generic pointer to @code{Gtk<ObjectType>Class*}. Like +@code{GTK_<ObjectType>}, this function is, in reality, a macro. +@end deftypefun + +@deftypefun gint GTK_IS_<ObjectType> (gpointer @var{obj}) +Determine if a generic pointer refers to a @code{Gtk<ObjectType>} +object. This function is, in reality, a macro wrapper around the +@code{gtk_type_is_a} function (@pxref{Objects}). +@end deftypefun + + +@node Examples, Object Implementation, Miscellaneous, Top +@comment node-name, next, previous, up +@chapter Using GTK + + +@menu +* Simple:: The simplest GTK program. +* Hello World:: Hello world in GTK. +* Hello World II:: An enhanced hello world. +* Hello World III:: Making Hello World II robust. +@end menu + + +@node Simple, Hello World, Examples, Examples +@comment node-name, next, previous, up +@section The simplest GTK program + + +The 16 line GTK program shown below is just about the simplest possible +program which uses GTK. (Well, technically, you don't have to create the +window and it would still be a program which uses GTK). The program, +when compiled and run, will create a single window 200x200 pixels in +size. The program does not exit until its is explicitly killed using the +shell or a window manager function. + +@example +#include <gtk/gtk.h> + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + +The first point of interest in this program is the standard +initialization line. + +@example + gtk_init (&argc, &argv); +@end example + +Almost every GTK program will contain such a line. GTK will initialize +itself and GDK and remove any command line arguments it recognizes from +@var{argc} and @var{argv}. + +The next two lines of code create and display a window. + +@example + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_show (window); +@end example + +The @code{GTK_WINDOW_TOPLEVEL} argument specifies that we want the +window to undergo window manager decoration and placement. One might be +lead to think that the window, since it has no children, would be 0x0 +pixels in size. But, this is not the case because a window that has no +children defaults to 200x200 pixels in size. Mainly because 0x0 windows +are annoying to manipulate or even see in some cases. + +The last line enters the GTK main processing loop. + +@example + gtk_main (); +@end example + +Normally, @code{gtk_main} is called once and the program should exit +when it returns. @xref{Initialization and exit}. + + +@node Hello World, Hello World II, Simple, Examples +@comment node-name, next, previous, up +@section Hello world in GTK + + +@example +#include <gtk/gtk.h> + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + GtkWidget *label; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + label = gtk_label_new ("Hello World"); + gtk_container_add (GTK_CONTAINER (window), label); + gtk_widget_show (label); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + + +@node Hello World II, Hello World III, Hello World, Examples +@comment node-name, next, previous, up +@section An enhanced hello world + + +@example +#include "gtk.h" + +void +hello (void) +@{ + g_print ("Hello World\n"); + gtk_exit (0); +@} + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + button = gtk_button_new_with_label ("Hello World"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (hello), NULL); + gtk_container_add (GTK_CONTAINER (window), button); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + + +@node Hello World III, , Hello World II, Examples +@comment node-name, next, previous, up +@section Making Hello World II robust + + +@example +#include "gtk.h" + +void +hello (void) +@{ + g_print ("Hello World\n"); + gtk_exit (0); +@} + +void +destroy (void) +@{ + gtk_exit (0); +@} + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (destroy), NULL); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + button = gtk_button_new_with_label ("Hello World"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (hello), NULL); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_container_add (GTK_CONTAINER (window), button); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + + +@node Object Implementation, Signal Implementation, Examples, Top +@comment node-name, next, previous, up +@chapter Object internals +@cindex Object Implementaton + +Objects (or the @code{GtkObject} type) and the class hierarchy in +general is implemented via a hierarchy of structs and type casting. Be +aware that when classes are mentioned it is the conceptual idea of +classes that is being referred to. GTK is written entirely in C which +provides no direct support for classes. + +The first part to the class mechanism is the object fields. These are +fields that will be used on a per object basis. For example, the widget +type contains a field for the widgets parent. Every derived type needs a +reference to its parent type. A descendant class of @code{GtkObject} +would define itself like: + +@example +struct Descendant +@{ + GtkObject object; + + @dots{} +@}; +@end example + +It is important to note that the @code{GtkObject} field needs to appear +first in the descendant type structure. This allows pointers to objects +of type @code{Descendant} to be cast to pointers to @code{GtkObjects}'s +and vice-versa. + +The second part to the class mechanism is the class fields. These fields +are defined on a per class basis. In the case of widgets, the class +fields are all the ``virtual'' functions for widgets. The +@code{GtkObject} class defines the @code{destroy} virtual function and +the necessary fields for the signal mechanism as well as a field for +determining the runtime type of an object. A virtual function is +semantically the same as it is in C++. That is, the actual function that +is called is determined based on the type of the object. Or, more +specifically, the actual function call depends on the class structure +that is pointed to by the @code{klass} field of the @code{GtkObject} +structure. + +To see how the class fields work it is necessary to see the object +fields for a @code{GtkObject}. The @code{GtkObject} type is defined as +follows: + +@example +typedef struct _GtkObject GtkObject; + +struct _GtkObject +@{ + guint32 flags; + GtkObjectClass *klass; + gpointer object_data; +@}; +@end example + +The @code{class} field actually points to a class structure derived from +@code{GtkObjectClass}. By convention, each new type defines its own +class structure even if it is unnecessary. As an example, the +hypothetical @code{Descendant} class would define its class structure +as: + +@example +struct DescendantClass +@{ + GtkObjectClass parent_class; + + @dots{} +@}; +@end example + +It is convention to name the parent class field (@code{GtkObjectClass} +in this case), @code{parent_class}. For the same reason as stated above +for the object structure, the parent class field must be the first field +in the class structure. + +@strong{Note:} GTK assumes that the first field in a structure will be +placed by the compiler at the start of the structure. This is certainly +true for gcc, however, from my precursory reading of the C standard I +was unable to come to a definite conclusion as to whether this was +required or simply done for simplicity. I'm not too worried about this +assumption, though, as every C compiler I've ever encountered would work +with GTK. + +The @code{flags} field of the @code{GtkObject} structure is used to keep +track of a relatively few object flags and is also used by the +@code{GtkWidget} type to store additional flags. At this time, the upper +16 bits of the flags field are reserved but unused. + +The @code{object_data} field of the @code{GtkObject} structure is an +opaque pointer used by the object data mechanism. In truth, it is a +pointer to the beginning of the data list which is composed of the +following structures. + +@example +typedef struct _GtkObjectData GtkObjectData; + +struct _GtkObjectData +@{ + guint id; + gpointer data; + GtkObjectData *next; +@}; +@end example + +The data mechanism allows arbitrary data to be associated with a +character string key in any object. A hash table is used to transform +the character string key into the data id and then a search through the +list is made to see if the data exists. The assumption being that the +data list will usually be short and therefore a linear search is +ok. Future work on the data mechanism might make use of a resizable +array instead of a linked list. This would shrink the overhead of the +@code{GtkObjectData} structure by 4 bytes on 32 bit architectures. + + +@node Signal Implementation, Widget Implementation, Object Implementation, Top +@comment node-name, next, previous, up +@chapter Signal internals +@cindex Signal Implementation + + +@node Widget Implementation, Function Index, Signal Implementation, Top +@comment node-name, next, previous, up +@chapter Widget internals +@cindex Widget Implementation + + +@node Function Index, Concept Index, Widget Implementation, Top +@comment node-name, next, previous, up +@unnumbered Function Index + +@printindex fn + + +@node Concept Index, , Function Index, Top +@comment node-name, next, previous, up +@unnumbered Concept Index + +@printindex cp + + +@summarycontents +@contents +@bye diff --git a/docs/macros.texi b/docs/macros.texi new file mode 100644 index 0000000000..f8df89a46f --- /dev/null +++ b/docs/macros.texi @@ -0,0 +1,18 @@ +@macro gtkstdmacros {p, q} + +@deftypefun Gtk\p\* GTK_\q\ (gpointer @var{obj}) +Cast a generic pointer to @code{Gtk\p\*}. @xref{Standard Macros}, for +more info. +@end deftypefun + +@deftypefun Gtk\p\Class* GTK_\q\_CLASS (gpointer @var{class}) +Cast a generic pointer to @code{Gtk\p\Class*}. @xref{Standard Macros}, +for more info. +@end deftypefun + +@deftypefun gint GTK_IS_\q\ (gpointer @var{obj}) +Determine if a generic pointer refers to a @code{Gtk\p\} +object. @xref{Standard Macros}, for more info. +@end deftypefun + +@end macro diff --git a/docs/texinfo.tex b/docs/texinfo.tex new file mode 100644 index 0000000000..7d62f26f70 --- /dev/null +++ b/docs/texinfo.tex @@ -0,0 +1,4692 @@ +%% TeX macros to handle texinfo files + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, +% 94, 95, 1996 Free Software Foundation, Inc. + +%This texinfo.tex file 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, or (at +%your option) any later version. + +%This texinfo.tex file 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 +%General Public License for more details. + +%You should have received a copy of the GNU General Public License +%along with this texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +%Boston, MA 02111-1307, USA. + + +%In other words, you are welcome to use, share and improve this program. +%You are forbidden to forbid anyone else to use, share and improve +%what you give them. Help stamp out software-hoarding! + + +% Send bug reports to bug-texinfo@prep.ai.mit.edu. +% Please include a *precise* test case in each bug report. + + +% Make it possible to create a .fmt file just by loading this file: +% if the underlying format is not loaded, start by loading it now. +% Added by gildea November 1993. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$Revision$ +\message{Loading texinfo package [Version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{} + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv = \equiv +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t +\let\ptextilde=\~ + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} +\let\~ = \tie % And make it available as @~. + + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +%---------------------Begin change----------------------- +% +%%%% For @cropmarks command. +% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen \topandbottommargin +\newdimen \outerhsize \newdimen \outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in +% +%---------------------End change----------------------- + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}} +\def\onepageout#1{% + \hoffset=\normaloffset + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + {% + \escapechar = `\\ % use backslash in output files. + \indexdummies + \shipout\vbox{% + {\let\hsize=\pagewidth \makeheadline}% + \pagebody{#1}% + {\let\hsize=\pagewidth \makefootline}% + }% + }% + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +%%%% For @cropmarks command %%%% + +% Here is a modification of the main output routine for Near East Publications +% This provides right-angle cropmarks at all four corners. +% The contents of the page are centerlined into the cropmarks, +% and any desired binding offset is added as an \hskip on either +% site of the centerlined box. (P. A. MacKay, 12 November, 1986) +% +\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up +{\escapechar=`\\\relax % makes sure backslash is used in output files. + \shipout + \vbox to \outervsize{\hsize=\outerhsize + \vbox{\line{\ewtop\hfill\ewtop}} + \nointerlineskip + \line{\vbox{\moveleft\cornerthick\nstop} + \hfill + \vbox{\moveright\cornerthick\nstop}} + \vskip \topandbottommargin + \centerline{\ifodd\pageno\hskip\bindingoffset\fi + \vbox{ + {\let\hsize=\pagewidth \makeheadline} + \pagebody{#1} + {\let\hsize=\pagewidth \makefootline}} + \ifodd\pageno\else\hskip\bindingoffset\fi} + \vskip \topandbottommargin plus1fill minus1fill + \boxmaxdepth\cornerthick + \line{\vbox{\moveleft\cornerthick\nsbot} + \hfill + \vbox{\moveright\cornerthick\nsbot}} + \nointerlineskip + \vbox{\line{\ewbot\hfill\ewbot}} + }} + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} +% +% Do @cropmarks to get crop marks +\def\cropmarks{\let\onepageout=\croppageout } + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type <Return> to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% @paragraphindent is defined for the Info formatting commands only. +\let\paragraphindent=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% Also ignore @macro ... @end macro. The user must run texi2dvi, +% which runs makeinfo to do macro expansion. Ignore @unmacro, too. +\def\macro{\doignore{macro}} +\let\unmacro = \comment + + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.ai.mit.edu/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}} +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value#1{\expandafter + \ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}} + \else \csname SET#1\endcsname \fi} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex always succeeds; we read the text following, through @end +% iftex). But `@end iftex' should be valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\defineunmatchedend{iftex} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +% @refill is a no-op. +\let\refill=\relax + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + \comment % Ignore the actual filename. +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +% \def\macro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\macroxxx} +% \def\macroxxx#1#2 \end macro{% +% \expandafter\gdef\macrotemp#1{#2}% +% \endgroup} + +%\def\linemacro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\linemacroxxx} +%\def\linemacroxxx#1#2 \end linemacro{% +%\let\parsearg=\relax +%\edef\macrotempx{\csname M\butfirst\expandafter\string\macrotemp\endcsname}% +%\expandafter\xdef\macrotemp{\parsearg\macrotempx}% +%\expandafter\gdef\macrotempx#1{#2}% +%\endgroup} + +%\def\butfirst#1{} + + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +%% Try out Computer Modern fonts at \magstephalf +\let\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\slshape{9}{1000} +\let\indsl=\indit +\let\indtt=\ninett +\let\indttsl=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{12}{\magstep2} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{\magstep1} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled \magstep1 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\let\authorrm = \secrm + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp #1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{$\langle$}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{$\langle$}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{$\rangle$}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp +\let\url=\samp % perhaps include a hypertex \special eventually +\def\email#1{$\langle${\tt #1}$\rangle$} + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ +\catcode`\-=\active +\catcode`\_=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder} +} + +\def\realdash{-} +\def\realunder{_} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\normalunderscore\discretionary{}{}{}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. +% +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\ttsl\look}}\fi +\else{\tclose{\ttsl\look}}\fi} + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of +% @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +\def\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\def\titlefont#1{{\titlerm #1}} + +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefont{##1}} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish} +\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish} +\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + %{\parskip = 0in + %\par + %}% + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. Since that + % text will be indented by \tableindent, we make the item text be in + % a zero-width box. + \noindent + \rlap{\hskip -\tableindent\box0}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{\in hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. + +%%%% +% Dimensions + +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +%% 2/1/96, to allow fractions to be given with more than one digit. +\def\pickupwholefraction#1 {\global\advance\colcount by1 % +\expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% +\setuptable} + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xcolumnfractions\global\setpercenttrue% + \else + \ifsetpercent + \let\go\pickupwholefraction % In this case arg of setuptable + % is the decimal point before the + % number given in percent of hsize. + % We don't need this so we don't use it. + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1 }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% +\ifx\go\pickupwholefraction\else\let\go\setuptable\fi% +\fi\go} + +%%%% +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + + +%%%% +% @multitable ... @end multitable definitions: + +\def\multitable{\parsearg\dotable} + +\def\dotable#1{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\setmultitablespacing +\parskip=\multitableparskip +\parindent=\multitableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\setuptable#1 \endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has <not> set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: +\leftskip=\multitablecolspace +\fi +\noindent##\multistrut}\cr% + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{% +\filbreak%% keeps underfull box messages off when table breaks over pages. +\global\colcount=0\relax}} +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +%\let\{ = \lbracecmd +%\let\} = \rbracecmd +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +%\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\copyright{\realbackslash copyright }% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\unsepspaces +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there +\def\doind #1#2{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio=0 % We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % First process the index-string with all font commands turned off + % to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2}}% + % + % Now produce the complete index entry, with both the sort key and the + % original text, including any font commands. + \toks0 = {#2}% + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + \temp + }% + }% + \penalty\count255 + }% +} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% This is what you call to cause a particular index to get printed. +% Write +% @unnumbered Function Index +% @printindex fn + +\def\printindex{\parsearg\doprintindex} + +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + \def\indexbackslash{\rawbackslashxx}% + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \catcode`\\ = 0 + \catcode`\@ = 11 + \escapechar = `\\ + \begindoublecolumns + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + \input \jobname.#1s + \fi + \fi + \closein 1 + \enddoublecolumns +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry #1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent=2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {\global\setbox\partialpage + =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% + \eject + % + % Now switch to the double-column output routine. + \output={\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it once. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +- < + % 1pt) as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage + % box0 will be the left-hand column, box1 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 \penalty\outputpenalty +} +\def\pagesofar{% + % The contents of the output page -- any previous material, + % followed by the two boxes we just split. + \unvbox\partialpage + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output={\balancecolumns}\eject % split what we have + \endgroup + % Back to normal single-column typesetting, but take account of the + % fact that we just accumulated some stuff on the output page. + \pagegoal=\vsize +} +\def\balancecolumns{% + % Called on the last page of the double column material. + \setbox0=\vbox{\unvbox255}% + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {\vbadness=10000 \loop \global\setbox3=\copy0 + \global\setbox1=\vsplit3 to\dimen@ + \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + \pagesofar +} +\catcode `\@=\other + + +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount \chapno +\newcount \secno \secno=0 +\newcount \subsecno \subsecno=0 +\newcount \subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount \appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite \contentsfile +% This is called from \setfilename. +\def\opencontents{\openout \contentsfile = \jobname.toc} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\if \pageno<0 % +\errmessage{@#1 not allowed after generating table of contents}\fi +% +} + +\def\chapternofonts{% +\let\rawbackslash=\relax% +\let\frenchspacing=\relax% +\def\result{\realbackslash result} +\def\equiv{\realbackslash equiv} +\def\expansion{\realbackslash expansion} +\def\print{\realbackslash print} +\def\TeX{\realbackslash TeX} +\def\dots{\realbackslash dots} +\def\copyright{\realbackslash copyright} +\def\tt{\realbackslash tt} +\def\bf{\realbackslash bf } +\def\w{\realbackslash w} +\def\less{\realbackslash less} +\def\gtr{\realbackslash gtr} +\def\hat{\realbackslash hat} +\def\char{\realbackslash char} +\def\tclose##1{\realbackslash tclose {##1}} +\def\code##1{\realbackslash code {##1}} +\def\samp##1{\realbackslash samp {##1}} +\def\r##1{\realbackslash r {##1}} +\def\b##1{\realbackslash b {##1}} +\def\key##1{\realbackslash key {##1}} +\def\file##1{\realbackslash file {##1}} +\def\kbd##1{\realbackslash kbd {##1}} +% These are redefined because @smartitalic wouldn't work inside xdef. +\def\i##1{\realbackslash i {##1}} +\def\cite##1{\realbackslash cite {##1}} +\def\var##1{\realbackslash var {##1}} +\def\emph##1{\realbackslash emph {##1}} +\def\dfn##1{\realbackslash dfn {##1}} +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{\seccheck{chapter}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry + {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of the <toks register>. +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry % + {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry{#1}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\penalty 10000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc printing,} +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund <tege@matematik.su.se> + \contentsalignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. +} + + +% Normal (long) toc. +\outer\def\contents{% + \startcontents{\putwordTableofContents}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +% +% \turnoffactive is for the sake of @" used for umlauts. +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + \entry{\turnoffactive #1}{\turnoffactive #2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 % plus +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\,=\ptexcomma +\let\~=\ptextilde +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\endldots{\mathinner{\ldots\ldots\ldots\ldots}} +\def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi} +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% + +% This macro is +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \rawbackslash % have \ input char produce \ char from current font + \gobble +} + +% Define the \E... control sequence only if we are inside the +% environment, so the error checking in \end will work. +% +% We must call \lisp last in the definition, since it reads the +% return following the @example (or whatever) command. +% +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller fonts for small examples. + \indexfonts \tt + \rawbackslash % make \ output the \ character from the current font (tt) + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested % +\global\advance\parencount by 1 } +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. +% also in that case restore the outer-level definition of (. +\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi +\global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 \advance \hsize by -\dimen3 +\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does, putting the result in \tptemp. +% +\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}% + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + \removeemptybraces#2\relax + #1{\tptemp}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name. +\def\deftypevarheader #1#2{% +\doind {vr}{\code{#2}}% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% cross-reference, #3 the printed node name, #4 the name of the Info +% file, #5 the name of the printed manual. All but the node name can be +% omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \turnoffactive so that punctuation chars such as underscore +% work in node names. +\def\dosetq #1#2{{\let\folio=0 \turnoffactive \auxhat% +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% Read the last existing aux file, if any. No error if none exists. + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{ +{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}} + +\def\readauxfile{% +\begingroup +\catcode `\^^@=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\^^C=\other +\catcode `\^^D=\other +\catcode `\^^E=\other +\catcode `\^^F=\other +\catcode `\^^G=\other +\catcode `\^^H=\other +\catcode `\=\other +\catcode `\^^L=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode 26=\other +\catcode `\^^[=\other +\catcode `\^^\=\other +\catcode `\^^]=\other +\catcode `\^^^=\other +\catcode `\^^_=\other +\catcode `\@=\other +\catcode `\^=\other +\catcode `\~=\other +\catcode `\[=\other +\catcode `\]=\other +\catcode`\"=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode `\$=\other +\catcode `\#=\other +\catcode `\&=\other +% `\+ does not work, so use 43. +\catcode 43=\other +% Make the characters 128-255 be printing characters +{% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% +}% +% the aux file uses ' as the escape. +% Turn off \ as an escape so we do not lose on +% entries which were dumped with control sequences in their names. +% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ +% Reference to such entries still does not work the way one would wish, +% but at least they do not bomb out when the aux file is read in. +\catcode `\{=1 \catcode `\}=2 +\catcode `\%=\other +\catcode `\'=0 +\catcode`\^=7 % to make ^^e4 etc usable in xref tags +\catcode `\\=\other +\openin 1 \jobname.aux +\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue +\global\warnedobstrue +\fi +% Open the new aux file. Tex will close it automatically at exit. +\openout \auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only.. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +\long\gdef\footnotezzz#1{\insert\footins{% + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + #1\strut}% +} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + + +% End of control word definitions. + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +\hsize = 6in +\hoffset = .25in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 3pt plus 2pt minus 1pt +\setleading{13.2pt} +\advance\topskip by 1.2cm + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. This makes it come to about 9pt for the 8.5x11 format. +% +\ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + \global\chapheadingskip = 15pt plus 4pt minus 2pt + \global\secheadingskip = 12pt plus 3pt minus 2pt + \global\subsecheadingskip = 9pt plus 2pt minus 2pt + % + \global\lispnarrowing = 0.3in + \setleading{12pt} + \advance\topskip by -1cm + \global\parskip 2pt plus 1pt + \global\hsize = 5in + \global\vsize=7.5in + \global\tolerance=700 + \global\hfuzz=1pt + \global\contentsrightmargin=0pt + \global\deftypemargin=0pt + \global\defbodyindent=.5cm + % + \global\pagewidth=\hsize + \global\pageheight=\vsize + % + \global\let\smalllisp=\smalllispx + \global\let\smallexample=\smalllispx + \global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +\bindingoffset=0pt +\normaloffset=\hoffset +\pagewidth=\hsize +\pageheight=\vsize + +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; voffset; hoffset; binding offset; topskip. +% All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5#6{ + \global\vsize= #1 + \global\topskip= #6 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex + {\global\tolerance=700 + \global\hfuzz=1pt + \setleading{12pt} + \global\parskip 15pt plus 1pt + \advance\baselineskip by 1.6pt + \changepagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm} + } + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{\afourpaper +\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def\auxhat{\def^{'hat}} +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +%% These look ok in all fonts, so just make them not special. The @rm below +%% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: diff --git a/gdk/.cvsignore b/gdk/.cvsignore new file mode 100644 index 0000000000..79680c82cb --- /dev/null +++ b/gdk/.cvsignore @@ -0,0 +1,6 @@ +*.lo +Makefile +.deps +_libs +libgdk.la + diff --git a/gdk/Makefile.am b/gdk/Makefile.am new file mode 100644 index 0000000000..f298e2c3a1 --- /dev/null +++ b/gdk/Makefile.am @@ -0,0 +1,75 @@ +## Process this file with automake to produce Makefile.in + +gdkincludedir = $(includedir)/gdk + +lib_LTLIBRARIES = libgdk.la + +libgdk_la_SOURCES = \ + gdk.c \ + gdkcolor.c \ + gdkcursor.c \ + gdkdraw.c \ + gdkfont.c \ + gdkgc.c \ + gdkglobals.c \ + gdkimage.c \ + gdkinput.c \ + gdkpixmap.c \ + gdkproperty.c \ + gdkrectangle.c \ + gdkselection.c \ + gdkvisual.c \ + gdkwindow.c \ + gdkxid.c \ + gxid_lib.c +## this last one is ifdef'd out unless XINPUT_GXI is defined +## It's easier than trying to get automake to handle compiling +## it conditionally + +gdkinclude_HEADERS = \ + gdk.h \ + gdkcursors.h \ + gdkkeysyms.h \ + gdkprivate.h \ + gdktypes.h \ + gdkinput.h \ + gdkinputnone.h \ + gdkinputcommon.h\ + gdkinputgxi.h \ + gdkinputxfree.h \ + gxid_lib.h \ + gxid_proto.h \ + gdkx.h + +libgdk_la_LDFLAGS = -version-info 1:0:0 \ + @x_ldflags@ @x_libs@ + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ + +EXTRA_PROGRAMS = gxid + +bin_PROGRAMS = @xinput_progs@ + +gxid_SOURCES = gxid.c + +gxid_LDADD = \ + @x_ldflags@ \ + @x_libs@ \ + -lm + +BUILT_SOURCES = gdkcursors.h gdkkeysyms.h + +EXTRA_DIST = makecursors makecursors.sed makekeysyms makekeysyms.sed + +gdkcursors.h: + $(srcdir)/makecursors @x_includes@/X11/cursorfont.h > $@ + +gdkkeysyms.h: + $(srcdir)/makekeysyms @x_includes@/X11/keysymdef.h > $@ + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done diff --git a/gdk/gdk.c b/gdk/gdk.c new file mode 100644 index 0000000000..d5f85dd1ef --- /dev/null +++ b/gdk/gdk.c @@ -0,0 +1,2897 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <ctype.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif /* HAVE_SYS_SELECT_H_ */ + +#define XLIB_ILLEGAL_ACCESS +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xos.h> +#include <X11/Xutil.h> +#include <X11/Xmu/WinUtil.h> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +#ifndef X_GETTIMEOFDAY +#define X_GETTIMEOFDAY(tv) gettimeofday (tv, NULL) +#endif /* X_GETTIMEOFDAY */ + + +#define DOUBLE_CLICK_TIME 250 +#define TRIPLE_CLICK_TIME 500 +#define DOUBLE_CLICK_DIST 5 +#define TRIPLE_CLICK_DIST 5 + + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else +# ifndef _AIX + typedef long fd_mask; +# endif +# if defined(_IBMR2) +# define SELECT_MASK void +# else +# define SELECT_MASK int +# endif +#endif + + +typedef struct _GdkInput GdkInput; +typedef struct _GdkPredicate GdkPredicate; + +struct _GdkInput +{ + gint tag; + gint source; + GdkInputCondition condition; + GdkInputFunction function; + gpointer data; +}; + +struct _GdkPredicate +{ + GdkEventFunc func; + gpointer data; +}; + +/* + * Private function declarations + */ +static gint gdk_event_wait (void); +static gint gdk_event_translate (GdkEvent *event, + XEvent *xevent); +static Bool gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg); +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +static void gdk_dnd_drag_begin (GdkWindow *initial_window); +static void gdk_dnd_drag_enter (Window dest); +static void gdk_dnd_drag_leave (Window dest); +static void gdk_dnd_drag_end (Window dest, + GdkPoint coords); +static GdkAtom gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent); +static void gdk_print_atom (GdkAtom anatom); + +/* + * old junk from offix, we might use it though so leave it + */ +static Window gdk_drop_get_client_window (Display *dpy, + Window win); +static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y); +static void gdk_exit_func (void); +static int gdk_x_error (Display *display, + XErrorEvent *error); +static int gdk_x_io_error (Display *display); +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +static int connection_number = 0; /* The file descriptor number of our + * connection to the X server. This + * is used so that we may determine + * when events are pending by using + * the "select" system call. + */ + +static gint received_destroy_notify = FALSE; /* Did we just receive a destroy notify + * event? If so, we need to actually + * destroy the window which received + * it now. + */ +static GdkWindow *window_to_destroy = NULL; /* If we previously received a destroy + * notify event then this is the window + * which received that event. + */ + +static struct timeval start; /* The time at which the library was + * last initialized. + */ +static struct timeval timer; /* Timeout interval to use in the call + * to "select". This is used in + * conjunction with "timerp" to create + * a maximum time to wait for an event + * to arrive. + */ +static struct timeval *timerp; /* The actual timer passed to "select" + * This may be NULL, in which case + * "select" will block until an event + * arrives. + */ +static guint32 timer_val; /* The timeout length as specified by + * the user in milliseconds. + */ +static GList *inputs; /* A list of the input file descriptors + * that we care about. Each list node + * contains a GdkInput struct that describes + * when we are interested in the specified + * file descriptor. That is, when it is + * available for read, write or has an + * exception pending. + */ +static guint32 button_click_time[2]; /* The last 2 button click times. Used + * to determine if the latest button click + * is part of a double or triple click. + */ +static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. + * Also used to determine if the latest button + * click is part of a double or triple click. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ + +#define OTHER_XEVENT_BUFSIZE 4 +static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */ +static int other_xevent_i = 0; +static GList *putback_events = NULL; + +static gulong base_id; +static gint autorepeat; + + +/* + *-------------------------------------------------------------- + * gdk_init + * + * Initialize the library for use. + * + * Arguments: + * "argc" is the number of arguments. + * "argv" is an array of strings. + * + * Results: + * "argc" and "argv" are modified to reflect any arguments + * which were not handled. (Such arguments should either + * be handled by the application or dismissed). + * + * Side effects: + * The library is initialized. + * + *-------------------------------------------------------------- + */ + +void +gdk_init (int *argc, + char ***argv) +{ + XKeyboardState keyboard_state; + int synchronize; + int i, j, k; + XClassHint *class_hint; + int argc_orig = *argc; + char **argv_orig; + + argv_orig = malloc ((argc_orig + 1) * sizeof (char*)); + for (i = 0; i < argc_orig; i++) + argv_orig[i] = g_strdup ((*argv)[i]); + argv_orig[argc_orig] = NULL; + + X_GETTIMEOFDAY (&start); + + signal (SIGHUP, gdk_signal); + signal (SIGINT, gdk_signal); + signal (SIGQUIT, gdk_signal); + signal (SIGBUS, gdk_signal); + signal (SIGSEGV, gdk_signal); + signal (SIGPIPE, gdk_signal); + signal (SIGTERM, gdk_signal); + + gdk_display_name = NULL; + + XSetErrorHandler (gdk_x_error); + XSetIOErrorHandler (gdk_x_io_error); + + synchronize = FALSE; + + if (argc && argv) + { + if (*argc > 0) + gdk_progname = (*argv)[0]; + + for (i = 1; i < *argc;) + { + if (strcmp ("--display", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + + if ((i + 1) < *argc) + { + gdk_display_name = g_strdup ((*argv)[i + 1]); + (*argv)[i + 1] = NULL; + i += 1; + } + } + else if (strcmp ("--sync", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + synchronize = TRUE; + } + else if (strcmp ("--show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = TRUE; + } + else if (strcmp ("--no-show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = FALSE; + } + else if (strcmp ("--no-xshm", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_use_xshm = FALSE; + } + else if (strcmp ("--debug-level", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_debug_level = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("-name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progname = (*argv)[i]; + (*argv)[i] = NULL; + } + } + else if (strcmp ("-class", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progclass = (*argv)[i]; + (*argv)[i] = NULL; + } + } +#ifdef XINPUT_GXI + else if (strcmp ("--gxid_host", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_host = ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("--gxid_port", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_port = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } +#endif + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + gdk_progname = "<unknown>"; + } + + gdk_display = XOpenDisplay (gdk_display_name); + if (!gdk_display) + g_error ("cannot open display: %s", XDisplayName (gdk_display_name)); + + /* This is really crappy. We have to look into the display structure + * to find the base resource id. This is only needed for recording + * and playback of events. + */ + /* base_id = RESOURCE_BASE; */ + base_id = 0; + if (gdk_show_events) + g_print ("base id: %lu\n", base_id); + + connection_number = ConnectionNumber (gdk_display); + if (gdk_debug_level >= 1) + g_print ("connection number: %d\n", connection_number); + + if (synchronize) + XSynchronize (gdk_display, True); + + gdk_screen = DefaultScreen (gdk_display); + gdk_root_window = RootWindow (gdk_display, gdk_screen); + + gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window, + 10, 10, 10, 10, 0, 0 , 0); + class_hint = XAllocClassHint(); + class_hint->res_name = gdk_progname; + class_hint->res_class = gdk_progclass; + XSetClassHint(gdk_display, gdk_leader_window, class_hint); + XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig); + XFree (class_hint); + + gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True); + gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True); + gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True); + gdk_wm_window_protocols[0] = gdk_wm_delete_window; + gdk_wm_window_protocols[1] = gdk_wm_take_focus; + gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False); + + gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE); + gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE); + gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE); + gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE); + gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE); + gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity); + gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart); + + XGetKeyboardControl (gdk_display, &keyboard_state); + autorepeat = keyboard_state.global_auto_repeat; + + timer.tv_sec = 0; + timer.tv_usec = 0; + timerp = NULL; + + button_click_time[0] = 0; + button_click_time[1] = 0; + button_window[0] = NULL; + button_window[1] = NULL; + button_number[0] = -1; + button_number[1] = -1; + + if (ATEXIT (gdk_exit_func)) + g_warning ("unable to register exit function"); + + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + + initialized = 1; +} + +/* + *-------------------------------------------------------------- + * gdk_exit + * + * Restores the library to an un-itialized state and exits + * the program using the "exit" system call. + * + * Arguments: + * "errorcode" is the error value to pass to "exit". + * + * Results: + * Allocated structures are freed and the program exits + * cleanly. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_exit (int errorcode) +{ + /* de-initialisation is done by the gdk_exit_funct(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale () +{ + if (!setlocale (LC_ALL,"")) + g_print ("locale not supported by C library\n"); + + if (!XSupportsLocale ()) + { + g_print ("locale not supported by Xlib, locale set to C\n"); + setlocale (LC_ALL, "C"); + } + + if (!XSetLocaleModifiers ("")) + { + g_print ("can not set locale modifiers\n"); + } + + return setlocale (LC_ALL,NULL); +} + +/* + *-------------------------------------------------------------- + * gdk_events_pending + * + * Returns the number of events pending on the queue. + * These events have already been read from the server + * connection. + * + * Arguments: + * + * Results: + * Returns the number of events on XLib's event queue. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_events_pending () +{ + return XPending (gdk_display); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * "event" is used to hold the received event. + * If "event" is NULL an event is received as normal + * however it is not placed in "event" (and thus no + * error occurs). + * + * Results: + * Returns TRUE if an event was received that we care about + * and FALSE otherwise. This function will also return + * before an event is received if the timeout interval + * runs out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data) +{ + GdkEvent *temp_event; + GdkPredicate event_pred; + GList *temp_list; + XEvent xevent; + + /* If the last event we received was a destroy notify + * event then we will actually destroy the "gdk" data + * structures now. We don't want to destroy them at the + * time of receiving the event since the main program + * may try to access them and may need to destroy user + * data that has been attached to the window + */ + if (received_destroy_notify) + { + if (gdk_show_events) + g_print ("destroying window:\twindow: %ld\n", + ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id); + + gdk_window_real_destroy (window_to_destroy); + received_destroy_notify = FALSE; + window_to_destroy = NULL; + } + + /* Initially we haven't received an event and want to + * return FALSE. If "event" is non-NULL, then initialize + * it to the nothing event. + */ + if (event) + { + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + } + + if (pred) + { + temp_list = putback_events; + while (temp_list) + { + temp_event = temp_list->data; + + if ((* pred) (temp_event, data)) + { + if (event) + *event = *temp_event; + putback_events = g_list_remove_link (putback_events, temp_list); + g_list_free (temp_list); + return TRUE; + } + + temp_list = temp_list->next; + } + + event_pred.func = pred; + event_pred.data = data; + + if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred)) + if (event) + return gdk_event_translate (event, &xevent); + } + else + { + if (putback_events) + { + temp_event = putback_events->data; + *event = *temp_event; + + temp_list = putback_events; + putback_events = putback_events->next; + if (putback_events) + putback_events->prev = NULL; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + g_free (temp_event); + + return TRUE; + } + + /* Wait for an event to occur or the timeout to elapse. + * If an event occurs "gdk_event_wait" will return TRUE. + * If the timeout elapses "gdk_event_wait" will return + * FALSE. + */ + if (gdk_event_wait ()) + { + /* If we get here we can rest assurred that an event + * has occurred. Read it. + */ + XNextEvent (gdk_display, &xevent); + + event->any.send_event = xevent.xany.send_event; + + /* If "event" non-NULL. + */ + if (event) + return gdk_event_translate (event, &xevent); + } + } + + return FALSE; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_if_fail (event != NULL); + + new_event = g_new (GdkEvent, 1); + *new_event = *event; + + putback_events = g_list_prepend (putback_events, new_event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_copy + * + * Copy a event structure into new storage. + * + * Arguments: + * "event" is the event struct to copy. + * + * Results: + * A new event structure. Free it with gdk_event_free. + * + * Side effects: + * The reference count of the window in the event is increased. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *event_chunk; + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_val_if_fail (event != NULL, NULL); + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEvent), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEvent, event_chunk); + *new_event = *event; + gdk_window_ref (new_event->any.window); + return new_event; +} + +/* + *-------------------------------------------------------------- + * gdk_event_free + * + * Free a event structure obtained from gdk_event_copy. Do not use + * with other event structures. + * + * Arguments: + * "event" is the event struct to free. + * + * Results: + * + * Side effects: + * The reference count of the window in the event is decreased and + * might be freed, too. + * + *-------------------------------------------------------------- */ + +void +gdk_event_free (GdkEvent *event) +{ + g_assert (event_chunk != NULL); + g_return_if_fail (event != NULL); + + gdk_window_unref (event->any.window); + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_set_debug_level + * + * Sets the debugging level. + * + * Arguments: + * "level" is the new debugging level. + * + * Results: + * + * Side effects: + * Other function calls to "gdk" use the debugging + * level to determine what kind of debugging information + * to print out. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_debug_level (int level) +{ + gdk_debug_level = level; +} + +/* + *-------------------------------------------------------------- + * gdk_set_show_events + * + * Turns on/off the showing of events. + * + * Arguments: + * "show_events" is a boolean describing whether or + * not to show the events gdk receives. + * + * Results: + * + * Side effects: + * When "show_events" is TRUE, calls to "gdk_event_get" + * will output debugging informatin regarding the event + * received to stdout. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_show_events (int show_events) +{ + gdk_show_events = show_events; +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + gdk_use_xshm = use_xshm; +} + +gint +gdk_get_debug_level () +{ + return gdk_debug_level; +} + +gint +gdk_get_show_events () +{ + return gdk_show_events; +} + +gint +gdk_get_use_xshm () +{ + return gdk_use_xshm; +} + +/* + *-------------------------------------------------------------- + * gdk_time_get + * + * Get the number of milliseconds since the library was + * initialized. + * + * Arguments: + * + * Results: + * The time since the library was initialized is returned. + * This time value is accurate to milliseconds even though + * a more accurate time down to the microsecond could be + * returned. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_time_get () +{ + struct timeval end; + struct timeval elapsed; + guint32 milliseconds; + + X_GETTIMEOFDAY (&end); + + if (start.tv_usec > end.tv_usec) + { + end.tv_usec += 1000000; + end.tv_sec--; + } + elapsed.tv_sec = end.tv_sec - start.tv_sec; + elapsed.tv_usec = end.tv_usec - start.tv_usec; + + milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000); + + return milliseconds; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_get + * + * Returns the current timer. + * + * Arguments: + * + * Results: + * Returns the current timer interval. This interval is + * in units of milliseconds. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_timer_get () +{ + return timer_val; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_set + * + * Sets the timer interval. + * + * Arguments: + * "milliseconds" is the new value for the timer. + * + * Results: + * + * Side effects: + * Calls to "gdk_event_get" will last for a maximum + * of time of "milliseconds". However, a value of 0 + * milliseconds will cause "gdk_event_get" to block + * indefinately until an event is received. + * + *-------------------------------------------------------------- + */ + +void +gdk_timer_set (guint32 milliseconds) +{ + timer_val = milliseconds; + timer.tv_sec = milliseconds / 1000; + timer.tv_usec = (milliseconds % 1000) * 1000; + +} + +void +gdk_timer_enable () +{ + timerp = &timer; +} + +void +gdk_timer_disable () +{ + timerp = NULL; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + static gint next_tag = 1; + GList *list; + GdkInput *input; + gint tag; + + tag = 0; + list = inputs; + + while (list) + { + input = list->data; + list = list->next; + + if ((input->source == source) && (input->condition == condition)) + { + input->function = function; + input->data = data; + tag = input->tag; + } + } + + if (!tag) + { + input = g_new (GdkInput, 1); + input->tag = next_tag++; + input->source = source; + input->condition = condition; + input->function = function; + input->data = data; + tag = input->tag; + + inputs = g_list_prepend (inputs, input); + } + + return tag; +} + +void +gdk_input_remove (gint tag) +{ + GList *list; + GList *temp_list; + GdkInput *input; + + list = inputs; + while (list) + { + input = list->data; + + if (input->tag == tag) + { + temp_list = list; + + if (list->next) + list->next->prev = list->prev; + if (list->prev) + list->prev->next = list->next; + if (inputs == list) + inputs = list->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + + g_free (temp_list->data); + g_list_free (temp_list); + break; + } + + list = list->next; + } +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + gint return_val; + GdkWindowPrivate *window_private; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + guint xevent_mask; + Window xwindow; + Window xconfine_to; + Cursor xcursor; + int i; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to) + xconfine_to = None; + else + xconfine_to = confine_to_private->xwindow; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + + xevent_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + if (((GdkWindowPrivate *)window)->extension_events && + gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success;; + + if (return_val == Success) + return_val = XGrabPointer (window_private->xdisplay, + xwindow, + owner_events, + xevent_mask, + GrabModeAsync, GrabModeAsync, + xconfine_to, + xcursor, + time); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); + + XUngrabPointer (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + GdkWindowPrivate *window_private; + Window xwindow; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + xwindow = window_private->xwindow; + + return XGrabKeyboard (window_private->xdisplay, + xwindow, + owner_events, + GrabModeAsync, GrabModeAsync, + time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + XUngrabKeyboard (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width () +{ + gint return_val; + + return_val = DisplayWidth (gdk_display, gdk_screen); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height () +{ + gint return_val; + + return_val = DisplayHeight (gdk_display, gdk_screen); + + return return_val; +} + +void +gdk_key_repeat_disable () +{ + XAutoRepeatOff (gdk_display); +} + +void +gdk_key_repeat_restore () +{ + if (autorepeat) + XAutoRepeatOn (gdk_display); + else + XAutoRepeatOff (gdk_display); +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void gdk_flush () +{ + XSync (gdk_display, False); +} + + +void +gdk_beep () +{ + XBell(gdk_display, 100); +} + + +/* + *-------------------------------------------------------------- + * gdk_event_wait + * + * Waits until an event occurs or the timer runs out. + * + * Arguments: + * + * Results: + * Returns TRUE if an event is ready to be read and FALSE + * if the timer ran out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static gint +gdk_event_wait () +{ + GList *list; + GdkInput *input; + GdkInputCondition condition; + SELECT_MASK readfds; + SELECT_MASK writefds; + SELECT_MASK exceptfds; + int max_input; + int nfd; + + /* If there are no events pending we will wait for an event. + * The time we wait is dependant on the "timer". If no timer + * has been specified then we'll block until an event arrives. + * If a timer has been specified we'll block until an event + * arrives or the timer expires. (This is all done using the + * "select" system call). + */ + + if (XPending (gdk_display) == 0) + { + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_ZERO (&exceptfds); + + FD_SET (connection_number, &readfds); + max_input = connection_number; + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + if (input->condition & GDK_INPUT_READ) + FD_SET (input->source, &readfds); + if (input->condition & GDK_INPUT_WRITE) + FD_SET (input->source, &writefds); + if (input->condition & GDK_INPUT_EXCEPTION) + FD_SET (input->source, &exceptfds); + + max_input = MAX (max_input, input->source); + } + + nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp); + + timerp = NULL; + timer_val = 0; + + if (nfd > 0) + { + if (FD_ISSET (connection_number, &readfds)) + { + if (XPending (gdk_display) == 0) + { + if (nfd == 1) + { + XNoOp (gdk_display); + XFlush (gdk_display); + } + return FALSE; + } + else + return TRUE; + } + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + condition = 0; + if (FD_ISSET (input->source, &readfds)) + condition |= GDK_INPUT_READ; + if (FD_ISSET (input->source, &writefds)) + condition |= GDK_INPUT_WRITE; + if (FD_ISSET (input->source, &exceptfds)) + condition |= GDK_INPUT_EXCEPTION; + + if (condition && input->function) + (* input->function) (input->data, input->source, condition); + } + } + } + else + return TRUE; + + return FALSE; +} + +static gint +gdk_event_translate (GdkEvent *event, + XEvent *xevent) +{ + + GdkWindow *window; + GdkWindowPrivate *window_private; + XComposeStatus compose; + int charcount; + char buf[16]; + gint return_val; + + /* Are static variables used for this purpose thread-safe? */ + static GdkPoint dnd_drag_start = {0,0}, + dnd_drag_oldpos = {0,0}; + static GdkRectangle dnd_drag_dropzone = {0,0,0,0}; + static gint dnd_drag_perhaps = 0; + static GdkWindowPrivate *real_sw = NULL; + static Window dnd_drag_curwin = None, dnd_drag_target = None; + + return_val = FALSE; + + /* Find the GdkWindow that this event occurred in. + * All events occur in some GdkWindow (otherwise, why + * would we be receiving them). It really is an error + * to receive an event for which we cannot find the + * corresponding GdkWindow. We handle events with window=None + * specially - they are generated by XFree86's XInput under + * some circumstances. + */ + + if ((xevent->xany.window == None) && + gdk_input_vtable.window_none_event) + { + return_val = gdk_input_vtable.window_none_event (event,xevent); + + if (return_val >= 0) /* was handled */ + return return_val; + else + return_val = FALSE; + } + + window = gdk_window_lookup (xevent->xany.window); + window_private = (GdkWindowPrivate *) window; + + /* We do a "manual" conversion of the XEvent to a + * GdkEvent. The structures are mostly the same so + * the conversion is fairly straightforward. We also + * optionally print debugging info regarding events + * received. + */ + /* Addendum: + * During drag & drop you get events where the pointer is + * in other windows. Need to just do finer-grained checking + */ + switch (xevent->type) + { + case KeyPress: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key press:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_PRESS; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case KeyRelease: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key release:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_RELEASE; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case ButtonPress: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } + if(window_private + && window_private->dnd_drag_enabled + && !dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + dnd_drag_perhaps = 1; + dnd_drag_start.x = xevent->xbutton.x_root; + dnd_drag_start.y = xevent->xbutton.y_root; + real_sw = window_private; + + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; + + { + /* Set motion mask for first DnD'd window, since it + will be the one that is actually dragged */ + XWindowAttributes dnd_winattr; + XSetWindowAttributes dnd_setwinattr; + Status rv; + + /* We need to get motion events while the button is down, so + we can know whether to really start dragging or not... */ + XGetWindowAttributes(gdk_display, (Window)window_private->xwindow, + &dnd_winattr); + + window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; + dnd_setwinattr.event_mask = + window_private->dnd_drag_eventmask = ButtonMotionMask; + XChangeWindowAttributes(gdk_display, window_private->xwindow, + CWEventMask, &dnd_setwinattr); + } + } + return_val = window_private?(!window_private->destroyed):FALSE; + break; + + case ButtonRelease: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if(dnd_drag_perhaps) + { + if(gdk_dnd.drag_really) + { + GdkPoint foo = {xevent->xbutton.x_root, + xevent->xbutton.y_root}; + XUngrabPointer(gdk_display, CurrentTime); + + if(dnd_drag_target != None) + gdk_dnd_drag_end(dnd_drag_target, foo); + gdk_dnd.drag_really = 0; + + if(gdk_dnd.drag_numwindows) + { + XSetWindowAttributes attrs; + /* Reset event mask to pre-drag value, assuming event_mask + doesn't change during drag */ + attrs.event_mask = real_sw->dnd_drag_savedeventmask; + XChangeWindowAttributes(gdk_display, real_sw->xwindow, + CWEventMask, &attrs); + } + + gdk_dnd.drag_numwindows = 0; + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + + real_sw = NULL; + } + + dnd_drag_perhaps = 0; + dnd_drag_start.x = dnd_drag_start.y = 0; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_curwin = None; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case MotionNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n", + xevent->xmotion.window - base_id, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false", + dnd_drag_perhaps, gdk_dnd.drag_really); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + event->motion.time = xevent->xmotion.time; + event->motion.x = xevent->xmotion.x; + event->motion.y = xevent->xmotion.y; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = (GdkModifierType) xevent->xmotion.state; + event->motion.is_hint = xevent->xmotion.is_hint; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + +#define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \ + && cy >= dnd_drag_dropzone.y \ + && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \ + && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height)) + + if(dnd_drag_perhaps && gdk_dnd.drag_really) + { + /* First, we have to find what window the motion was in... */ + /* XXX there has to be a better way to do this, perhaps with + XTranslateCoordinates or XQueryTree - I don't know how, + and this sort of works */ + Window curwin, childwin = gdk_root_window, rootwinret; + int x, y; + unsigned int mask; + while(childwin != None) + { + curwin = childwin; + XQueryPointer(gdk_display, curwin, &rootwinret, &childwin, + &x, &y, &x, &y, &mask); + } + if(curwin != dnd_drag_curwin) + { + /* We have left one window and entered another + (do leave & enter bits) */ + if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None) + gdk_dnd_drag_leave(dnd_drag_curwin); + dnd_drag_curwin = curwin; + gdk_dnd_drag_enter(dnd_drag_curwin); + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_target = None; + XChangeActivePointerGrab(gdk_display, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragdefault, + CurrentTime); + } + else if(dnd_drag_dropzone.width > 0 + && dnd_drag_dropzone.height > 0) + { + /* Handle all that dropzone stuff - thanks John ;-) */ + if(dnd_drag_target != None + && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y) + && !IS_IN_ZONE(xevent->xmotion.x_root, + xevent->xmotion.y_root)) + { + /* We were in the drop zone and moved out */ + dnd_drag_target = None; + gdk_dnd_drag_leave(curwin); + } + else + { + /* We were outside drop zone but in the window + - have to send enter events */ + gdk_dnd_drag_enter(curwin); + dnd_drag_curwin = curwin; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_target = None; + } + } else + dnd_drag_curwin = None; + return_val = FALSE; + } + else + return_val = window?(!window_private->destroyed):FALSE; + break; + + case EnterNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow - base_id); + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&xevent->xcrossing, window); + + event->crossing.type = GDK_ENTER_NOTIFY; + event->crossing.window = window; + + /* If the subwindow field of the XEvent is non-NULL, then + * lookup the corresponding GdkWindow. + */ + if (xevent->xcrossing.subwindow != None) + event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + if(dnd_drag_perhaps + && gdk_dnd.drag_really + && xevent->xcrossing.window == real_sw->xwindow) + { + gdk_dnd.drag_really = 0; + XUngrabPointer(gdk_display, CurrentTime); + } + + return_val = (window ? !window_private->destroyed : FALSE); + break; + + case LeaveNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + if(dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + gdk_dnd_drag_addwindow((GdkWindow *) real_sw); + gdk_dnd_drag_begin((GdkWindow *) real_sw); + XGrabPointer(gdk_display, real_sw->xwindow, False, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + GrabModeAsync, GrabModeAsync, gdk_root_window, + gdk_dnd.gdk_cursor_dragdefault, CurrentTime); + gdk_dnd.drag_really = 1; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case FocusIn: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus in:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = TRUE; + + return_val = !window_private->destroyed; + break; + + case FocusOut: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus out:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = FALSE; + + return_val = !window_private->destroyed; + break; + + case KeymapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("keymap notify\n"); + + /* Not currently handled */ + break; + + case Expose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n", + xevent->xexpose.window - base_id, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xexpose.x; + event->expose.area.y = xevent->xexpose.y; + event->expose.area.width = xevent->xexpose.width; + event->expose.area.height = xevent->xexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case GraphicsExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("graphics expose:\tdrawable: %ld\n", + xevent->xgraphicsexpose.drawable - base_id); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xgraphicsexpose.x; + event->expose.area.y = xevent->xgraphicsexpose.y; + event->expose.area.width = xevent->xgraphicsexpose.width; + event->expose.area.height = xevent->xgraphicsexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case NoExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("no expose:\t\tdrawable: %ld\n", + xevent->xnoexpose.drawable - base_id); + + /* Not currently handled */ + break; + + case VisibilityNotify: + /* Print debugging info. + */ + if (gdk_show_events) + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + g_print ("visibility notify:\twindow: %ld none\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityPartiallyObscured: + g_print ("visibility notify:\twindow: %ld partial\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityUnobscured: + g_print ("visibility notify:\twindow: %ld full\n", + xevent->xvisibility.window - base_id); + break; + } + + /* Not currently handled */ + break; + + case CreateNotify: + /* Not currently handled */ + break; + + case DestroyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("destroy notify:\twindow: %ld\n", + xevent->xdestroywindow.window - base_id); + + event->any.type = GDK_DESTROY; + event->any.window = window; + + /* Remeber which window received the destroy notify + * event so that we can destroy our associated + * data structures the next time the user asks + * us for an event. + */ + received_destroy_notify = TRUE; + window_to_destroy = window; + + return_val = !window_private->destroyed; + break; + + case UnmapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("unmap notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case MapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("map notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case ReparentNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("reparent notify:\twindow: %ld\n", + xevent->xreparent.window - base_id); + + /* Not currently handled */ + break; + + case ConfigureNotify: + /* Print debugging info. + */ + while ((XPending(gdk_display) > 0) && + XCheckTypedWindowEvent(gdk_display, xevent->xany.window, + ConfigureNotify, xevent)) + /*XSync(gdk_display, 0)*/; + + if (gdk_show_events) + g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d\n", + xevent->xconfigure.window - base_id, + xevent->xconfigure.x, xevent->xconfigure.y, + xevent->xconfigure.width, xevent->xconfigure.height); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&xevent->xconfigure, window); + + if ((window_private->window_type != GDK_WINDOW_CHILD) && + ((window_private->width != xevent->xconfigure.width) || + (window_private->height != xevent->xconfigure.height))) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = xevent->xconfigure.x; + event->configure.y = xevent->xconfigure.y; + event->configure.width = xevent->xconfigure.width; + event->configure.height = xevent->xconfigure.height; + + window_private->x = xevent->xconfigure.x; + window_private->y = xevent->xconfigure.y; + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + } + break; + + case PropertyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("property notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = xevent->xproperty.atom; + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + + return_val = !window_private->destroyed; + break; + + case SelectionClear: + if (gdk_show_events) + g_print ("selection clear:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->xselectionclear.selection; + event->selection.time = xevent->xselectionclear.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionRequest: + if (gdk_show_events) + g_print ("selection request:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = xevent->xselectionrequest.selection; + event->selection.target = xevent->xselectionrequest.target; + event->selection.property = xevent->xselectionrequest.property; + event->selection.requestor = xevent->xselectionrequest.requestor; + event->selection.time = xevent->xselectionrequest.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionNotify: + if (gdk_show_events) + g_print ("selection notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->xselection.selection; + event->selection.target = xevent->xselection.target; + event->selection.property = xevent->xselection.property; + event->selection.time = xevent->xselection.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case ColormapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("colormap notify:\twindow: %ld\n", + xevent->xcolormap.window - base_id); + + /* Not currently handled */ + break; + + case ClientMessage: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("client message:\twindow: %ld\n", + xevent->xclient.window - base_id); + + /* Client messages are the means of the window manager + * communicating with a program. We'll first check to + * see if this is really the window manager talking + * to us. + */ + if (xevent->xclient.message_type == gdk_wm_protocols) + { + if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) + { + /* The delete window request specifies a window + * to delete. We don't actually destroy the + * window because "it is only a request". (The + * window might contain vital data that the + * program does not want destroyed). Instead + * the event is passed along to the program, + * which should then destroy the window. + */ + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("delete window:\t\twindow: %ld\n", + xevent->xclient.window - base_id); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !window_private->destroyed; + } + else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) + { + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter) + { + Atom reptype = 0; + + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + if (gdk_show_events) + g_print ("GDK_DROP_ENTER\n"); + return_val = FALSE; + + /* Now figure out if we really want this drop... + * If someone is trying funky clipboard stuff, ignore + */ + if (window_private + && window_private->dnd_drop_enabled + && event->dropenter.u.flags.sendreply + && (reptype = gdk_dnd_check_types (window, xevent))) + { + XEvent replyev; + + replyev.xclient.type = ClientMessage; + replyev.xclient.window = xevent->xclient.data.l[0]; + replyev.xclient.format = 32; + replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest; + replyev.xclient.data.l[0] = window_private->xwindow; + + event->dragrequest.u.allflags = 0; + event->dragrequest.u.flags.protocol_version = + DND_PROTOCOL_VERSION; + event->dragrequest.u.flags.willaccept = 1; + event->dragrequest.u.flags.delete_data = + (window_private->dnd_drop_destructive_op) ? 1 : 0; + + replyev.xclient.data.l[1] = event->dragrequest.u.allflags; + replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0; + replyev.xclient.data.l[4] = reptype; + + XSendEvent (gdk_display, replyev.xclient.window, + False, NoEventMask, &replyev); + + event->any.type = GDK_DROP_ENTER; + event->dropenter.requestor = replyev.xclient.window; + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave) + { + if (gdk_show_events) + g_print ("GDK_DROP_LEAVE\n"); + if (window_private && window_private->dnd_drop_enabled) + { + event->dropleave.type = GDK_DROP_LEAVE; + event->dropleave.window = window; + event->dropleave.requestor = xevent->xclient.data.l[0]; + event->dropleave.u.allflags = xevent->xclient.data.l[1]; + return_val = TRUE; + } + else + return_val = FALSE; + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest) + { + /* + * make sure to only handle requests from the window the cursor is + * over + */ + if (gdk_show_events) + g_print ("GDK_DRAG_REQUEST\n"); + event->dragrequest.u.allflags = xevent->xclient.data.l[1]; + return_val = FALSE; + + if (window && gdk_dnd.drag_really && + xevent->xclient.data.l[0] == dnd_drag_curwin && + event->dragrequest.u.flags.sendreply == 0) + { + /* Got request - do we need to ask user? */ + if (!event->dragrequest.u.flags.willaccept + && event->dragrequest.u.flags.senddata) + { + /* Yes we do :) */ + event->dragrequest.type = GDK_DRAG_REQUEST; + event->dragrequest.window = window; + event->dragrequest.requestor = xevent->xclient.data.l[0]; + event->dragrequest.isdrop = 0; + event->dragrequest.drop_coords.x = + event->dragrequest.drop_coords.y = 0; + return_val = TRUE; + } + else if (event->dragrequest.u.flags.willaccept) + { + window_private->dnd_drag_destructive_op = + event->dragrequest.u.flags.delete_data; + window_private->dnd_drag_accepted = 1; + window_private->dnd_drag_data_type = + xevent->xclient.data.l[4]; + + dnd_drag_target = dnd_drag_curwin; + XChangeActivePointerGrab (gdk_display, + ButtonMotionMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragok, + CurrentTime); + } + dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535; + dnd_drag_dropzone.y = + (xevent->xclient.data.l[2] >> 16) & 65535; + dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535; + dnd_drag_dropzone.height = + (xevent->xclient.data.l[3] >> 16) & 65535; + } + } + else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable) + { + gint tmp_int; Atom tmp_atom; + gulong tmp_long; + guchar *tmp_charptr; + gpointer tmp_ptr; + + if(gdk_show_events) + g_print("GDK_DROP_DATA_AVAIL\n"); + event->dropdataavailable.u.allflags = xevent->xclient.data.l[1]; + if(window + /* No preview of data ATM */ + && event->dropdataavailable.u.flags.isdrop) + { + event->dropdataavailable.type = GDK_DROP_DATA_AVAIL; + event->dropdataavailable.window = window; + event->dropdataavailable.requestor = xevent->xclient.data.l[0]; + event->dropdataavailable.data_type = + gdk_atom_name(xevent->xclient.data.l[2]); + if(XGetWindowProperty (gdk_display, + event->dropdataavailable.requestor, + xevent->xclient.data.l[2], + 0, LONG_MAX - 1, + False, XA_PRIMARY, &tmp_atom, + &tmp_int, + &event->dropdataavailable.data_numbytes, + &tmp_long, + &tmp_charptr) + != Success) + { + g_warning("XGetWindowProperty on %#x may have failed\n", + event->dropdataavailable.requestor); + event->dropdataavailable.data = NULL; + } + else + { + g_print("XGetWindowProperty got us %d bytes\n", + event->dropdataavailable.data_numbytes); + event->dropdataavailable.data = + g_malloc(event->dropdataavailable.data_numbytes); + memcpy(event->dropdataavailable.data, + tmp_charptr, event->dropdataavailable.data_numbytes); + XFree(tmp_charptr); + return_val = TRUE; + } + return_val = TRUE; + } + } else { + /* Send unknown ClientMessage's on to Gtk for it to use */ + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->xclient.message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + return_val = TRUE; + } + return_val = return_val && !window_private->destroyed; + break; + + case MappingNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("mapping notify\n"); + + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&xevent->xmapping); + break; + + default: + /* something else - (e.g., a Xinput event) */ + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.other_event) + return_val = gdk_input_vtable.other_event(event, xevent, window); + + if (return_val < 0) /* not an XInput event, convert */ + { + event->other.type = GDK_OTHER_EVENT; + event->other.window = window; + event->other.xevent = &other_xevent[other_xevent_i]; + memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent)); + other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE; + return_val = TRUE; + } + + return_val = return_val && !window_private->destroyed; + break; + } + + return return_val; +} + +static Bool +gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg) +{ + GdkEvent event; + GdkPredicate *pred; + + if (gdk_event_translate (&event, xevent)) + { + pred = (GdkPredicate*) arg; + return (* pred->func) (&event, pred->data); + } + + return FALSE; +} + +static void +gdk_synthesize_click (GdkEvent *event, + gint nclicks) +{ + GdkEvent temp_event; + + g_return_if_fail (event != NULL); + + temp_event = *event; + temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; + + gdk_event_put (&temp_event); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func () +{ + if (initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + + XCloseDisplay (gdk_display); + initialized = 0; + } +} + +/* + *-------------------------------------------------------------- + * gdk_x_error + * + * The X error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * "error" is the XErrorEvent that we are handling. + * + * Results: + * Either we were expecting some sort of error to occur, + * in which case we set the "gdk_error_code" flag, or this + * error was unexpected, in which case we will print an + * error message and exit. (Since trying to continue will + * most likely simply lead to more errors). + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_error (Display *display, + XErrorEvent *error) +{ + char buf[64]; + + if (gdk_error_warnings) + { + XGetErrorText (display, error->error_code, buf, 63); + g_error ("%s", buf); + } + + gdk_error_code = -1; + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_x_io_error + * + * The X I/O error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * + * Results: + * An X I/O error basically means we lost our connection + * to the X server. There is not much we can do to + * continue, so simply print an error message and exit. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_io_error (Display *display) +{ + g_error ("an x io error occurred"); + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_signal + * + * The signal handler. + * + * Arguments: + * "sig_num" is the number of the signal we received. + * + * Results: + * The signals we catch are all fatal. So we simply build + * up a nice little error message and print it and exit. + * If in the process of doing so another signal is received + * we notice that we are already exiting and simply kill + * our process. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static RETSIGTYPE +gdk_signal (int sig_num) +{ + static int caught_fatal_sig = 0; + char *sig; + + if (caught_fatal_sig) + kill (getpid (), sig_num); + caught_fatal_sig = 1; + + switch (sig_num) + { + case SIGHUP: + sig = "sighup"; + break; + case SIGINT: + sig = "sigint"; + break; + case SIGQUIT: + sig = "sigquit"; + break; + case SIGBUS: + sig = "sigbus"; + break; + case SIGSEGV: + sig = "sigsegv"; + break; + case SIGPIPE: + sig = "sigpipe"; + break; + case SIGTERM: + sig = "sigterm"; + break; + default: + sig = "unknown signal"; + break; + } + + g_print ("\n** ERROR **: %s caught\n", sig); + gdk_exit (1); +} + +static void +gdk_dnd_drag_begin (GdkWindow *initial_window) +{ + GdkEventDragBegin tev; + tev.type = GDK_DRAG_BEGIN; + tev.window = initial_window; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + + gdk_event_put ((GdkEvent *) &tev); +} + +static void +gdk_dnd_drag_enter (Window dest) +{ + XEvent sev; + GdkEventDropEnter tev; + int i; + GdkWindowPrivate *wp; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeEnter; + sev.xclient.window = dest; + + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.u.flags.sendreply = 1; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_data_numtypesavail) + { + sev.xclient.data.l[0] = wp->xwindow; + tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0; + sev.xclient.data.l[1] = tev.u.allflags; + sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0]; + if (wp->dnd_drag_data_numtypesavail > 1) + { + sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1]; + if (wp->dnd_drag_data_numtypesavail > 2) + { + sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2]; + } + else + sev.xclient.data.l[4] = None; + } + else + sev.xclient.data.l[3] = sev.xclient.data.l[4] = None; + XSendEvent (gdk_display, dest, False, NoEventMask, &sev); + } + + } +} + +static void +gdk_dnd_drag_leave (Window dest) +{ + XEvent sev; + GdkEventDropLeave tev; + int i; + GdkWindowPrivate *wp; + + tev.u.allflags = 0; + + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + sev.xclient.type = ClientMessage; + sev.xclient.window = dest; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeLeave; + sev.xclient.data.l[1] = tev.u.allflags; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + sev.xclient.data.l[0] = wp->xwindow; + XSendEvent(gdk_display, dest, False, NoEventMask, &sev); + wp->dnd_drag_accepted = 0; + } +} + +/* + * when a drop occurs, we go through the list of windows being dragged and + * tell them that it has occurred, so that they can set things up and reply + * to 'dest' window + */ +static void +gdk_dnd_drag_end (Window dest, + GdkPoint coords) +{ + GdkWindowPrivate *wp; + GdkEventDragRequest tev; + gchar *tmp_cptr; + int i; + + tev.type = GDK_DRAG_REQUEST; + tev.drop_coords = coords; + tev.requestor = dest; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.isdrop = 1; + + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_accepted) + { + tev.window = (GdkWindow *) wp; + tev.u.flags.delete_data = wp->dnd_drag_destructive_op; + tev.data_type = + gdk_atom_name(wp->dnd_drag_data_type); + + gdk_event_put((GdkEvent *) &tev); + } + } +} + +static GdkAtom +gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent) +{ + GdkWindowPrivate *wp = (GdkWindowPrivate *) window; + int i, j; + GdkEventDropEnter event; + + g_return_val_if_fail(window != NULL, 0); + g_return_val_if_fail(xevent != NULL, 0); + g_return_val_if_fail(xevent->type == ClientMessage, 0); + g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0); + + if(wp->dnd_drop_data_numtypesavail <= 0 || + !wp->dnd_drop_data_typesavail) + return 0; + + for (i = 2; i <= 4; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j]) + return xevent->xclient.data.l[i]; + } + } + + /* Now we get the extended type list if it's available */ + event.u.allflags = xevent->xclient.data.l[1]; + if (event.u.flags.extended_typelist) + { + Atom *exttypes, realtype; + gulong nitems, nbar; + gint realfmt; + + if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0], + gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1, + False, AnyPropertyType, &realtype, &realfmt, + &nitems, &nbar, (unsigned char **) &exttypes) + != Success) + return 0; + + if (realfmt != (sizeof(Atom) * 8)) + { + g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n", + realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]); + return 0; + } + + for (i = 0; i <= nitems; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (exttypes[i] == wp->dnd_drop_data_typesavail[j]) + { + XFree (exttypes); + return exttypes[i]; + } + } + } + XFree (exttypes); + } + return 0; +} + +/* + * used for debugging only + */ +static void +gdk_print_atom (GdkAtom anatom) +{ + gchar *tmpstr = NULL; + tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)"; + g_print("Atom %lu has name %s\n", anatom, tmpstr); + if(tmpstr) + g_free(tmpstr); +} + +/* + * used only by below routine and itself + */ +static Window +getchildren (Display *dpy, + Window win, + Atom WM_STATE) +{ + Window root, parent, *children, inf = 0; + Atom type = None; + unsigned int nchildren, i; + int format; + unsigned long nitems, after; + unsigned char *data; + + if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) + return 0; + + for (i = 0; !inf && (i < nchildren); i++) + { + XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + if (type != 0) + inf = children[i]; + } + + for (i = 0; !inf && (i < nchildren); i++) + inf = getchildren (dpy, children[i], WM_STATE); + + if (children != 0) + XFree ((char *) children); + + return inf; +} + +/* + * find a window with WM_STATE, else return win itself, as per ICCCM + * + * modification of the XmuClientWindow() routine from X11R6.3 + */ +Window +gdk_get_client_window (Display *dpy, + Window win) +{ + Atom WM_STATE; + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window inf; + + if (win == 0) + return DefaultRootWindow(dpy); + + if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0) + return win; + + XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data); + if (type) + return win; + + inf = getchildren (dpy, win, WM_STATE); + + if (inf == 0) + return win; + else + return inf; +} + +static GdkWindow * +gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y) +{ + GdkWindow *retval = w; + GdkWindowPrivate *awin; + GList *children; + gint16 myx = *x, myy = *y; + + g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL); + + myx = *x; + myy = *y; + +descend: + for (children = gdk_window_get_children(retval); + children && children->next; + children = children->next) + { + awin = (GdkWindowPrivate *) children->data; + if ((myx >= awin->x) && (myy >= awin->y) + && (myx < (awin->x + awin->width)) + && (myy < (awin->y + awin->height))) + { + retval = (GdkWindow *) awin; + myx -= awin->x; + myy -= awin->y; + goto descend; + } + } + + *x = myx; + *y = myy; + + return retval; +} + +/* Sends a ClientMessage to all toplevel client windows */ +void +gdk_event_send_clientmessage_toall(GdkEvent *event) +{ + XEvent sev; + Window *ret_children, ret_root, ret_parent, curwin; + unsigned int ret_nchildren; + int i; + + g_return_if_fail(event != NULL); + + /* Set up our event to send, with the exception of its target window */ + sev.xclient.type = ClientMessage; + sev.xclient.display = gdk_display; + sev.xclient.format = event->client.data_format; + sev.xclient.serial = CurrentTime; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + /* OK, we're all set, now let's find some windows to send this to */ + if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent, + &ret_children, &ret_nchildren) != True) + return; + + /* foreach true child window of the root window, send an event to it */ + for(i = 0; i < ret_nchildren; i++) { + curwin = gdk_get_client_window(gdk_display, ret_children[i]); + sev.xclient.window = curwin; + XSendEvent(gdk_display, curwin, False, NoEventMask, &sev); + } + + XFree(ret_children); +} diff --git a/gdk/gdk.h b/gdk/gdk.h new file mode 100644 index 0000000000..ac341b2067 --- /dev/null +++ b/gdk/gdk.h @@ -0,0 +1,614 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GDK_H__ +#define __GDK_H__ + + +#include <gdk/gdktypes.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Initialization, exit and events + */ +void gdk_init (int *argc, + char ***argv); +void gdk_exit (int error_code); +gchar* gdk_set_locale (void); + +gint gdk_events_pending (void); +gint gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data); +void gdk_event_put (GdkEvent *event); + +GdkEvent *gdk_event_copy (GdkEvent *event); +void gdk_event_free (GdkEvent *event); + +void gdk_set_debug_level (gint level); +void gdk_set_show_events (gint show_events); +void gdk_set_use_xshm (gint use_xshm); + +gint gdk_get_debug_level (void); +gint gdk_get_show_events (void); +gint gdk_get_use_xshm (void); + +guint32 gdk_time_get (void); +guint32 gdk_timer_get (void); +void gdk_timer_set (guint32 milliseconds); +void gdk_timer_enable (void); +void gdk_timer_disable (void); + +gint gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data); +void gdk_input_remove (gint tag); + +gint gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time); +void gdk_pointer_ungrab (guint32 time); + +gint gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time); +void gdk_keyboard_ungrab (guint32 time); + +gint gdk_screen_width (void); +gint gdk_screen_height (void); + +void gdk_flush (void); +void gdk_beep (void); + +void gdk_key_repeat_disable (void); +void gdk_key_repeat_restore (void); + + +/* Visuals + */ +gint gdk_visual_get_best_depth (void); +GdkVisualType gdk_visual_get_best_type (void); +GdkVisual* gdk_visual_get_system (void); +GdkVisual* gdk_visual_get_best (void); +GdkVisual* gdk_visual_get_best_with_depth (gint depth); +GdkVisual* gdk_visual_get_best_with_type (GdkVisualType visual_type); +GdkVisual* gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type); + +/* Actually, these are no-ops... */ +GdkVisual* gdk_visual_ref (GdkVisual *visual); +void gdk_visual_unref (GdkVisual *visual); + +void gdk_query_depths (gint **depths, + gint *count); +void gdk_query_visual_types (GdkVisualType **visual_types, + gint *count); +void gdk_query_visuals (GdkVisual **visuals, + gint *count); + + +/* Windows + */ +GdkWindow* gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask); + +GdkWindow * gdk_window_foreign_new (guint32 anid); +void gdk_window_destroy (GdkWindow *window); +GdkWindow* gdk_window_ref (GdkWindow *window); +void gdk_window_unref (GdkWindow *window); + +void gdk_window_show (GdkWindow *window); +void gdk_window_hide (GdkWindow *window); +void gdk_window_move (GdkWindow *window, + gint x, + gint y); +void gdk_window_resize (GdkWindow *window, + gint width, + gint height); +void gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y); +void gdk_window_clear (GdkWindow *window); +void gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_clear_area_e(GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height); +void gdk_window_raise (GdkWindow *window); +void gdk_window_lower (GdkWindow *window); + +void gdk_window_set_user_data (GdkWindow *window, + gpointer user_data); + + +/* + * This allows for making shaped (partially transparent) windows + * - cool feature, needed for Drag and Drag for example. + * The shape_mask can be the mask + * from gdk_pixmap_create_from_xpm. Stefan Wille + */ +void gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y); + +/* + * Drag & Drop + * Algorithm (drop source): + * A window being dragged will be sent a GDK_DRAG_BEGIN message. + * It will then do gdk_dnd_drag_addwindow() for any other windows that are to be + * dragged. + * When we get a DROP_ENTER incoming, we send it on to the window in question. + * That window needs to use gdk_dnd_drop_enter_reply() to indicate the state of + * things (it must call that even if it's not going to accept the drop) + * + * These two turn on/off drag or drop, and if enabling it also + * sets the list of types supported. The list of types passed in + * should be in order of decreasing preference. + */ +void gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes); + +/* + *XXX todo: add a GDK_DROP_ENTER which can look at actual data + */ +void gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op); + +/* + * This is used by the GDK_DRAG_BEGIN handler. An example of usage would be a + * file manager where multiple icons were selected and the drag began. + * The icon that the drag actually began on would gdk_dnd_drag_addwindow + * for all the other icons that were being dragged... + */ +void gdk_dnd_drag_addwindow (GdkWindow *window); +void gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes); + + +void gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags); +void gdk_window_set_title (GdkWindow *window, + const gchar *title); +void gdk_window_set_background (GdkWindow *window, + GdkColor *color); +void gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative); +void gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor); +void gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap); +void gdk_window_get_user_data (GdkWindow *window, + gpointer *data); +void gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth); +void gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y); +void gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height); +GdkVisual* gdk_window_get_visual (GdkWindow *window); +GdkColormap* gdk_window_get_colormap (GdkWindow *window); +GdkWindowType gdk_window_get_type (GdkWindow *window); +gint gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y); +GdkWindow* gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask); +GdkWindow* gdk_window_get_parent (GdkWindow *window); +GdkWindow* gdk_window_get_toplevel (GdkWindow *window); +GList* gdk_window_get_children (GdkWindow *window); +GdkEventMask gdk_window_get_events (GdkWindow *window); +void gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask); + +/* Cursors + */ +GdkCursor* gdk_cursor_new (GdkCursorType cursor_type); +void gdk_cursor_destroy (GdkCursor *cursor); + + +/* GCs + */ +GdkGC* gdk_gc_new (GdkWindow *window); +GdkGC* gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask); +void gdk_gc_destroy (GdkGC *gc); +void gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values); +void gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_background (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_font (GdkGC *gc, + GdkFont *font); +void gdk_gc_set_function (GdkGC *gc, + GdkFunction function); +void gdk_gc_set_fill (GdkGC *gc, + GdkFill fill); +void gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile); +void gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple); +void gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask); +void gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle); +void gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode); +void gdk_gc_set_exposures (GdkGC *gc, + gint exposures); +void gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style); + + +/* Pixmaps + */ +GdkPixmap* gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth); +GdkBitmap* gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height); +GdkPixmap* gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg); +GdkPixmap* gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename); +GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data); +void gdk_pixmap_destroy (GdkPixmap *pixmap); + + + +/* Images + */ +GdkImage* gdk_image_new_bitmap(GdkVisual *, + gpointer, + gint, + gint); +GdkImage* gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height); +GdkImage* gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel); +guint32 gdk_image_get_pixel (GdkImage *image, + gint x, + gint y); +void gdk_image_destroy (GdkImage *image); + + +/* Color + */ +GdkColormap* gdk_colormap_new (GdkVisual *visual, + gint allocate); +void gdk_colormap_destroy (GdkColormap *colormap); + +GdkColormap* gdk_colormap_ref (GdkColormap *cmap); +void gdk_colormap_unref (GdkColormap *cmap); + +GdkColormap* gdk_colormap_get_system (void); +gint gdk_colormap_get_system_size (void); + +void gdk_colormap_change (GdkColormap *colormap, + gint ncolors); +void gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors); +gint gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels); +void gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes); +gint gdk_color_white (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_black (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_parse (const gchar *spec, + GdkColor *color); +gint gdk_color_alloc (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_change (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_equal (GdkColor *colora, + GdkColor *colorb); + + +/* Fonts + */ +GdkFont* gdk_font_load (const gchar *font_name); +GdkFont* gdk_fontset_load (gchar *fontset_name); +void gdk_font_free (GdkFont *font); +void gdk_fontset_free (GdkFont *font); +GdkFont* gdk_font_ref (GdkFont *font); +gint gdk_font_id (GdkFont *font); +gint gdk_font_equal (GdkFont *fonta, + GdkFont *fontb); +gint gdk_string_width (GdkFont *font, + const gchar *string); +gint gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_width (GdkFont *font, + gchar character); +gint gdk_string_measure (GdkFont *font, + const gchar *string); +gint gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_measure (GdkFont *font, + gchar character); + + +/* Drawing + */ +void gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y); +void gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2); +void gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height); +void gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2); +void gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints); +void gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string); +void gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length); +void gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_bitmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints); +void gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs); + + +/* Selections + */ +gint gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event); +GdkWindow* gdk_selection_owner_get (GdkAtom selection); +void gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time); +gint gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *prop_type, + gint *prop_format); +void gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time); + +/* Properties + */ +GdkAtom gdk_atom_intern (const gchar *atom_name, + gint only_if_exists); +gchar* gdk_atom_name (GdkAtom atom); +gint gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format, + gint *actual_length, + guchar **data); + +void gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements); +void gdk_property_delete (GdkWindow *window, + GdkAtom property); + + +/* Rectangle utilities + */ +gint gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest); + +/* XInput support + */ + +void gdk_input_init (void); +void gdk_input_exit (void); +GList *gdk_input_list_devices (void); +void gdk_input_set_extension_events (GdkWindow *window, + gint mask, + GdkExtensionMode mode); +void gdk_input_set_source (guint32 deviceid, + GdkInputSource source); +gint gdk_input_set_mode (guint32 deviceid, + GdkInputMode mode); +void gdk_input_set_axes (guint32 deviceid, + GdkAxisUse *axes); +void gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +GdkTimeCoord *gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + +/* Miscellaneous */ +void gdk_event_send_clientmessage_toall(GdkEvent *event); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_H__ */ diff --git a/gdk/gdkcolor.c b/gdk/gdkcolor.c new file mode 100644 index 0000000000..5e66f089ba --- /dev/null +++ b/gdk/gdkcolor.c @@ -0,0 +1,718 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); + +static GHashTable *colormap_hash = NULL; + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + XColor default_colors[256]; + int size; + int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->visual = visual; + private->next_color = 0; + private->ref_count = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->private_val = private_cmap; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + for (i = 0; i < 256; i++) + default_colors[i].pixel = i; + + XQueryColors (private->xdisplay, + DefaultColormap (private->xdisplay, gdk_screen), + default_colors, visual->colormap_size); + + for (i = 0; i < visual->colormap_size; i++) + { + colormap->colors[i].pixel = default_colors[i].pixel; + colormap->colors[i].red = default_colors[i].red; + colormap->colors[i].green = default_colors[i].green; + colormap->colors[i].blue = default_colors[i].blue; + } + + gdk_colormap_change (colormap, visual->colormap_size); + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + private->private_val = TRUE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocAll); + + size = 1 << visual->red_prec; + for (i = 0; i < size; i++) + colormap->colors[i].red = i * 65535 / (size - 1); + + size = 1 << visual->green_prec; + for (i = 0; i < size; i++) + colormap->colors[i].green = i * 65535 / (size - 1); + + size = 1 << visual->blue_prec; + for (i = 0; i < size; i++) + colormap->colors[i].blue = i * 65535 / (size - 1); + + gdk_colormap_change (colormap, visual->colormap_size); + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + + if (private->ref_count > 0) + return; + + gdk_colormap_remove (colormap); + XFreeColormap (private->xdisplay, private->xcolormap); + g_free (colormap); +} + +void +gdk_colormap_destroy (GdkColormap *colormap) +{ + gdk_colormap_unref (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_if_fail (cmap != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = DefaultColormap (gdk_display, gdk_screen); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->next_color = 0; + private->ref_count = 1; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + return DisplayCells (gdk_display, gdk_screen); +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor palette[256]; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].pixel = colormap->colors[i].pixel; + palette[i].red = colormap->colors[i].red; + palette[i].green = colormap->colors[i].green; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoRed | DoGreen | DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors); + private->next_color = MAX (private->next_color, ncolors); + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + + shift = visual->red_shift; + max_colors = 1 << visual->red_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].red = colormap->colors[i].red; + palette[i].flags = DoRed; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->green_shift; + max_colors = 1 << visual->green_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].green = colormap->colors[i].green; + palette[i].flags = DoGreen; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->blue_shift; + max_colors = 1 << visual->blue_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + break; + + default: + break; + } +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gint +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = XAllocColorCells (private->xdisplay, private->xcolormap, + contiguous, planes, nplanes, pixels, npixels); + + return return_val; +} + +void +gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + GdkColormapPrivate *private; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + + XFreeColors (private->xdisplay, private->xcolormap, + pixels, npixels, planes); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = WhitePixel (gdk_display, gdk_screen); + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = BlackPixel (gdk_display, gdk_screen); + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gint return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (gdk_display, gdk_screen); + + if (XParseColor (gdk_display, xcolormap, spec, &xcolor)) + { + return_val = TRUE; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor xcolor; + gchar available[256]; + gint available_init; + gint return_val; + gint i, index; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.pixel = color->pixel; + xcolor.flags = DoRed | DoGreen | DoBlue; + + return_val = FALSE; + private = (GdkColormapPrivate*) colormap; + + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + if (private->private_val) + { + if (private->next_color > 255) + { + for (i = 0; i < 256; i++) + available[i] = TRUE; + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + *color = colormap->colors[index]; + return_val = TRUE; + } + else + { + return_val = FALSE; + } + } + else + { + xcolor.pixel = 255 - private->next_color; + color->pixel = xcolor.pixel; + private->next_color += 1; + + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + return_val = TRUE; + } + } + else + { + available_init = 1; + + while (1) + { + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + + colormap->colors[color->pixel] = *color; + + return_val = TRUE; + break; + } + else + { + if (available_init) + { + available_init = 0; + for (i = 0; i < 256; i++) + available[i] = TRUE; + } + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + xcolor.red = colormap->colors[index].red; + xcolor.green = colormap->colors[index].green; + xcolor.blue = colormap->colors[index].blue; + } + else + { + return_val = FALSE; + break; + } + } + } + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) + + ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) + + ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + color->pixel = xcolor.pixel; + return_val = TRUE; + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + return_val = TRUE; + } + else + return_val = FALSE; + break; + } + + return return_val; +} + +gint +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.pixel = color->pixel; + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.flags = DoRed | DoGreen | DoBlue; + + private = (GdkColormapPrivate*) colormap; + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + + return TRUE; +} + +gint +gdk_color_equal (GdkColor *colora, + GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +GdkColormap* +gdkx_colormap_get (Colormap xcolormap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + colormap = gdk_colormap_lookup (xcolormap); + if (colormap) + return colormap; + + if (xcolormap == DefaultColormap (gdk_display, gdk_screen)) + return gdk_colormap_get_system (); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = xcolormap; + private->visual = NULL; + private->private_val = TRUE; + private->next_color = 0; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + + return colormap; +} + + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < 256; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} diff --git a/gdk/gdkcursor.c b/gdk/gdkcursor.c new file mode 100644 index 0000000000..22bfd250b1 --- /dev/null +++ b/gdk/gdkcursor.c @@ -0,0 +1,52 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + Cursor xcursor; + + xcursor = XCreateFontCursor (gdk_display, cursor_type); + private = g_new (GdkCursorPrivate, 1); + private->xdisplay = gdk_display; + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + + private = (GdkCursorPrivate *) cursor; + XFreeCursor (private->xdisplay, private->xcursor); + + g_free (private); +} diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c new file mode 100644 index 0000000000..47482f72e6 --- /dev/null +++ b/gdk/gdkdraw.c @@ -0,0 +1,383 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xos.h> +#include "gdk.h" +#include "gdkprivate.h" + + +void +gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawPoint (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y); +} + +void +gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawLine (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x1, y1, x2, y2); +} + +void +gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + if (filled) + XFillRectangle (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height); + else + XDrawRectangle (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height); +} + +void +gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + if (filled) + XFillArc (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height, angle1, angle2); + else + XDrawArc (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height, angle1, angle2); +} + +void +gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (filled) + { + XFillPolygon (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, (XPoint*) points, npoints, Complex, CoordModeOrigin); + } + else + { + XDrawLines (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, (XPoint*) points, npoints, CoordModeOrigin); + + if ((points[0].x != points[npoints-1].x) || + (points[0].y != points[npoints-1].y)) + XDrawLine (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, points[npoints-1].x, points[npoints-1].y, + points[0].x, points[0].y); + } +} + +/* gdk_draw_string + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (string != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + XFontStruct *xfont = (XFontStruct *) font_private->xfont; + XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XDrawString (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, string, strlen (string)); + } + else + { + XDrawString16 (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, (XChar2b *) string, + strlen (string) / 2); + } + } + else if (font->type == GDK_FONT_FONTSET) + { + XFontSet fontset = (XFontSet) font_private->xfont; + XmbDrawString (drawable_private->xdisplay, drawable_private->xwindow, + fontset, gc_private->xgc, x, y, string, strlen (string)); + } + else + g_error("undefined font type\n"); +} + +/* gdk_draw_text + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + XFontStruct *xfont = (XFontStruct *) font_private->xfont; + XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XDrawString (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, text, text_length); + } + else + { + XDrawString16 (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, (XChar2b *) text, text_length / 2); + } + } + else if (font->type == GDK_FONT_FONTSET) + { + XFontSet fontset = (XFontSet) font_private->xfont; + XmbDrawString (drawable_private->xdisplay, drawable_private->xwindow, + fontset, gc_private->xgc, x, y, text, text_length); + } + else + g_error("undefined font type\n"); +} + +void +gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkWindowPrivate *src_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + src_private = (GdkWindowPrivate*) src; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = src_private->width; + if (height == -1) + height = src_private->height; + + XCopyArea (drawable_private->xdisplay, + src_private->xwindow, + drawable_private->xwindow, + gc_private->xgc, + xsrc, ysrc, + width, height, + xdest, ydest); +} + +void +gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkImagePrivate *image_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + image_private = (GdkImagePrivate*) image; + + g_return_if_fail (image_private->image_put != NULL); + + if (width == -1) + width = image->width; + if (height == -1) + height = image->height; + + (* image_private->image_put) (drawable, gc, image, xsrc, ysrc, + xdest, ydest, width, height); +} + +void +gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail ((points != NULL) && (npoints > 0)); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawPoints (drawable_private->xdisplay, + drawable_private->xwindow, + gc_private->xgc, + (XPoint *) points, + npoints, + CoordModeOrigin); +} + +void +gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + if (nsegs <= 0) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (segs != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawSegments (drawable_private->xdisplay, + drawable_private->xwindow, + gc_private->xgc, + (XSegment *) segs, + nsegs); +} diff --git a/gdk/gdkfont.c b/gdk/gdkfont.c new file mode 100644 index 0000000000..e1b1e72549 --- /dev/null +++ b/gdk/gdkfont.c @@ -0,0 +1,379 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xos.h> +#include "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + private->xfont = XLoadQueryFont (private->xdisplay, font_name); + private->ref_count = 1; + + if (!private->xfont) + { + g_free (font); + return NULL; + } + else + { + font->type = GDK_FONT_FONT; + font->ascent = ((XFontStruct *) private->xfont)->ascent; + font->descent = ((XFontStruct *) private->xfont)->descent; + } + + gdk_xid_table_insert (&((XFontStruct *) private->xfont)->fid, font); + + return font; +} + +GdkFont* +gdk_fontset_load(gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + XFontSet fontset; + gint missing_charset_count; + gchar **missing_charset_list; + gchar *def_string; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + fontset = XCreateFontSet (gdk_display, fontset_name, + &missing_charset_list, &missing_charset_count, + &def_string); + + if (missing_charset_count) + { + g_print ("Missing charsets in FontSet creation"); + XFreeStringList (missing_charset_list); + } + + private->ref_count = 1; + + if (!fontset) + { + g_free (font); + return NULL; + } + else + { + XFontSetExtents *extent = XExtentsOfFontSet(fontset); + + private->xfont = fontset; + font->type = GDK_FONT_FONTSET; + /* how to define ascent and descent for fontset ??? */ + font->ascent = extent->max_logical_extent.height; + font->descent = font->ascent / 4 ; + } + return font; +} +void +gdk_font_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid); + XFreeFont (private->xdisplay, (XFontStruct *) private->xfont); + g_free (font); + } +} + +void +gdk_fontset_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + XFreeFontSet (private->xdisplay, (XFontSet) private->xfont); + g_free (font); + } +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +gint +gdk_font_id (GdkFont *font) +{ + GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + return ((XFontStruct *) font_private->xfont)->fid; + } + else + { + return 0; + } +} + +gint +gdk_font_equal (GdkFont *fonta, + GdkFont *fontb) +{ + GdkFontPrivate *privatea; + GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (GdkFontPrivate*) fonta; + privateb = (GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + { + return (((XFontStruct *) privatea->xfont)->fid == + ((XFontStruct *) privateb->xfont)->fid); + } + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + /* how to compare two fontsets ?? by basename or XFontSet ?? */ + return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont)); + } + else + /* fontset != font */ + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + GdkFontPrivate *font_private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + font_private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) font_private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, string, strlen (string)); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) font_private->xfont; + width = XmbTextEscapement (fontset, string, strlen(string)); + break; + default: + width = 0; + } + + return width; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, text, text_length); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, text, text_length); + break; + default: + width = 0; + } + return width; +} + +/* Problem: What if a character is a 16 bits character ?? */ +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + GdkFontPrivate *private; + XCharStruct *chars; + gint width; + guint ch = character & 0xff; /* get rid of sign-extension */ + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + /* only 8 bits characters are considered here */ + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && + (xfont->max_byte1 == 0) && + (ch >= xfont->min_char_or_byte2) && + (ch <= xfont->max_char_or_byte2)) + { + chars = xfont->per_char; + if (chars) + width = chars[ch - xfont->min_char_or_byte2].width; + else + width = xfont->min_bounds.width; + } + else + { + width = XTextWidth (xfont, &character, 1); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, &character, 1) ; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, log; + int direction; + int font_ascent; + int font_descent; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + width = overall.rbearing; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &log); + width = log.width; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_measure (font, &character, 1); +} diff --git a/gdk/gdkgc.c b/gdk/gdkgc.c new file mode 100644 index 0000000000..3dc11ce6cc --- /dev/null +++ b/gdk/gdkgc.c @@ -0,0 +1,636 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include <X11/Xlib.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkGC* +gdk_gc_new (GdkWindow *window) +{ + return gdk_gc_new_with_values (window, NULL, 0); +} + +GdkGC* +gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGC *gc; + GdkGCPrivate *private; + Window xwindow; + XGCValues xvalues; + unsigned long xvalues_mask; + + private = g_new (GdkGCPrivate, 1); + gc = (GdkGC*) private; + + xwindow = ((GdkWindowPrivate*) window)->xwindow; + private->xdisplay = ((GdkWindowPrivate*) window)->xdisplay; + + xvalues.function = GXcopy; + xvalues.fill_style = FillSolid; + xvalues.arc_mode = ArcPieSlice; + xvalues.subwindow_mode = ClipByChildren; + xvalues.graphics_exposures = True; + xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures; + + if (values_mask & GDK_GC_FOREGROUND) + { + xvalues.foreground = values->foreground.pixel; + xvalues_mask |= GCForeground; + } + if (values_mask & GDK_GC_BACKGROUND) + { + xvalues.background = values->background.pixel; + xvalues_mask |= GCBackground; + } + if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT)) + { + xvalues.font = ((XFontStruct *) ((GdkFontPrivate*) values->font)->xfont)->fid; + xvalues_mask |= GCFont; + } + if (values_mask & GDK_GC_FUNCTION) + { + switch (values->function) + { + case GDK_COPY: + xvalues.function = GXcopy; + break; + case GDK_INVERT: + xvalues.function = GXinvert; + break; + case GDK_XOR: + xvalues.function = GXxor; + break; + } + xvalues_mask |= GCFunction; + } + if (values_mask & GDK_GC_FILL) + { + switch (values->fill) + { + case GDK_SOLID: + xvalues.fill_style = FillSolid; + break; + case GDK_TILED: + xvalues.fill_style = FillTiled; + break; + case GDK_STIPPLED: + xvalues.fill_style = FillStippled; + break; + case GDK_OPAQUE_STIPPLED: + xvalues.fill_style = FillOpaqueStippled; + break; + } + xvalues_mask |= GCFillStyle; + } + if (values_mask & GDK_GC_TILE) + { + xvalues.tile = ((GdkPixmapPrivate*) values->tile)->xwindow; + xvalues_mask |= GCTile; + } + if (values_mask & GDK_GC_STIPPLE) + { + xvalues.stipple = ((GdkPixmapPrivate*) values->stipple)->xwindow; + xvalues_mask |= GCStipple; + } + if (values_mask & GDK_GC_CLIP_MASK) + { + xvalues.clip_mask = ((GdkPixmapPrivate*) values->clip_mask)->xwindow; + xvalues_mask |= GCClipMask; + } + if (values_mask & GDK_GC_SUBWINDOW) + { + xvalues.subwindow_mode = values->subwindow_mode; + xvalues_mask |= GCSubwindowMode; + } + if (values_mask & GDK_GC_TS_X_ORIGIN) + { + xvalues.ts_x_origin = values->ts_x_origin; + xvalues_mask |= GCTileStipXOrigin; + } + if (values_mask & GDK_GC_TS_Y_ORIGIN) + { + xvalues.ts_y_origin = values->ts_y_origin; + xvalues_mask |= GCTileStipYOrigin; + } + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + { + xvalues.clip_x_origin = values->clip_x_origin; + xvalues_mask |= GCClipXOrigin; + } + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + { + xvalues.clip_y_origin = values->clip_y_origin; + xvalues_mask |= GCClipYOrigin; + } + if (values_mask & GDK_GC_EXPOSURES) + { + xvalues.graphics_exposures = values->graphics_exposures; + xvalues_mask |= GCGraphicsExposures; + } + if (values_mask & GDK_GC_LINE_WIDTH) + { + xvalues.line_width = values->line_width; + xvalues_mask |= GCLineWidth; + } + if (values_mask & GDK_GC_LINE_STYLE) + { + switch (values->line_style) + { + case GDK_LINE_SOLID: + xvalues.line_style = LineSolid; + break; + case GDK_LINE_ON_OFF_DASH: + xvalues.line_style = LineOnOffDash; + break; + case GDK_LINE_DOUBLE_DASH: + xvalues.line_style = LineDoubleDash; + break; + } + xvalues_mask |= GCLineStyle; + } + if (values_mask & GDK_GC_CAP_STYLE) + { + switch (values->cap_style) + { + case GDK_CAP_NOT_LAST: + xvalues.cap_style = CapNotLast; + break; + case GDK_CAP_BUTT: + xvalues.cap_style = CapButt; + break; + case GDK_CAP_ROUND: + xvalues.cap_style = CapRound; + break; + case GDK_CAP_PROJECTING: + xvalues.cap_style = CapProjecting; + break; + } + xvalues_mask |= GCCapStyle; + } + if (values_mask & GDK_GC_JOIN_STYLE) + { + switch (values->join_style) + { + case GDK_JOIN_MITER: + xvalues.join_style = JoinMiter; + break; + case GDK_JOIN_ROUND: + xvalues.join_style = JoinRound; + break; + case GDK_JOIN_BEVEL: + xvalues.join_style = JoinBevel; + break; + } + xvalues_mask |= GCJoinStyle; + } + + private->xgc = XCreateGC (private->xdisplay, xwindow, xvalues_mask, &xvalues); + + return gc; +} + +void +gdk_gc_destroy (GdkGC *gc) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + XFreeGC (private->xdisplay, private->xgc); + + memset (gc, 0, sizeof (GdkGCPrivate)); + g_free (gc); +} + +void +gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values) +{ + GdkGCPrivate *private; + XGCValues xvalues; + + g_return_if_fail (gc != NULL); + g_return_if_fail (values != NULL); + + private = (GdkGCPrivate*) gc; + + if (XGetGCValues (private->xdisplay, private->xgc, + GCForeground | GCBackground | GCFont | + GCFunction | GCTile | GCStipple | /* GCClipMask | */ + GCSubwindowMode | GCGraphicsExposures | + GCTileStipXOrigin | GCTileStipYOrigin | + GCClipXOrigin | GCClipYOrigin | + GCLineWidth | GCLineStyle | GCCapStyle | + GCFillStyle | GCJoinStyle, &xvalues)) + { + values->foreground.pixel = xvalues.foreground; + values->background.pixel = xvalues.background; + values->font = gdk_font_lookup (xvalues.font); + + switch (xvalues.function) + { + case GXcopy: + values->function = GDK_COPY; + break; + case GXinvert: + values->function = GDK_INVERT; + break; + case GXxor: + values->function = GDK_XOR; + break; + } + + switch (xvalues.fill_style) + { + case FillSolid: + values->fill = GDK_SOLID; + break; + case FillTiled: + values->fill = GDK_TILED; + break; + case FillStippled: + values->fill = GDK_STIPPLED; + break; + case FillOpaqueStippled: + values->fill = GDK_OPAQUE_STIPPLED; + break; + } + + values->tile = gdk_pixmap_lookup (xvalues.tile); + values->stipple = gdk_pixmap_lookup (xvalues.stipple); + values->clip_mask = NULL; + values->subwindow_mode = xvalues.subwindow_mode; + values->ts_x_origin = xvalues.ts_x_origin; + values->ts_y_origin = xvalues.ts_y_origin; + values->clip_x_origin = xvalues.clip_x_origin; + values->clip_y_origin = xvalues.clip_y_origin; + values->graphics_exposures = xvalues.graphics_exposures; + values->line_width = xvalues.line_width; + + switch (xvalues.line_style) + { + case LineSolid: + values->line_style = GDK_LINE_SOLID; + break; + case LineOnOffDash: + values->line_style = GDK_LINE_ON_OFF_DASH; + break; + case LineDoubleDash: + values->line_style = GDK_LINE_DOUBLE_DASH; + break; + } + + switch (xvalues.cap_style) + { + case CapNotLast: + values->cap_style = GDK_CAP_NOT_LAST; + break; + case CapButt: + values->cap_style = GDK_CAP_BUTT; + break; + case CapRound: + values->cap_style = GDK_CAP_ROUND; + break; + case CapProjecting: + values->cap_style = GDK_CAP_PROJECTING; + break; + } + + switch (xvalues.join_style) + { + case JoinMiter: + values->join_style = GDK_JOIN_MITER; + break; + case JoinRound: + values->join_style = GDK_JOIN_ROUND; + break; + case JoinBevel: + values->join_style = GDK_JOIN_BEVEL; + break; + } + } + else + { + memset (values, 0, sizeof (GdkGCValues)); + } +} + +void +gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + XSetForeground (private->xdisplay, private->xgc, color->pixel); +} + +void +gdk_gc_set_background (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + XSetBackground (private->xdisplay, private->xgc, color->pixel); +} + +void +gdk_gc_set_font (GdkGC *gc, + GdkFont *font) +{ + GdkGCPrivate *gc_private; + GdkFontPrivate *font_private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (font != NULL); + + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + XSetFont (gc_private->xdisplay, gc_private->xgc, + ((XFontStruct *) font_private->xfont)->fid); +} + +void +gdk_gc_set_function (GdkGC *gc, + GdkFunction function) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (function) + { + case GDK_COPY: + XSetFunction (private->xdisplay, private->xgc, GXcopy); + break; + case GDK_INVERT: + XSetFunction (private->xdisplay, private->xgc, GXinvert); + break; + case GDK_XOR: + XSetFunction (private->xdisplay, private->xgc, GXor); + break; + } +} + +void +gdk_gc_set_fill (GdkGC *gc, + GdkFill fill) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (fill) + { + case GDK_SOLID: + XSetFillStyle (private->xdisplay, private->xgc, FillSolid); + break; + case GDK_TILED: + XSetFillStyle (private->xdisplay, private->xgc, FillTiled); + break; + case GDK_STIPPLED: + XSetFillStyle (private->xdisplay, private->xgc, FillStippled); + break; + case GDK_OPAQUE_STIPPLED: + XSetFillStyle (private->xdisplay, private->xgc, FillOpaqueStippled); + break; + } +} + +void +gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile) +{ + GdkGCPrivate *private; + GdkPixmapPrivate *pixmap_private; + Pixmap pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = None; + if (tile) + { + pixmap_private = (GdkPixmapPrivate*) tile; + pixmap = pixmap_private->xwindow; + } + + XSetTile (private->xdisplay, private->xgc, pixmap); +} + +void +gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple) +{ + GdkGCPrivate *private; + GdkPixmapPrivate *pixmap_private; + Pixmap pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = None; + if (stipple) + { + pixmap_private = (GdkPixmapPrivate*) stipple; + pixmap = pixmap_private->xwindow; + } + + XSetStipple (private->xdisplay, private->xgc, pixmap); +} + +void +gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetTSOrigin (private->xdisplay, private->xgc, x, y); +} + +void +gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetClipOrigin (private->xdisplay, private->xgc, x, y); +} + +void +gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask) +{ + GdkGCPrivate *private; + Pixmap xmask; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + if (mask) + xmask = ((GdkWindowPrivate*) mask)->xwindow; + else + xmask = None; + + XSetClipMask (private->xdisplay, private->xgc, xmask); +} + + +void +gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle) +{ + GdkGCPrivate *private; + XRectangle xrectangle; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + xrectangle.x = rectangle->x; + xrectangle.y = rectangle->y; + xrectangle.width = rectangle->width; + xrectangle.height = rectangle->height; + + XSetClipRectangles (private->xdisplay, private->xgc, 0, 0, + &xrectangle, 1, Unsorted); +} + +void +gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetSubwindowMode (private->xdisplay, private->xgc, mode); +} + +void +gdk_gc_set_exposures (GdkGC *gc, + gint exposures) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetGraphicsExposures (private->xdisplay, private->xgc, exposures); +} + +void +gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style) +{ + GdkGCPrivate *private; + int xline_style; + int xcap_style; + int xjoin_style; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (line_style) + { + case GDK_LINE_SOLID: + xline_style = LineSolid; + break; + case GDK_LINE_ON_OFF_DASH: + xline_style = LineOnOffDash; + break; + case GDK_LINE_DOUBLE_DASH: + xline_style = LineDoubleDash; + break; + default: + xline_style = None; + } + + switch (cap_style) + { + case GDK_CAP_NOT_LAST: + xcap_style = CapNotLast; + break; + case GDK_CAP_BUTT: + xcap_style = CapButt; + break; + case GDK_CAP_ROUND: + xcap_style = CapRound; + break; + case GDK_CAP_PROJECTING: + xcap_style = CapProjecting; + break; + default: + xcap_style = None; + } + + switch (join_style) + { + case GDK_JOIN_MITER: + xjoin_style = JoinMiter; + break; + case GDK_JOIN_ROUND: + xjoin_style = JoinRound; + break; + case GDK_JOIN_BEVEL: + xjoin_style = JoinBevel; + break; + default: + xjoin_style = None; + } + + XSetLineAttributes (private->xdisplay, private->xgc, line_width, + xline_style, xcap_style, xjoin_style); +} diff --git a/gdk/gdkglobals.c b/gdk/gdkglobals.c new file mode 100644 index 0000000000..58f7bf8447 --- /dev/null +++ b/gdk/gdkglobals.c @@ -0,0 +1,47 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include <X11/Xlib.h> +#include "gdktypes.h" +#include "gdkprivate.h" + +gint gdk_debug_level = 0; +gint gdk_show_events = FALSE; +gint gdk_use_xshm = TRUE; +gchar *gdk_display_name = NULL; +Display *gdk_display = NULL; +gint gdk_screen; +Window gdk_root_window; +Window gdk_leader_window; +GdkWindowPrivate gdk_root_parent; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +Atom gdk_selection_property; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + None,None, + NULL, + 0, 0, + {0,0}}; +gchar *gdk_progname = NULL; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; diff --git a/gdk/gdkimage.c b/gdk/gdkimage.c new file mode 100644 index 0000000000..bcda3119fc --- /dev/null +++ b/gdk/gdkimage.c @@ -0,0 +1,492 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <sys/types.h> + +#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) +#define USE_SHM +#endif + +#ifdef USE_SHM +#include <sys/ipc.h> +#include <sys/shm.h> +#endif /* USE_SHM */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#ifdef USE_SHM +#include <X11/extensions/XShm.h> +#endif /* USE_SHM */ + +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + + +static GList *image_list = NULL; + + +void +gdk_image_exit () +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap, + 0, 0, w ,h, 8, 0); + private->ximage->data = data; + private->ximage->bitmap_bit_order = MSBFirst; + private->ximage->byte_order = MSBFirst; + image->byte_order = MSBFirst; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +static int +gdk_image_check_xshm(Display *display) +/* + * Desc: query the server for support for the MIT_SHM extension + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +{ +#ifdef USE_SHM + int major, minor, ignore; + Bool pixmaps; + + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) + { + return (pixmaps==True) ? 2 : 1; + } + } +#endif /* USE_SHM */ + return 0; +} + +void +gdk_image_init () +{ + if (gdk_use_xshm) + { + if (!gdk_image_check_xshm (gdk_display)) + { + g_warning ("MIT-SHM Extension not availible on server"); + gdk_use_xshm = False; + } + } +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + Visual *xvisual; + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + + if (!image) + image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = visual->depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + if (gdk_use_xshm) + { + private->image_put = gdk_image_put_shared; + + private->x_shm_info = g_new (XShmSegmentInfo, 1); + x_shm_info = private->x_shm_info; + + private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, NULL, x_shm_info, width, height); + if (private->ximage == NULL) + { + g_warning ("XShmCreateImage failed"); + + g_free (image); + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->shmid = shmget (IPC_PRIVATE, + private->ximage->bytes_per_line * private->ximage->height, + IPC_CREAT | 0777); + + if (x_shm_info->shmid == -1) + { + g_warning ("shmget failed!"); + + XDestroyImage (private->ximage); + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->readOnly = False; + x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0); + private->ximage->data = x_shm_info->shmaddr; + + if (x_shm_info->shmaddr == (char*) -1) + { + g_warning ("shmat failed!"); + + XDestroyImage (private->ximage); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + return NULL; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (x_shm_info->shmaddr != (char*) -1) + shmctl (x_shm_info->shmid, IPC_RMID, 0); +#endif + + gdk_error_code = 0; + gdk_error_warnings = 0; + + XShmAttach (private->xdisplay, x_shm_info); + XSync (private->xdisplay, False); + + gdk_error_warnings = 1; + if (gdk_error_code == -1) + { + g_warning ("XShmAttach failed!"); + + XDestroyImage (private->ximage); + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + return NULL; + } + + if (image) + image_list = g_list_prepend (image_list, image); + } + else + { + g_free (image); + return NULL; + } + break; +#else /* USE_SHM */ + g_free (image); + return NULL; +#endif /* USE_SHM */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, 0, 0, width, height, 32, 0); + + private->ximage->data = g_new (char, private->ximage->bytes_per_line * + private->ximage->height); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + if (image) + { + image->byte_order = private->ximage->byte_order; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + + switch (private->ximage->bits_per_pixel) + { + case 8: + image->bpp = 1; + break; + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + } + } + } + + return image; +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + private->ximage = XGetImage (private->xdisplay, + win_private->xwindow, + x, y, width, height, + AllPlanes, ZPixmap); + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + image->depth = private->ximage->depth; + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + pixel = XGetPixel (private->ximage, x, y); + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + pixel = XPutPixel (private->ximage, x, y, pixel); +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + switch (image->type) + { + case GDK_IMAGE_NORMAL: + XDestroyImage (private->ximage); + break; + + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + XShmDetach (private->xdisplay, private->x_shm_info); + XDestroyImage (private->ximage); + + x_shm_info = private->x_shm_info; + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + + image_list = g_list_remove (image_list, image); +#else /* USE_SHM */ + g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_NORMAL); + + XPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height); +} + +static void +gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ +#ifdef USE_SHM + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_SHARED); + + XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height, False); +#else /* USE_SHM */ + g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ +} diff --git a/gdk/gdkinput.c b/gdk/gdkinput.c new file mode 100644 index 0000000000..ad4b1fcc93 --- /dev/null +++ b/gdk/gdkinput.c @@ -0,0 +1,324 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "../config.h" +#include "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 id); + + +/* Incorporate the specific routines depending on compilation options */ + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +gchar *gdk_input_gxid_host; +gint gdk_input_gxid_port; +gint gdk_input_ignore_core; + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; + +#include "gdkinputnone.h" +#include "gdkinputcommon.h" +#include "gdkinputxfree.h" +#include "gdkinputgxi.h" + +GList * +gdk_input_list_devices () +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +gint +gdk_input_set_mode (guint32 deviceid, GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode(deviceid,mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes) + gdk_input_vtable.set_axes (deviceid, axes); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + XTimeCoord *xcoords; + GdkTimeCoord *coords; + int i; + + if (deviceid == GDK_CORE_POINTER) + { + xcoords = XGetMotionEvents (gdk_display, + ((GdkWindowPrivate *)window)->xwindow, + start, stop, nevents_return); + if (xcoords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + for (i=0; i<*nevents_return; i++) + { + coords[i].time = xcoords[i].time; + coords[i].x = xcoords[i].x; + coords[i].y = xcoords[i].y; + coords[i].pressure = 0.5; + coords[i].xtilt = 0.0; + coords[i].ytilt = 0.0; + } + + XFree(xcoords); + + return coords; + } + else + return NULL; + } + else + { + if (gdk_input_vtable.motion_events) + { + return gdk_input_vtable.motion_events(window, + deviceid, start, stop, + nevents_return); + } + else + { + *nevents_return = 0; + return NULL; + } + } +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find(GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, gint mask, + GdkExtensionMode mode) +{ + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new(GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->obscuring = NULL; + iw->num_obscuring = 0; + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append(gdk_input_windows,iw); + ((GdkWindowPrivate *)window)->extension_events = mask; + + /* Add enter window events to the event mask */ + /* FIXME, this is not needed for XINPUT_NONE */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove(gdk_input_windows,iw); + g_free(iw); + } + + ((GdkWindowPrivate *)window)->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window(window,gdkdev); + else + gdk_input_disable_window(window,gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove(gdk_input_windows,input_window); + g_free(input_window); +} + +void +gdk_input_exit (void) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED); + + g_free(gdkdev->info.name); +#ifndef XINPUT_NONE + g_free(gdkdev->axes); +#endif + g_free(gdkdev->info.axes); + g_free(gdkdev); + } + } + + g_list_free(gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free(tmp_list->data); + } + g_list_free(gdk_input_windows); +} + +static GdkDevicePrivate * +gdk_input_find_device(guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/gdkinput.h b/gdk/gdkinput.h new file mode 100644 index 0000000000..21aee6000b --- /dev/null +++ b/gdk/gdkinput.h @@ -0,0 +1,143 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#ifndef __GDK_INPUT_H__ +#define __GDK_INPUT_H__ + +#ifndef XINPUT_NONE +#include <X11/extensions/XInput.h> +#endif + +typedef struct _GdkAxisInfo GdkAxisInfo; +typedef struct _GdkInputVTable GdkInputVTable; +typedef struct _GdkDevicePrivate GdkDevicePrivate; +typedef struct _GdkInputWindow GdkInputWindow; + +struct _GdkInputVTable { + gint (*set_mode) (guint32 deviceid, GdkInputMode mode); + void (*set_axes) (guint32 deviceid, GdkAxisUse *axes); + GdkTimeCoord* (*motion_events) (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + void (*get_pointer) (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + gint (*grab_pointer) (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); + void (*ungrab_pointer) (guint32 time); + + void (*configure_event) (XConfigureEvent *xevent, GdkWindow *window); + void (*enter_event) (XCrossingEvent *xevent, GdkWindow *window); + gint (*other_event) (GdkEvent *event, XEvent *xevent, GdkWindow *window); + /* Handle an unidentified event. Returns TRUE if handled, FALSE + otherwise */ + gint (*window_none_event) (GdkEvent *event, XEvent *xevent); + gint (*enable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); + gint (*disable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); +}; + +/* information about a device axis */ +struct _GdkAxisInfo +{ + /* reported x resolution */ + gint xresolution; + + /* reported x minimum/maximum values */ + gint xmin_value, xmax_value; + + /* calibrated resolution (for aspect ration) - only relative values + between axes used */ + gint resolution; + + /* calibrated minimum/maximum values */ + gint min_value, max_value; +}; + +#define GDK_INPUT_NUM_EVENTC 6 + +struct _GdkDevicePrivate { + GdkDeviceInfo info; + +#ifndef XINPUT_NONE + /* information about the axes */ + GdkAxisInfo *axes; + + /* reverse lookup on axis use type */ + gint axis_for_use[GDK_AXIS_LAST]; + + /* Information about XInput device */ + XDevice *xdevice; + + int buttonpress_type, buttonrelease_type, motionnotify_type, + proximityin_type, proximityout_type, changenotify_type; + + /* true if we need to select a different set of events, but + can't because this is the core pointer */ + gint needs_update; + + /* Mask of buttons (used for button grabs) */ + gint button_state; + + /* true if we've claimed the device as active. (used only for XINPUT_GXI) */ + gint claimed; +#endif /* !XINPUT_NONE */ +}; + +struct _GdkInputWindow +{ + /* gdk window */ + GdkWindow *window; + + /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */ + GdkExtensionMode mode; + + /* position relative to root window */ + gint16 root_x; + gint16 root_y; + + /* rectangles relative to window of windows obscuring this one */ + GdkRectangle *obscuring; + gint num_obscuring; + + /* Is there a pointer grab for this window ? */ + gint grabbed; +}; + +/* Global data */ + +extern GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +extern gchar *gdk_input_gxid_host; +extern gint gdk_input_gxid_port; +extern gint gdk_input_ignore_core; + +/* Function declarations */ + +void gdk_input_window_destroy (GdkWindow *window); + +#endif __GDK_INPUT_H__ diff --git a/gdk/gdkinputcommon.h b/gdk/gdkinputcommon.h new file mode 100644 index 0000000000..5e457e0aa1 --- /dev/null +++ b/gdk/gdkinputcommon.h @@ -0,0 +1,687 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#if defined(XINPUT_GXI) || defined(XINPUT_XFREE) + +/* Forward declarations */ +static void gdk_input_get_root_relative_geometry (Display *dpy, Window w, + int *x_ret, int *y_ret, + int *width_ret, + int *height_ret); +static GdkDevicePrivate *gdk_input_device_new(XDeviceInfo *device, + gint include_core); +static void gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes); +static void gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_translate_coordinates(GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, + gdouble *pressure, + gdouble *xtilt, gdouble *ytilt); +static guint gdk_input_translate_state(guint state, guint device_state); +static gint gdk_input_common_init(gint include_core); +static gint gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev); +static void gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes); +static GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +/* Global variables */ + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static void +gdk_input_get_root_relative_geometry(Display *dpy, Window w, int *x_ret, int *y_ret, + int *width_ret, int *height_ret) +{ + Window root,parent; + Window *children; + int nchildren; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&x,&y,&width,&height,&border_widthc, + &depthc); + x += border_widthc; + y += border_widthc; + + while (root != parent) + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&xc,&yc,&widthc,&heightc, + &border_widthc,&depthc); + x += xc + border_widthc; + y += yc + border_widthc; + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; + if (width_ret) + *width_ret = width; + if (height_ret) + *height_ret = height; +} + +static GdkDevicePrivate * +gdk_input_device_new(XDeviceInfo *device, gint include_core) +{ + GdkDevicePrivate *gdkdev; + gchar *tmp_name, *p; + XAnyClassPtr class; + gint i,j; + + gdkdev = g_new(GdkDevicePrivate,1); + + gdkdev->info.deviceid = device->id; + if (device->name[0]) { + gdkdev->info.name = g_new(char, strlen(device->name)+1); + strcpy(gdkdev->info.name,device->name); + } else { + /* XFree86 3.2 gives an empty name to the default core devices, + (fixed in 3.2A) */ + gdkdev->info.name = g_strdup("pointer"); + strcpy(gdkdev->info.name,"pointer"); + gdkdev->info.source = GDK_SOURCE_MOUSE; + } + + gdkdev->info.mode = GDK_MODE_DISABLED; + + /* Try to figure out what kind of device this is by its name - + could invite a very, very, long list... Lowercase name + for comparison purposes */ + + tmp_name = g_strdup(gdkdev->info.name); + for (p = tmp_name; *p; p++) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + } + + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + + g_free(tmp_name); + + gdkdev->xdevice = NULL; + + /* step through the classes */ + + gdkdev->info.num_axes = 0; + gdkdev->axes = 0; + gdkdev->info.has_cursor = 0; + gdkdev->needs_update = FALSE; + gdkdev->claimed = FALSE; + gdkdev->button_state = 0; + + class = device->inputclassinfo; + for (i=0;i<device->num_classes;i++) + { + switch (class->class) { + case ButtonClass: + { + break; + } + case ValuatorClass: + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + gdkdev->info.num_axes = xvi->num_axes; + gdkdev->axes = g_new(GdkAxisInfo, xvi->num_axes); + gdkdev->info.axes = g_new(GdkAxisUse, xvi->num_axes); + for (j=0;j<xvi->num_axes;j++) + { + gdkdev->axes[j].resolution = + gdkdev->axes[j].xresolution = xvi->axes[j].resolution; + gdkdev->axes[j].min_value = + gdkdev->axes[j].xmin_value = xvi->axes[j].min_value; + gdkdev->axes[j].max_value = + gdkdev->axes[j].xmax_value = xvi->axes[j].max_value; + gdkdev->info.axes[j] = GDK_AXIS_IGNORE; + } + j=0; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_X; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_Y; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_PRESSURE; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_XTILT; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_YTILT; + + /* set up reverse lookup on axis use */ + for (j=GDK_AXIS_IGNORE;j<GDK_AXIS_LAST;j++) + gdkdev->axis_for_use[j] = -1; + + for (j=0;j<xvi->num_axes;j++) + if (gdkdev->info.axes[j] != GDK_AXIS_IGNORE) + gdkdev->axis_for_use[gdkdev->info.axes[j]] = j; + + break; + } + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + /* return NULL if no axes */ + if (!gdkdev->info.num_axes || !gdkdev->axes || + (!include_core && device->use == IsXPointer)) + { + g_free(gdkdev->info.name); + if (gdkdev->axes) + g_free(gdkdev->axes); + g_free(gdkdev); + return NULL; + } + + if (device->use != IsXPointer) + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + + return gdkdev; +} + +static void +gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes) +{ + gint i; + XEventClass class; + + i = 0; + /* We have to track press and release events in pairs to keep + track of button state correctly and implement grabbing */ + if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK) + { + DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type, + class); + if (class != 0) + classes[i++] = class; + DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type, + class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_MASK) + { + DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_HINT_MASK) + { + /* We'll get into trouble if the macros change, but at least we'll + know about it, and we avoid warnings now */ + DevicePointerMotionHint (gdkdev->xdevice, 0, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_IN_MASK) + { + ProximityIn (gdkdev->xdevice, gdkdev->proximityin_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_OUT_MASK) + { + ProximityOut (gdkdev->xdevice, gdkdev->proximityout_type, class); + if (class != 0) + classes[i++] = class; + } + + *num_classes = i; +} + +static void +gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + XEventClass classes[6]; + gint num_classes; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes); + else + gdk_input_common_find_events(window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + classes, &num_classes); + + XSelectExtensionEvent (gdk_display, + GDK_WINDOW_XWINDOW(window), + classes, num_classes); +} + +gint +gdk_input_common_init(gint include_core) +{ + char **extensions; + XDeviceInfo *devices; + int num_devices; + int num_extensions, loop; + Display *display = gdk_display; + + /* Init global vars */ + gdk_window_get_geometry(NULL, /* use root window */ + NULL,NULL, + &gdk_input_root_width,&gdk_input_root_height, + NULL); + + /* Init XInput extension */ + + extensions = XListExtensions(display, &num_extensions); + for (loop = 0; loop < num_extensions && + (strcmp(extensions[loop], "XInputExtension") != 0); loop++); + XFreeExtensionList(extensions); + if (loop == num_extensions) /* XInput extension not found */ + return FALSE; + + gdk_input_devices = 0; + devices = XListInputDevices(display, &num_devices); + + for(loop=0; loop<num_devices; loop++) + { + GdkDevicePrivate *gdkdev = gdk_input_device_new(&devices[loop], + include_core); + if (gdkdev) + gdk_input_devices = g_list_append(gdk_input_devices, gdkdev); + } + XFreeDeviceList(devices); + + gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); + + return TRUE; +} + +static void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, gdouble *pressure, + gdouble *xtilt, gdouble *ytilt) +{ + GdkWindowPrivate *win_priv; + + int x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; + + double device_width, device_height; + double x_offset, y_offset, x_scale, y_scale; + + win_priv = (GdkWindowPrivate *) input_window->window; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = - input_window->root_x; + y_offset = - input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * win_priv->width >= win_priv->height) + { + /* device taller than window */ + x_scale = win_priv->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + win_priv->height)/2; + } + else + { + /* window taller than device */ + y_scale = win_priv->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = - (device_width * x_scale - win_priv->width)/2; + } + } + + if (x) *x = x_offset + x_scale*axis_data[x_axis]; + if (y) *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +/* combine the state of the core device and the device state + into one - for now we do this in a simple-minded manner - + we just take the keyboard portion of the core device and + the button portion (all of?) the device state. + Any button remapping should go on here. */ +static guint +gdk_input_translate_state(guint state, guint device_state) +{ + return device_state | (state & 0xFF); +} + +static gint +gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev) +{ + if ((xevent->type == gdkdev->buttonpress_type) || + (xevent->type == gdkdev->buttonrelease_type)) + { + XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent); + + if (xdbe->type == gdkdev->buttonpress_type) + { + event->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1 << xdbe->button; + } + else + { + event->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~(1 << xdbe->button); + } + event->button.window = input_window->window; + event->button.time = xdbe->time; + event->button.source = gdkdev->info.source; + event->button.deviceid = xdbe->deviceid; + + gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data, + &event->button.x,&event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state); + event->button.button = xdbe->button; + + return TRUE; + } + + if (xevent->type == gdkdev->motionnotify_type) + { + XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent); + + gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data, + &event->motion.x,&event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = input_window->window; + event->motion.time = xdme->time; + event->motion.deviceid = xdme->deviceid; + event->motion.state = gdk_input_translate_state(xdme->state, + xdme->device_state); + event->motion.source = gdkdev->info.source; + event->motion.deviceid = xdme->deviceid; + + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f hint: %s\n", + xdme->window, + xdme->deviceid, + event->motion.x, event->motion.y, + (xevent->xmotion.is_hint) ? "true" : "false"); + + + return TRUE; + } + + if (xevent->type == gdkdev->proximityin_type || + xevent->type == gdkdev->proximityout_type) + { + XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent); + + event->proximity.type = (xevent->type == gdkdev->proximityin_type)? + GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT; + event->proximity.window = input_window->window; + event->proximity.time = xpne->time; + event->proximity.source = gdkdev->info.source; + event->proximity.deviceid = xpne->deviceid; + + return TRUE; + } + + return -1; /* wasn't one of our event types */ +} + +static void +gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + for (i=GDK_AXIS_IGNORE;i<GDK_AXIS_LAST;i++) + { + gdkdev->axis_for_use[i] = -1; + } + + for (i=0;i<gdkdev->info.num_axes;i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static GdkTimeCoord * +gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkTimeCoord *coords; + XDeviceTimeCoord *device_coords; + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + + int mode_return; + int axis_count_return; + int i; + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_val_if_fail (gdkdev != NULL, NULL); + g_return_val_if_fail (gdkdev->xdevice != NULL, NULL); + g_return_val_if_fail (input_window != NULL, NULL); + + device_coords = XGetDeviceMotionEvents (gdk_display, + gdkdev->xdevice, + start, stop, + nevents_return, &mode_return, + &axis_count_return); + + if (device_coords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + + for (i=0; i<*nevents_return; i++) + { + gdk_input_translate_coordinates (gdkdev, input_window, + device_coords[i].data, + &coords[i].x, &coords[i].y, + &coords[i].pressure, + &coords[i].xtilt, &coords[i].ytilt); + } + XFreeDeviceMotionEvents (device_coords); + + return coords; + } + else + return NULL; +} + +static void +gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + XDeviceState *state; + XInputClass *input_class; + gint x_int, y_int; + gint i; + + /* we probably need to get the mask in any case */ + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_if_fail (gdkdev != NULL); + g_return_if_fail (gdkdev->xdevice != NULL); + g_return_if_fail (input_window != NULL); + + state = XQueryDeviceState (gdk_display, gdkdev->xdevice); + input_class = state->data; + for (i=0; i<state->num_classes; i++) + { + switch (input_class->class) + { + case ValuatorClass: + gdk_input_translate_coordinates(gdkdev, input_window, + ((XValuatorState *)input_class)->valuators, + x, y, pressure, + xtilt, ytilt); + + + break; + case ButtonClass: + if (mask) + { + *mask &= ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK); + for (i=0; i < ((XButtonState *)input_class)->num_buttons; i++) + { + if (((XButtonState *)input_class)->buttons[i]) + *mask |= GDK_BUTTON1_MASK << i; + } + } + break; + } + input_class = (XInputClass *)(((char *)input_class)+input_class->length); + } + } +} + +#endif diff --git a/gdk/gdkinputgxi.h b/gdk/gdkinputgxi.h new file mode 100644 index 0000000000..a30e05f956 --- /dev/null +++ b/gdk/gdkinputgxi.h @@ -0,0 +1,628 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#ifdef XINPUT_GXI + +/* #define DEBUG_SWITCHING */ + +#include <gxid_lib.h> + +/* Forward declarations */ +static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode); +static gint gdk_input_is_extension_device (guint32 deviceid); +static void gdk_input_gxi_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev); + +static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent); +static gint gdk_input_gxi_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static Window gdk_input_find_root_child(Display *dpy, Window w); +static void gdk_input_compute_obscuring(GdkInputWindow *input_window); +static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, + gdouble y); +static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_gxi_ungrab_pointer (guint32 time); + +/* Local variables */ + +static GdkDevicePrivate *gdk_input_current_device; +static GdkDevicePrivate *gdk_input_core_pointer; + +void +gdk_input_init(void) +{ + GList *tmp_list; + + gdk_input_vtable.set_mode = gdk_input_gxi_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_gxi_motion_events; + gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_gxi_configure_event; + gdk_input_vtable.enter_event = gdk_input_gxi_enter_event; + gdk_input_vtable.other_event = gdk_input_gxi_other_event; + gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event; + gdk_input_vtable.enable_window = gdk_input_gxi_enable_window; + gdk_input_vtable.disable_window = gdk_input_gxi_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_core_pointer = NULL; + + if (!gdk_input_gxid_host) + { + gdk_input_gxid_host = getenv("GXID_HOST"); + } + if (!gdk_input_gxid_port) + { + char *t = getenv("GXID_PORT"); + if (t) + gdk_input_gxid_port = atoi(t); + } + + gdk_input_common_init(TRUE); + + /* find initial core pointer */ + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdk_input_is_extension_device(gdkdev->info.deviceid)) + { + gdk_input_gxi_select_notify (gdkdev); + } + else + { + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + gdk_input_core_pointer = gdkdev; + } + } +} + +static void +gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev) +{ + XEventClass class; + + ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class); + + XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1); +} + +/* Set the core pointer. Device should already be enabled. */ +static gint +gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev) +{ + int x_axis,y_axis; + + g_return_val_if_fail(gdkdev->xdevice,FALSE); + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + + g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE); + + /* core_pointer might not be up to date so we check with the server + before change the pointer */ + + if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) ) + { +#if 0 + if (gdkdev != gdk_input_core_pointer) + g_warning("core pointer inconsistency"); +#endif + return TRUE; + } + + if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis) + != Success ) + { + return FALSE; + } + else + { + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + return TRUE; + } +} + + +/* FIXME, merge with gdk_input_xfree_set_mode */ + +static gint +gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (old_mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + if (mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + if (!gdk_input_enable_window(input_window->window, gdkdev)) + { + gdk_input_set_mode(deviceid, old_mode); + return FALSE; + } + } + } + + return TRUE; + +} + +gint +gdk_input_is_extension_device (guint32 deviceid) +{ + XDeviceInfo *devices; + int num_devices, loop; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + devices = XListInputDevices(gdk_display, &num_devices); + for(loop=0; loop<num_devices; loop++) + { + if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice)) + { + XFreeDeviceList(devices); + return TRUE; + } + } + + XFreeDeviceList(devices); + return FALSE; +} + +static void +gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window), + &root_x, &root_y, NULL, NULL); + input_window->root_x = root_x; + input_window->root_y = root_y; + gdk_input_compute_obscuring(input_window); +} + +static void +gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_compute_obscuring(input_window); +} + +static gint +gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (gdkdev->info.mode == GDK_MODE_DISABLED || + input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + if (gdkdev != gdk_input_current_device && + xevent->type != gdkdev->changenotify_type) + { + gdk_input_current_device = gdkdev; + } + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_MOTION_NOTIFY && + (!gdkdev->button_state) && (!input_window->grabbed) && + ((event->motion.x < 0) || (event->motion.y < 0) || + (event->motion.x > ((GdkWindowPrivate *)window)->width) || + (event->motion.y > ((GdkWindowPrivate *)window)->height) || + gdk_input_is_obscured(input_window,event->motion.x,event->motion.y))) + { +#ifdef DEBUG_SWITCHING + g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n", + gdkdev->info.deviceid,event->motion.x,event->motion.y); + g_print(" window geometry is: %dx%d\n", + ((GdkWindowPrivate *)window)->width, + ((GdkWindowPrivate *)window)->height); +#endif + gdk_input_gxi_set_core_pointer(gdkdev); + return FALSE; + } + else + return return_val; + +} + +static void +gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev) +{ + GList *t; + + if (gdk_input_is_extension_device (gdkdev->info.deviceid)) + { + if (!gdkdev->xdevice) + { + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + gdk_input_gxi_select_notify (gdkdev); + gdkdev->needs_update = 1; + } + if (gdkdev->needs_update && gdkdev->xdevice) + { + for (t = gdk_input_windows; t; t = t->next) + gdk_input_common_select_events (((GdkInputWindow *)t->data)->window, + gdkdev); + gdkdev->needs_update = 0; + } + } +} + +static gint +gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent) +{ + GdkDevicePrivate *gdkdev = + gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (xevent->type == gdkdev->changenotify_type) + { + if (gdk_input_core_pointer != gdkdev) + { +#ifdef DEBUG_SWITCHING + g_print("ChangeNotify from %d to %d:\n", + gdk_input_core_pointer->info.deviceid, + gdkdev->info.deviceid); +#endif + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + } + } + + return FALSE; +} + +static gint +gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (!gdkdev->claimed) + { + if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window), FALSE) != + GXID_RETURN_OK) + { + g_warning("Could not get device (is gxid running?)\n"); + return FALSE; + } + gdkdev->claimed = TRUE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (gdkdev->claimed) + { + gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window)); + + gdkdev->claimed = FALSE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y) +{ + int i; + for (i=0;i<input_window->num_obscuring;i++) + { + GdkRectangle *rect = &input_window->obscuring[i]; + if ((x >= rect->x) && + (y >= rect->y) && + (x < rect->x + rect->width) && + (y < rect->y + rect->height)) + return TRUE; + } + return FALSE; +} + +/* If this routine needs fixing, the corresponding routine + in gxid.c will need it too. */ + +static Window +gdk_input_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +void +gdk_input_compute_obscuring(GdkInputWindow *input_window) +{ + int i; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + Window root,parent; + Window *children; + int nchildren; + + Window w = GDK_WINDOW_XWINDOW(input_window->window); + Window root_child = gdk_input_find_root_child(gdk_display,w); + gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height); + + input_window->root_x = x; + input_window->root_y = y; + + XQueryTree(gdk_display,GDK_ROOT_WINDOW(), + &root,&parent,&children,&nchildren); + + + if (input_window->obscuring) + g_free(input_window->obscuring); + input_window->obscuring = 0; + input_window->num_obscuring = 0; + + for (i=0;i<nchildren;i++) + if (children[i] == root_child) + break; + + if (i>=nchildren-1) + { + if (nchildren) + XFree(children); + return; + } + + input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1)); + + for (i=i+1;i<nchildren;i++) + { + int xmin, xmax, ymin, ymax; + XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc, + &border_widthc, &depthc); + xmin = xc>x ? xc : x; + xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width; + ymin = yc>y ? yc : y; + ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height; + if ((xmin < xmax) && (ymin < ymax)) + { + XWindowAttributes attributes; + XGetWindowAttributes(gdk_display,children[i],&attributes); + if (attributes.map_state == IsViewable) + { + GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring]; + + /* we store the whole window, not just the obscuring part */ + rect->x = xc - x; + rect->y = yc - y; + rect->width = widthc; + rect->height = heightc; + input_window->num_obscuring++; + } + } + } + + if (nchildren) + XFree(children); +} + +static void +gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (gdkdev == gdk_input_core_pointer) + gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y, + pressure, xtilt, ytilt, mask); + else + gdk_input_common_get_pointer (window, deviceid, x, y, + pressure, xtilt, ytilt, mask); +} + +static GdkTimeCoord * +gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, NULL); + + + if (gdkdev == gdk_input_core_pointer) + return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop, + nevents_return); + else + return gdk_input_common_motion_events (window, deviceid, start, stop, + nevents_return); + +} + +static gint +gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + new_window = input_window; + + tmp_list = tmp_list->next; + } + + new_window->grabbed = TRUE; + return Success; +} + +static void +gdk_input_gxi_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + input_window->grabbed = FALSE; + tmp_list = tmp_list->next; + } +} + +#endif /* XINPUT_GXI */ diff --git a/gdk/gdkinputnone.h b/gdk/gdkinputnone.h new file mode 100644 index 0000000000..8ae8c4189a --- /dev/null +++ b/gdk/gdkinputnone.h @@ -0,0 +1,72 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#ifdef XINPUT_NONE + +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +void +gdk_input_init () +{ + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + + gdk_input_devices = g_list_append (NULL, &gdk_input_core_info); + + gdk_input_ignore_core = FALSE; +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; +} + +#endif /* XINPUT_NONE */ diff --git a/gdk/gdkinputxfree.h b/gdk/gdkinputxfree.h new file mode 100644 index 0000000000..f742490088 --- /dev/null +++ b/gdk/gdkinputxfree.h @@ -0,0 +1,368 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#ifdef XINPUT_XFREE + +/* forward declarations */ + +static gint gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode); +static void gdk_input_check_proximity(); +static void gdk_input_xfree_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_enable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_disable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_xfree_ungrab_pointer (guint32 time); + +void +gdk_input_init(void) +{ + gdk_input_vtable.set_mode = gdk_input_xfree_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_common_motion_events; + gdk_input_vtable.get_pointer = gdk_input_common_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_xfree_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_xfree_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_xfree_configure_event; + gdk_input_vtable.enter_event = gdk_input_xfree_enter_event; + gdk_input_vtable.other_event = gdk_input_xfree_other_event; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = gdk_input_xfree_enable_window; + gdk_input_vtable.disable_window = gdk_input_xfree_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_common_init(FALSE); +} + +static gint +gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; + +} + +static void +gdk_input_check_proximity() +{ + gint new_proximity = 0; + GList *tmp_list = gdk_input_devices; + + while (tmp_list && !new_proximity) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.mode != GDK_MODE_DISABLED + && gdkdev->info.deviceid != GDK_CORE_POINTER + && gdkdev->xdevice) + { + XDeviceState *state = XQueryDeviceState(GDK_DISPLAY(), + gdkdev->xdevice); + XInputClass *xic; + int i; + + xic = state->data; + for (i=0; i<state->num_classes; i++) + { + if (xic->class == ValuatorClass) + { + XValuatorState *xvs = (XValuatorState *)xic; + if ((xvs->mode & ProximityState) == InProximity) + { + new_proximity = TRUE; + } + break; + } + xic = (XInputClass *)((char *)xic + xic->length); + } + } + tmp_list = tmp_list->next; + } + + gdk_input_ignore_core = new_proximity; +} + +static void +gdk_input_xfree_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_check_proximity(); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static gint +gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + /* FIXME: It would be nice if we could just get rid of the events + entirely, instead of having to ignore them */ + if (gdkdev->info.mode == GDK_MODE_DISABLED || + (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)) + return FALSE; + + if (!gdk_input_ignore_core) + gdk_input_check_proximity(); + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_PROXIMITY_OUT && + gdk_input_ignore_core) + gdk_input_check_proximity(); + + /* Do a passive button grab. We have to be careful not to release + an explicit grab, if any. Doubling the grab should be harmless, + but we check anyways. */ + + /* FIXME, finding the proper events here is going to be SLOW - but + we might have different sets for each window/device combination */ + + if (return_val> 0 && !input_window->grabbed) + { + if (event->type == GDK_BUTTON_PRESS) + { + XEventClass event_classes[6]; + gint num_classes; + + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, event->button.time); + } + else if (event->type == GDK_BUTTON_RELEASE) + XUngrabDevice( GDK_DISPLAY(), gdkdev->xdevice, event->button.time); + } + + return return_val; +} + +static gint +gdk_input_xfree_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + /* FIXME: watchout, gdkdev might be core pointer, never opened */ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + XEventClass event_classes[6]; + gint num_classes; + + tmp_list = gdk_input_windows; + new_window = NULL; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + { + new_window = input_window; + break; + } + + tmp_list = tmp_list->next; + } + + g_return_if_fail (new_window == NULL); + + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + /* FIXME: we should do something on failure */ + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + } + tmp_list = tmp_list->next; + } + + return Success; +} + +static void +gdk_input_xfree_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + XUngrabDevice( gdk_display, gdkdev->xdevice, time); + } + tmp_list = tmp_list->next; + } + } +} + +#endif /* XINPUT_XFREE */ diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c new file mode 100644 index 0000000000..d2d96b6daf --- /dev/null +++ b/gdk/gdkpixmap.c @@ -0,0 +1,657 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <X11/Xlib.h> + +#include "gdk.h" +#include "gdkprivate.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow, + width, height, depth); + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreateBitmapFromData (private->xdisplay, + window_private->xwindow, + data, width, height); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (fg != NULL, NULL); + g_return_val_if_fail (bg != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay, + window_private->xwindow, + data, width, height, + fg->pixel, bg->pixel, depth); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%s", instr); + fscanf(infile, "%s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gchar b, oldb; + + while (!feof (infile)) + { + fscanf(infile, "%c", &b); + if (c != b && b == '/') + { + fscanf (infile, "%c", &b); + if (b == '*') + { + oldb = b; + while (!feof (infile) && !(oldb == '*' && b == '/')) + { + oldb = b; + fscanf (infile, "%c", &b); + } + fscanf (infile, "%c", &b); + } + } + if (c == b) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + int *buffer_size) +{ + gchar c; + gint cnt = 0; + + if ((*buffer) == NULL) + { + (*buffer_size) = 10 * sizeof (gchar); + (*buffer) = (gchar *) malloc (*buffer_size); + } + + do + fscanf (infile, "%c", &c); + while (!feof (infile) && c != '"'); + + if (c != '"') + return FALSE; + + while (!feof (infile)) + { + fscanf (infile, "%c", &c); + + if (cnt == (*buffer_size)) + { + (*buffer_size) *= 2; + (*buffer) = (gchar *) realloc ((*buffer), *buffer_size); + } + + if (c != '"') + (*buffer)[cnt++] = c; + else + { + (*buffer)[cnt++] = 0; + return TRUE; + } + } + + return FALSE; +} + +gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, finished = FALSE, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[128], *retcol; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + if (ptr == NULL) + return NULL; + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + retcol = g_new(gchar, strlen (ptr) + 1); + strcpy (retcol, ptr); + return retcol; + } + + color[0] = 0; + numnames = 0; + + while (finished == FALSE) + { + sscanf (ptr, "%s", temp); + + if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 || + strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0) + finished = TRUE; + else + { + if (numnames > 0) + strcat (color, " "); + strcat (color, temp); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_new(gchar, strlen (color) + 1); + strcpy (retcol, color); + return retcol; +} + + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + FILE *infile = NULL; + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt; + gchar *buffer = NULL, *color_name = NULL, pixel_str[32]; + guint buffer_size = 0; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + infile = fopen (filename, "rb"); + if (infile != NULL) + { + if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE) + { + if (gdk_pixmap_seek_char (infile,'{') == TRUE) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + } + + fclose (infile); + free (buffer); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i; + gchar *buffer, *color_name = NULL, pixel_str[32]; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + i = 0; + buffer = data[i++]; + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + buffer = data[i++]; + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = data[i++]; + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + + return pixmap; +} + +void +gdk_pixmap_destroy (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private; + + g_return_if_fail (pixmap != NULL); + + private = (GdkPixmapPrivate*) pixmap; + if (private->ref_count <= 0) + { + XFreePixmap (private->xdisplay, private->xwindow); + gdk_xid_table_remove (private->xwindow); + g_free (pixmap); + } + else + { + private->ref_count -= 1; + } +} diff --git a/gdk/gdkprivate.h b/gdk/gdkprivate.h new file mode 100644 index 0000000000..3c1677e41f --- /dev/null +++ b/gdk/gdkprivate.h @@ -0,0 +1,197 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GDK_PRIVATE_H__ +#define __GDK_PRIVATE_H__ + + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <gdk/gdktypes.h> + +#define DND_PROTOCOL_VERSION 0 + +#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid)) +#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid)) +#define gdk_font_lookup(xid) ((GdkFont*) gdk_xid_table_lookup (xid)) + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GdkWindowPrivate GdkWindowPrivate; +typedef struct _GdkWindowPrivate GdkPixmapPrivate; +typedef struct _GdkImagePrivate GdkImagePrivate; +typedef struct _GdkGCPrivate GdkGCPrivate; +typedef struct _GdkColormapPrivate GdkColormapPrivate; +typedef struct _GdkVisualPrivate GdkVisualPrivate; +typedef struct _GdkFontPrivate GdkFontPrivate; +typedef struct _GdkCursorPrivate GdkCursorPrivate; + + +struct _GdkWindowPrivate +{ + GdkWindow window; + GdkWindow *parent; + Window xwindow; + Display *xdisplay; + gint16 x; + gint16 y; + guint16 width; + guint16 height; + guint8 resize_count; + guint8 ref_count; + guint8 window_type; + guint8 destroyed : 2; + guint8 dnd_drag_enabled : 1, + dnd_drag_datashow : 1, + dnd_drag_destructive_op : 1, + dnd_drag_accepted : 1, + dnd_drop_enabled : 1, + dnd_drop_destructive_op : 1; + GdkAtom dnd_drag_data_type, *dnd_drag_data_typesavail; + guint dnd_drag_data_numtypesavail; + /* We have to turn on MotionMask/EnterWindowMask/LeaveWindowMask + during drags, then set it back to what it was after */ + glong dnd_drag_savedeventmask, dnd_drag_eventmask; + GdkAtom *dnd_drop_data_typesavail; + guint dnd_drop_data_numtypesavail; + /* need to allow custom drag/drop cursors */ + + gint extension_events; +}; + +struct _GdkImagePrivate +{ + GdkImage image; + XImage *ximage; + Display *xdisplay; + gpointer x_shm_info; + + void (*image_put) (GdkDrawable *window, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +}; + +struct _GdkGCPrivate +{ + GdkGC gc; + GC xgc; + Display *xdisplay; +}; + +struct _GdkColormapPrivate +{ + GdkColormap colormap; + Colormap xcolormap; + Display *xdisplay; + GdkVisual *visual; + gint private_val; + gint next_color; + gint ref_count; +}; + +struct _GdkVisualPrivate +{ + GdkVisual visual; + Visual *xvisual; +}; + +struct _GdkFontPrivate +{ + GdkFont font; + /* XFontStruct *xfont; */ + /* generic pointer point to XFontStruct or XFontSet */ + gpointer xfont; + Display *xdisplay; + gint ref_count; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; + Display *xdisplay; +}; + +struct _GdkDndGlobals { + GdkAtom gdk_XdeEnter, gdk_XdeLeave, gdk_XdeRequest; + GdkAtom gdk_XdeDataAvailable, gdk_XdeDataShow, gdk_XdeCancel; + GdkAtom gdk_XdeTypelist; + Cursor gdk_cursor_dragdefault, gdk_cursor_dragok; + GdkWindow **drag_startwindows; + guint drag_numwindows; + guint8 drag_really; + GdkPoint drag_dropcoords; +}; +typedef struct _GdkDndGlobals GdkDndGlobals; + +void gdk_window_init (void); +void gdk_visual_init (void); + +void gdk_image_init (void); +void gdk_image_exit (void); + +GdkColormap* gdk_colormap_lookup (Colormap xcolormap); +GdkVisual* gdk_visual_lookup (Visual *xvisual); + +void gdk_window_real_destroy (GdkWindow *window); +void gdk_window_add_colormap_windows (GdkWindow *window); + +void gdk_xid_table_insert (XID *xid, + gpointer data); +void gdk_xid_table_remove (XID xid); +gpointer gdk_xid_table_lookup (XID xid); + + +extern gint gdk_debug_level; +extern gint gdk_show_events; +extern gint gdk_use_xshm; +extern gint gdk_stack_trace; +extern gchar *gdk_display_name; +extern Display *gdk_display; +extern gint gdk_screen; +extern Window gdk_root_window; +extern Window gdk_leader_window; +extern GdkWindowPrivate gdk_root_parent; +extern Atom gdk_wm_delete_window; +extern Atom gdk_wm_take_focus; +extern Atom gdk_wm_protocols; +extern Atom gdk_wm_window_protocols[]; +extern Atom gdk_selection_property; +extern GdkDndGlobals gdk_dnd; +extern GdkWindow *selection_owner[]; +extern gchar *gdk_progname; +extern gchar *gdk_progclass; +extern gint gdk_error_code; +extern gint gdk_error_warnings; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_PRIVATE_H__ */ diff --git a/gdk/gdkproperty.c b/gdk/gdkproperty.c new file mode 100644 index 0000000000..35d8a50cf1 --- /dev/null +++ b/gdk/gdkproperty.c @@ -0,0 +1,194 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + return XInternAtom (gdk_display, atom_name, only_if_exists); +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar *t; + gchar *name; + + /* If this atom doesn't exist, we'll die with an X error unless + we take precautions */ + + gdk_error_warnings = 0; + t = XGetAtomName (gdk_display, atom); + gdk_error_warnings = 1; + + if (gdk_error_code == -1) + { + return NULL; + } + else + { + name = g_strdup (t); + XFree (t); + + return name; + } +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + Atom ret_prop_type; + gint ret_format; + gulong ret_nitems; + gulong ret_bytes_after; + gulong ret_length; + guchar *ret_data; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XGetWindowProperty (xdisplay, xwindow, property, + offset, (length + 3) / 4, pdelete, + type, &ret_prop_type, &ret_format, + &ret_nitems, &ret_bytes_after, + &ret_data); + + if ((ret_prop_type == None) && (ret_format == 0)) + return FALSE; + + if (actual_property_type) + *actual_property_type = ret_prop_type; + if (actual_format_type) + *actual_format_type = ret_format; + + if (ret_prop_type != property) + { + XFree (ret_data); + return FALSE; + } + + /* FIXME: ignoring bytes_after could have very bad effects */ + + if (data) + { + switch (ret_format) + { + case 8: + ret_length = ret_nitems; + break; + case 16: + ret_length = 2 * ret_nitems; + break; + case 32: + ret_length = 4 * ret_nitems; + break; + default: + g_warning ("unknown property return format: %d", ret_format); + XFree (ret_data); + return FALSE; + } + + *data = g_new (guchar, ret_length); + memcpy (*data, ret_data, ret_length); + if (actual_length) + *actual_length = ret_length; + } + + XFree (ret_data); + + return TRUE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XChangeProperty (xdisplay, xwindow, property, type, + format, mode, data, nelements); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XDeleteProperty (xdisplay, xwindow, property); +} diff --git a/gdk/gdkrectangle.c b/gdk/gdkrectangle.c new file mode 100644 index 0000000000..dbb35b664e --- /dev/null +++ b/gdk/gdkrectangle.c @@ -0,0 +1,83 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gdk.h" + + +gint +gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest) +{ + GdkRectangle *temp; + gint src1_x2, src1_y2; + gint src2_x2, src2_y2; + gint return_val; + + g_return_val_if_fail (src1 != NULL, FALSE); + g_return_val_if_fail (src2 != NULL, FALSE); + g_return_val_if_fail (dest != NULL, FALSE); + + return_val = FALSE; + + if (src2->x < src1->x) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->x = src2->x; + + src1_x2 = src1->x + src1->width; + src2_x2 = src2->x + src2->width; + + if (src2->x < src1_x2) + { + if (src1_x2 < src2_x2) + dest->width = src1_x2 - dest->x; + else + dest->width = src2_x2 - dest->x; + + if (src2->y < src1->y) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->y = src2->y; + + src1_y2 = src1->y + src1->height; + src2_y2 = src2->y + src2->height; + + if (src2->y < src1_y2) + { + return_val = TRUE; + + if (src1_y2 < src2_y2) + dest->height = src1_y2 - dest->y; + else + dest->height = src2_y2 - dest->y; + + if (dest->height == 0) + return_val = FALSE; + if (dest->width == 0) + return_val = FALSE; + } + } + + return return_val; +} diff --git a/gdk/gdkselection.c b/gdk/gdkselection.c new file mode 100644 index 0000000000..6bd4251100 --- /dev/null +++ b/gdk/gdkselection.c @@ -0,0 +1,168 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (owner) + { + private = (GdkWindowPrivate*) owner; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = None; + } + + XSetSelectionOwner (xdisplay, selection, xwindow, time); + + return (XGetSelectionOwner (xdisplay, selection) == xwindow); +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + Window xwindow; + + xwindow = XGetSelectionOwner (gdk_display, selection); + if (xwindow == None) + return NULL; + + return gdk_window_lookup (xwindow); +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + XConvertSelection (private->xdisplay, selection, target, + gdk_selection_property, private->xwindow, time); +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkWindowPrivate *private; + gulong nitems; + gulong nbytes; + gulong length; + GdkAtom prop_type; + gint prop_format; + guchar *t; + + g_return_val_if_fail (requestor != NULL, 0); + + /* If retrieved chunks are typically small, (and the ICCM says the + should be) it would be a win to try first with a buffer of + moderate length, to avoid two round trips to the server */ + + private = (GdkWindowPrivate*) requestor; + + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, 0, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (ret_type) + *ret_type = prop_type; + if (ret_format) + *ret_format = prop_format; + + if (prop_type == None) + { + *data = NULL; + return 0; + } + + XFree (t); + + /* Add on an extra byte to handle null termination. X guarantees + that t will be 1 longer than nbytes and null terminated */ + length = nbytes + 1; + + /* We can't delete the selection here, because it might be the INCR + protocol, in which case the client has to make sure they'll be + notified of PropertyChange events _before_ the property is deleted. + Otherwise there's no guarantee we'll win the race ... */ + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, (nbytes + 3) / 4, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (prop_type != None) + { + *data = g_new (guchar, length); + memcpy (*data, t, length); + XFree (t); + return length-1; + } + else + { + *data = NULL; + return 0; + } +} + + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + XSelectionEvent xevent; + + xevent.type = SelectionNotify; + xevent.serial = 0; + xevent.send_event = True; + xevent.display = gdk_display; + xevent.requestor = requestor; + xevent.selection = selection; + xevent.target = target; + xevent.property = property; + xevent.time = time; + + XSendEvent (gdk_display, requestor, False, NoEventMask, (XEvent*) &xevent); +} diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h new file mode 100644 index 0000000000..7fc7434ac1 --- /dev/null +++ b/gdk/gdktypes.h @@ -0,0 +1,967 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GDK_TYPES_H__ +#define __GDK_TYPES_H__ + + +/* GDK uses "glib". (And so does GTK). + */ +#include <glib.h> + + +#define GDK_NONE 0L +#define GDK_CURRENT_TIME 0L +#define GDK_PARENT_RELATIVE 1L + +/* special deviceid for core pointer events */ +#define GDK_CORE_POINTER 0xfedc + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Type definitions for the basic structures. + */ + +typedef gulong GdkAtom; +typedef struct _GdkColor GdkColor; +typedef struct _GdkColormap GdkColormap; +typedef struct _GdkVisual GdkVisual; +typedef struct _GdkWindowAttr GdkWindowAttr; +typedef struct _GdkWindow GdkWindow; +typedef struct _GdkWindow GdkPixmap; +typedef struct _GdkWindow GdkBitmap; +typedef struct _GdkWindow GdkDrawable; +typedef struct _GdkImage GdkImage; +typedef struct _GdkGCValues GdkGCValues; +typedef struct _GdkGC GdkGC; +typedef struct _GdkPoint GdkPoint; +typedef struct _GdkRectangle GdkRectangle; +typedef struct _GdkSegment GdkSegment; +typedef struct _GdkFont GdkFont; +typedef struct _GdkCursor GdkCursor; + +typedef struct _GdkEventAny GdkEventAny; +typedef struct _GdkEventExpose GdkEventExpose; +typedef struct _GdkEventMotion GdkEventMotion; +typedef struct _GdkEventButton GdkEventButton; +typedef struct _GdkEventKey GdkEventKey; +typedef struct _GdkEventFocus GdkEventFocus; +typedef struct _GdkEventCrossing GdkEventCrossing; +typedef struct _GdkEventConfigure GdkEventConfigure; +typedef struct _GdkEventProperty GdkEventProperty; +typedef struct _GdkEventSelection GdkEventSelection; +typedef struct _GdkEventProximity GdkEventProximity; +typedef struct _GdkEventOther GdkEventOther; +typedef struct _GdkEventDragBegin GdkEventDragBegin; +typedef struct _GdkEventDragRequest GdkEventDragRequest; +typedef struct _GdkEventDropEnter GdkEventDropEnter; +typedef struct _GdkEventDropDataAvailable GdkEventDropDataAvailable; +typedef struct _GdkEventDropLeave GdkEventDropLeave; +typedef struct _GdkEventClient GdkEventClient; +typedef union _GdkEvent GdkEvent; +typedef struct _GdkDeviceInfo GdkDeviceInfo; +typedef struct _GdkTimeCoord GdkTimeCoord; +typedef gint (*GdkEventFunc) (GdkEvent *event, + gpointer data); + + +/* Types of windows. + * Root: There is only 1 root window and it is initialized + * at startup. Creating a window of type GDK_WINDOW_ROOT + * is an error. + * Toplevel: Windows which interact with the window manager. + * Child: Windows which are children of some other type of window. + * (Any other type of window). Most windows are child windows. + * Dialog: A special kind of toplevel window which interacts with + * the window manager slightly differently than a regular + * toplevel window. Dialog windows should be used for any + * transient window. + * Pixmap: Pixmaps are really just another kind of window which + * doesn't actually appear on the screen. It can't have + * children, either and is really just a convenience so + * that the drawing functions can work on both windows + * and pixmaps transparently. (ie. You shouldn't pass a + * pixmap to any procedure which accepts a window with the + * exception of the drawing functions). + */ +typedef enum +{ + GDK_WINDOW_ROOT, + GDK_WINDOW_TOPLEVEL, + GDK_WINDOW_CHILD, + GDK_WINDOW_DIALOG, + GDK_WINDOW_TEMP, + GDK_WINDOW_PIXMAP +} GdkWindowType; + +/* Classes of windows. + * InputOutput: Almost every window should be of this type. Such windows + * receive events and are also displayed on screen. + * InputOnly: Used only in special circumstances when events need to be + * stolen from another window or windows. Input only windows + * have no visible output, so they are handy for placing over + * top of a group of windows in order to grab the events (or + * filter the events) from those windows. + */ +typedef enum +{ + GDK_INPUT_OUTPUT, + GDK_INPUT_ONLY +} GdkWindowClass; + +/* Types of images. + * Normal: Normal X image type. These are slow as they involve passing + * the entire image through the X connection each time a draw + * request is required. + * Shared: Shared memory X image type. These are fast as the X server + * and the program actually use the same piece of memory. They + * should be used with care though as there is the possibility + * for both the X server and the program to be reading/writing + * the image simultaneously and producing undesired results. + */ +typedef enum +{ + GDK_IMAGE_NORMAL, + GDK_IMAGE_SHARED, + GDK_IMAGE_FASTEST +} GdkImageType; + +/* Types of visuals. + * StaticGray: + * Grayscale: + * StaticColor: + * PseudoColor: + * TrueColor: + * DirectColor: + */ +typedef enum +{ + GDK_VISUAL_STATIC_GRAY, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR +} GdkVisualType; + +/* Types of font. + * GDK_FONT_FONT: the font is an XFontStruct. + * GDK_FONT_FONTSET: the font is an XFontSet used for I18N. + */ +typedef enum +{ + GDK_FONT_FONT, + GDK_FONT_FONTSET +} GdkFontType; + +/* Window attribute mask values. + * GDK_WA_TITLE: The "title" field is valid. + * GDK_WA_X: The "x" field is valid. + * GDK_WA_Y: The "y" field is valid. + * GDK_WA_CURSOR: The "cursor" field is valid. + * GDK_WA_COLORMAP: The "colormap" field is valid. + * GDK_WA_VISUAL: The "visual" field is valid. + */ +typedef enum +{ + GDK_WA_TITLE = 1 << 1, + GDK_WA_X = 1 << 2, + GDK_WA_Y = 1 << 3, + GDK_WA_CURSOR = 1 << 4, + GDK_WA_COLORMAP = 1 << 5, + GDK_WA_VISUAL = 1 << 6, + GDK_WA_WMCLASS = 1 << 7 +} GdkWindowAttributesType; + +/* Size restriction enumeration. + */ +typedef enum +{ + GDK_HINT_POS = 1 << 0, + GDK_HINT_MIN_SIZE = 1 << 1, + GDK_HINT_MAX_SIZE = 1 << 2 +} GdkWindowHints; + +/* GC function types. + * Copy: Overwrites destination pixels with the source pixels. + * Invert: Inverts the destination pixels. + * Xor: Xor's the destination pixels with the source pixels. + */ +typedef enum +{ + GDK_COPY, + GDK_INVERT, + GDK_XOR +} GdkFunction; + +/* GC fill types. + * Solid: + * Tiled: + * Stippled: + * OpaqueStippled: + */ +typedef enum +{ + GDK_SOLID, + GDK_TILED, + GDK_STIPPLED, + GDK_OPAQUE_STIPPLED +} GdkFill; + +/* GC line styles + * Solid: + * OnOffDash: + * DoubleDash: + */ +typedef enum +{ + GDK_LINE_SOLID, + GDK_LINE_ON_OFF_DASH, + GDK_LINE_DOUBLE_DASH +} GdkLineStyle; + +/* GC cap styles + * CapNotLast: + * CapButt: + * CapRound: + * CapProjecting: + */ +typedef enum +{ + GDK_CAP_NOT_LAST, + GDK_CAP_BUTT, + GDK_CAP_ROUND, + GDK_CAP_PROJECTING +} GdkCapStyle; + +/* GC join styles + * JoinMiter: + * JoinRound: + * JoinBevel: + */ +typedef enum +{ + GDK_JOIN_MITER, + GDK_JOIN_ROUND, + GDK_JOIN_BEVEL +} GdkJoinStyle; + +/* Cursor types. + */ +typedef enum +{ +#include <gdk/gdkcursors.h> + GDK_LAST_CURSOR +} GdkCursorType; + +/* Event types. + * Nothing: No event occurred. + * Delete: A window delete event was sent by the window manager. + * The specified window should be deleted. + * Destroy: A window has been destroyed. + * Expose: Part of a window has been uncovered. + * MotionNotify: The mouse has moved. + * ButtonPress: A mouse button was pressed. + * ButtonRelease: A mouse button was release. + * KeyPress: A key was pressed. + * KeyRelease: A key was released. + * EnterNotify: A window was entered. + * LeaveNotify: A window was exited. + * FocusChange: The focus window has changed. (The focus window gets + * keyboard events). + * Resize: A window has been resized. + * Map: A window has been mapped. (It is now visible on the screen). + * Unmap: A window has been unmapped. (It is no longer visible on + * the screen). + */ +typedef enum +{ + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_3BUTTON_PRESS = 6, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_BEGIN = 22, + GDK_DRAG_REQUEST = 23, + GDK_DROP_ENTER = 24, + GDK_DROP_LEAVE = 25, + GDK_DROP_DATA_AVAIL = 26, + GDK_CLIENT_EVENT = 27, + GDK_OTHER_EVENT = 9999 +} GdkEventType; + +/* Event masks. (Used to select what types of events a window + * will receive). + */ +typedef enum +{ + GDK_EXPOSURE_MASK = 1 << 1, + GDK_POINTER_MOTION_MASK = 1 << 2, + GDK_POINTER_MOTION_HINT_MASK = 1 << 3, + GDK_BUTTON_MOTION_MASK = 1 << 4, + GDK_BUTTON1_MOTION_MASK = 1 << 5, + GDK_BUTTON2_MOTION_MASK = 1 << 6, + GDK_BUTTON3_MOTION_MASK = 1 << 7, + GDK_BUTTON_PRESS_MASK = 1 << 8, + GDK_BUTTON_RELEASE_MASK = 1 << 9, + GDK_KEY_PRESS_MASK = 1 << 10, + GDK_KEY_RELEASE_MASK = 1 << 11, + GDK_ENTER_NOTIFY_MASK = 1 << 12, + GDK_LEAVE_NOTIFY_MASK = 1 << 13, + GDK_FOCUS_CHANGE_MASK = 1 << 14, + GDK_STRUCTURE_MASK = 1 << 15, + GDK_PROPERTY_CHANGE_MASK = 1 << 16, + GDK_PROXIMITY_IN_MASK = 1 << 17, + GDK_PROXIMITY_OUT_MASK = 1 << 18, + GDK_ALL_EVENTS_MASK = 0x07FFFF +} GdkEventMask; + +/* Types of enter/leave notifications. + * Ancestor: + * Virtual: + * Inferior: + * Nonlinear: + * NonlinearVirtual: + * Unknown: An unknown type of enter/leave event occurred. + */ +typedef enum +{ + GDK_NOTIFY_ANCESTOR = 0, + GDK_NOTIFY_VIRTUAL = 1, + GDK_NOTIFY_INFERIOR = 2, + GDK_NOTIFY_NONLINEAR = 3, + GDK_NOTIFY_NONLINEAR_VIRTUAL = 4, + GDK_NOTIFY_UNKNOWN = 5 +} GdkNotifyType; + +/* Types of modifiers. + */ +typedef enum +{ + GDK_SHIFT_MASK = 1 << 0, + GDK_LOCK_MASK = 1 << 1, + GDK_CONTROL_MASK = 1 << 2, + GDK_MOD1_MASK = 1 << 3, + GDK_MOD2_MASK = 1 << 4, + GDK_MOD3_MASK = 1 << 5, + GDK_MOD4_MASK = 1 << 6, + GDK_MOD5_MASK = 1 << 7, + GDK_BUTTON1_MASK = 1 << 8, + GDK_BUTTON2_MASK = 1 << 9, + GDK_BUTTON3_MASK = 1 << 10, + GDK_BUTTON4_MASK = 1 << 11, + GDK_BUTTON5_MASK = 1 << 12 +} GdkModifierType; + +typedef enum +{ + GDK_CLIP_BY_CHILDREN = 0, + GDK_INCLUDE_INFERIORS = 1 +} GdkSubwindowMode; + +typedef enum +{ + GDK_INPUT_READ = 1 << 0, + GDK_INPUT_WRITE = 1 << 1, + GDK_INPUT_EXCEPTION = 1 << 2 +} GdkInputCondition; + +typedef enum +{ + GDK_OK = 0, + GDK_ERROR = -1, + GDK_ERROR_PARAM = -2, + GDK_ERROR_FILE = -3, + GDK_ERROR_MEM = -4 +} GdkStatus; + +typedef enum +{ + GDK_LSB_FIRST, + GDK_MSB_FIRST +} GdkByteOrder; + +typedef enum +{ + GDK_GC_FOREGROUND = 1 << 0, + GDK_GC_BACKGROUND = 1 << 1, + GDK_GC_FONT = 1 << 2, + GDK_GC_FUNCTION = 1 << 3, + GDK_GC_FILL = 1 << 4, + GDK_GC_TILE = 1 << 5, + GDK_GC_STIPPLE = 1 << 6, + GDK_GC_CLIP_MASK = 1 << 7, + GDK_GC_SUBWINDOW = 1 << 8, + GDK_GC_TS_X_ORIGIN = 1 << 9, + GDK_GC_TS_Y_ORIGIN = 1 << 10, + GDK_GC_CLIP_X_ORIGIN = 1 << 11, + GDK_GC_CLIP_Y_ORIGIN = 1 << 12, + GDK_GC_EXPOSURES = 1 << 13, + GDK_GC_LINE_WIDTH = 1 << 14, + GDK_GC_LINE_STYLE = 1 << 15, + GDK_GC_CAP_STYLE = 1 << 16, + GDK_GC_JOIN_STYLE = 1 << 17 +} GdkGCValuesMask; + +typedef enum +{ + GDK_SELECTION_PRIMARY = 1, + GDK_SELECTION_SECONDARY = 2 +} GdkSelection; + +typedef enum +{ + GDK_PROPERTY_NEW_VALUE, + GDK_PROPERTY_DELETE +} GdkPropertyState; + +typedef enum +{ + GDK_PROP_MODE_REPLACE, + GDK_PROP_MODE_PREPEND, + GDK_PROP_MODE_APPEND +} GdkPropMode; + +/* These definitions are for version 1 of the OffiX D&D protocol, + taken from <OffiX/DragAndDropTypes.h> */ +typedef enum +{ + GDK_DNDTYPE_NOTDND = -1, + GDK_DNDTYPE_UNKNOWN = 0, + GDK_DNDTYPE_RAWDATA = 1, + GDK_DNDTYPE_FILE = 2, + GDK_DNDTYPE_FILES = 3, + GDK_DNDTYPE_TEXT = 4, + GDK_DNDTYPE_DIR = 5, + GDK_DNDTYPE_LINK = 6, + GDK_DNDTYPE_EXE = 7, + GDK_DNDTYPE_URL = 8, + GDK_DNDTYPE_MIME = 9, + GDK_DNDTYPE_END = 10 +} GdkDndType; + +/* Enums for XInput support */ + +typedef enum +{ + GDK_SOURCE_MOUSE, + GDK_SOURCE_PEN, + GDK_SOURCE_ERASER, + GDK_SOURCE_CURSOR +} GdkInputSource; + +typedef enum +{ + GDK_MODE_DISABLED, + GDK_MODE_SCREEN, + GDK_MODE_WINDOW +} GdkInputMode; + +typedef enum +{ + GDK_AXIS_IGNORE, + GDK_AXIS_X, + GDK_AXIS_Y, + GDK_AXIS_PRESSURE, + GDK_AXIS_XTILT, + GDK_AXIS_YTILT, + GDK_AXIS_LAST +} GdkAxisUse; + +/* The next two types define enums for predefined atoms relating + to selections. In general, one will need to use gdk_intern_atom */ + +typedef enum +{ + GDK_TARGET_BITMAP = 5, + GDK_TARGET_COLORMAP = 7, + GDK_TARGET_DRAWABLE = 17, + GDK_TARGET_PIXMAP = 20, + GDK_TARGET_STRING = 31 +} GdkTarget; + +typedef enum +{ + GDK_SELECTION_TYPE_ATOM = 4, + GDK_SELECTION_TYPE_BITMAP = 5, + GDK_SELECTION_TYPE_COLORMAP = 7, + GDK_SELECTION_TYPE_DRAWABLE = 17, + GDK_SELECTION_TYPE_INTEGER = 19, + GDK_SELECTION_TYPE_PIXMAP = 20, + GDK_SELECTION_TYPE_WINDOW = 33, + GDK_SELECTION_TYPE_STRING = 31 +} GdkSelectionType; + +typedef enum +{ + GDK_EXTENSION_EVENTS_NONE, + GDK_EXTENSION_EVENTS_ALL, + GDK_EXTENSION_EVENTS_CURSOR +} GdkExtensionMode; + +typedef void (*GdkInputFunction) (gpointer data, + gint source, + GdkInputCondition condition); + +/* The color type. + * A color consists of red, green and blue values in the + * range 0-65535 and a pixel value. The pixel value is highly + * dependent on the depth and colormap which this color will + * be used to draw into. Therefore, sharing colors between + * colormaps is a bad idea. + */ +struct _GdkColor +{ + gulong pixel; + gushort red; + gushort green; + gushort blue; +}; + +/* The colormap type. + * Colormaps consist of 256 colors. + */ +struct _GdkColormap +{ + GdkColor colors[256]; +}; + +/* The visual type. + * "type" is the type of visual this is (PseudoColor, TrueColor, etc). + * "depth" is the bit depth of this visual. + * "colormap_size" is the size of a colormap for this visual. + * "bits_per_rgb" is the number of significant bits per red, green and blue. + * The red, green and blue masks, shifts and precisions refer + * to value needed to calculate pixel values in TrueColor and DirectColor + * visuals. The "mask" is the significant bits within the pixel. The + * "shift" is the number of bits left we must shift a primary for it + * to be in position (according to the "mask"). "prec" refers to how + * much precision the pixel value contains for a particular primary. + */ +struct _GdkVisual +{ + GdkVisualType type; + gint depth; + GdkByteOrder byte_order; + gint colormap_size; + gint bits_per_rgb; + + guint32 red_mask; + gint red_shift; + gint red_prec; + + guint32 green_mask; + gint green_shift; + gint green_prec; + + guint32 blue_mask; + gint blue_shift; + gint blue_prec; +}; + +struct _GdkWindowAttr +{ + gchar *title; + gint event_mask; + gint16 x, y; + gint16 width; + gint16 height; + GdkWindowClass wclass; + GdkVisual *visual; + GdkColormap *colormap; + GdkWindowType window_type; + GdkCursor *cursor; + gchar *wmclass_name; + gchar *wmclass_class; +}; + +struct _GdkWindow +{ + gpointer user_data; +}; + +struct _GdkImage +{ + GdkImageType type; + GdkVisual *visual; /* visual used to create the image */ + GdkByteOrder byte_order; + guint16 width; + guint16 height; + guint16 depth; + guint16 bpp; /* bytes per pixel */ + guint16 bpl; /* bytes per line */ + gpointer mem; +}; + +struct _GdkGCValues +{ + GdkColor foreground; + GdkColor background; + GdkFont *font; + GdkFunction function; + GdkFill fill; + GdkPixmap *tile; + GdkPixmap *stipple; + GdkPixmap *clip_mask; + GdkSubwindowMode subwindow_mode; + gint ts_x_origin; + gint ts_y_origin; + gint clip_x_origin; + gint clip_y_origin; + gint graphics_exposures; + gint line_width; + GdkLineStyle line_style; + GdkCapStyle cap_style; + GdkJoinStyle join_style; +}; + +struct _GdkGC +{ + gint dummy_var; +}; + +struct _GdkPoint +{ + gint16 x; + gint16 y; +}; + +struct _GdkRectangle +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +struct _GdkSegment +{ + gint16 x1; + gint16 y1; + gint16 x2; + gint16 y2; +}; + +struct _GdkFont +{ + GdkFontType type; + gint ascent; + gint descent; +}; + +struct _GdkCursor +{ + GdkCursorType type; +}; + +/* Types for XInput support */ + +struct _GdkDeviceInfo +{ + guint32 deviceid; + gchar *name; + GdkInputSource source; + GdkInputMode mode; + gint has_cursor; /* TRUE if the X pointer follows device motion */ + gint num_axes; + GdkAxisUse *axes; /* Specifies use for each axis */ +}; + +struct _GdkTimeCoord +{ + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; +}; + +struct _GdkEventAny +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; +}; + +struct _GdkEventExpose +{ + GdkEventType type; + GdkWindow *window; + GdkRectangle area; + gint count; /* If non-zero, how many more events follow. */ +}; + +struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + gint16 is_hint; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + guint button; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + guint state; + guint keyval; +}; + +struct _GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + GdkWindow *subwindow; + GdkNotifyType detail; +}; + +struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint16 in; +}; + +struct _GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint16 x, y; + gint16 width; + gint16 height; +}; + +struct _GdkEventProperty +{ + GdkEventType type; + GdkWindow *window; + GdkAtom atom; + guint32 time; + guint state; +}; + +struct _GdkEventSelection +{ + GdkEventType type; + GdkWindow *window; + GdkAtom selection; + GdkAtom target; + GdkAtom property; + guint32 requestor; + guint32 time; +}; + +/* This event type will be used pretty rarely. It only is important + for XInput aware programs that are drawing their own cursor */ + +struct _GdkEventProximity +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventDragRequest +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint willaccept:1; + guint delete_data:1; /* Do *not* delete if link is sent, only + if data is sent */ + guint senddata:1; + guint reserved:22; + } flags; + glong allflags; + } u; + guint8 isdrop; /* This gdk event can be generated by a couple of + X events - this lets the app know whether the + drop really occurred or we just set the data */ + + GdkPoint drop_coords; + gchar *data_type; +}; + +struct _GdkEventDragBegin +{ + GdkEventType type; + GdkWindow *window; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropEnter +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint extended_typelist:1; + guint reserved:26; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropLeave +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropDataAvailable +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint isdrop:1; + guint reserved:25; + } flags; + glong allflags; + } u; + gchar *data_type; /* MIME type */ + gulong data_numbytes; + gpointer data; +}; + +struct _GdkEventClient +{ + GdkEventType type; + GdkWindow *window; + GdkAtom message_type; + gushort data_format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +}; + +#ifndef _XLIB_H_ +#define XEvent void +#endif + +struct _GdkEventOther +{ + GdkEventType type; + GdkWindow *window; + XEvent *xevent; +}; + +union _GdkEvent +{ + GdkEventType type; + GdkEventAny any; + GdkEventExpose expose; + GdkEventMotion motion; + GdkEventButton button; + GdkEventKey key; + GdkEventCrossing crossing; + GdkEventFocus focus_change; + GdkEventConfigure configure; + GdkEventProperty property; + GdkEventSelection selection; + GdkEventProximity proximity; + GdkEventDragBegin dragbegin; + GdkEventDragRequest dragrequest; + GdkEventDropEnter dropenter; + GdkEventDropLeave dropleave; + GdkEventDropDataAvailable dropdataavailable; + GdkEventClient client; + GdkEventOther other; +}; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_TYPES_H__ */ diff --git a/gdk/gdkvisual.c b/gdk/gdkvisual.c new file mode 100644 index 0000000000..22acee6f13 --- /dev/null +++ b/gdk/gdkvisual.c @@ -0,0 +1,431 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xutil.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[4]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +static char* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init () +{ + static gint possible_depths[5] = { 32, 24, 16, 15, 8 }; + static GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static gint npossible_depths = 5; + static gint npossible_types = 6; + + XVisualInfo *visual_list; + XVisualInfo visual_template; + GdkVisualPrivate temp_visual; + Visual *default_xvisual; + int nxvisuals; + int i, j; + + visual_template.screen = gdk_screen; + visual_list = XGetVisualInfo (gdk_display, VisualScreenMask, &visual_template, &nxvisuals); + visuals = g_new (GdkVisualPrivate, nxvisuals); + + default_xvisual = DefaultVisual (gdk_display, gdk_screen); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (visual_list[i].depth >= 8) + { +#ifdef __cplusplus + switch (visual_list[i].c_class) +#else /* __cplusplus */ + switch (visual_list[i].class) +#endif /* __cplusplus */ + { + case StaticGray: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + break; + case GrayScale: + visuals[nvisuals].visual.type = GDK_VISUAL_GRAYSCALE; + break; + case StaticColor: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + break; + case PseudoColor: + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + break; + case TrueColor: + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + break; + case DirectColor: + visuals[nvisuals].visual.type = GDK_VISUAL_DIRECT_COLOR; + break; + } + + visuals[nvisuals].visual.depth = visual_list[i].depth; + visuals[nvisuals].visual.byte_order = + (ImageByteOrder(gdk_display) == LSBFirst) ? + GDK_LSB_FIRST : GDK_MSB_FIRST; + visuals[nvisuals].visual.red_mask = visual_list[i].red_mask; + visuals[nvisuals].visual.green_mask = visual_list[i].green_mask; + visuals[nvisuals].visual.blue_mask = visual_list[i].blue_mask; + visuals[nvisuals].visual.colormap_size = visual_list[i].colormap_size; + visuals[nvisuals].visual.bits_per_rgb = visual_list[i].bits_per_rgb; + visuals[nvisuals].xvisual = visual_list[i].visual; + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + + nvisuals += 1; + } + } + + XFree (visual_list); + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + if (gdk_debug_level >= 1) + for (i = 0; i < nvisuals; i++) + g_print ("visual: %s: %d\n", + visual_names[visuals[i].visual.type], + visuals[i].visual.depth); + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable visual type"); +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth () +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type () +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system () +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best () +{ + return ((GdkVisual*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +void +gdk_query_visuals (GdkVisual **visual_return, + gint *count) +{ + *count = nvisuals; + *visual_return = (GdkVisual*) visuals; +} + + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c new file mode 100644 index 0000000000..aef1367d93 --- /dev/null +++ b/gdk/gdkwindow.c @@ -0,0 +1,1358 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/shape.h> +#include <netinet/in.h> +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include <stdlib.h> + +int nevent_masks = 16; +int event_mask_table[18] = +{ + ExposureMask, + PointerMotionMask, + PointerMotionHintMask, + ButtonMotionMask, + Button1MotionMask, + Button2MotionMask, + Button3MotionMask, + ButtonPressMask | OwnerGrabButtonMask, + ButtonReleaseMask | OwnerGrabButtonMask, + KeyPressMask, + KeyReleaseMask, + EnterWindowMask, + LeaveWindowMask, + FocusChangeMask, + StructureNotifyMask, + PropertyChangeMask, + 0, /* PROXIMITY_IN */ + 0 /* PROXIMTY_OUT */ +}; + + +void +gdk_window_init () +{ + XWindowAttributes xattributes; + unsigned int width; + unsigned int height; + unsigned int border_width; + unsigned int depth; + int x, y; + + XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window, + &x, &y, &width, &height, &border_width, &depth); + XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes); + + gdk_root_parent.xdisplay = gdk_display; + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + GdkColormap *colormap; + Display *parent_display; + Window xparent; + Visual *xvisual; + XSetWindowAttributes xattributes; + long xattributes_mask; + XSizeHints size_hints; + XWMHints wm_hints; + XTextProperty text_property; + XClassHint *class_hint; + int x, y, depth; + unsigned int class; + char *title; + int i; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + xparent = parent_private->xwindow; + parent_display = parent_private->xdisplay; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + private->xdisplay = parent_display; + private->destroyed = FALSE; + private->resize_count = 0; + private->ref_count = 1; + xattributes_mask = 0; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->window_type = attributes->window_type; + private->extension_events = FALSE; + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + xattributes.event_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (attributes->event_mask & (1 << (i + 1))) + xattributes.event_mask |= event_mask_table[i]; + } + + if (xattributes.event_mask) + xattributes_mask |= CWEventMask; + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + class = InputOutput; + depth = visual->depth; + + if (attributes_mask & GDK_WA_COLORMAP) + colormap = attributes->colormap; + else + colormap = gdk_colormap_get_system (); + + xattributes.background_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes_mask |= CWBorderPixel | CWBackPixel; + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_CHILD: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + break; + + case GDK_WINDOW_DIALOG: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_TEMP: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + + xattributes.save_under = True; + xattributes.override_redirect = True; + xattributes.cursor = None; + xattributes_mask |= CWSaveUnder | CWOverrideRedirect; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + } + else + { + depth = 1; + class = InputOnly; + colormap = NULL; + } + + private->xwindow = XCreateWindow (private->xdisplay, xparent, + x, y, private->width, private->height, + 0, depth, class, xvisual, + xattributes_mask, &xattributes); + gdk_xid_table_insert (&private->xwindow, window); + + switch (private->window_type) + { + case GDK_WINDOW_DIALOG: + XSetTransientForHint (private->xdisplay, private->xwindow, xparent); + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_TEMP: + XSetWMProtocols (private->xdisplay, private->xwindow, gdk_wm_window_protocols, 2); + break; + case GDK_WINDOW_CHILD: + if ((attributes->wclass == GDK_INPUT_OUTPUT) && + (colormap != gdk_colormap_get_system ()) && + (colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window)))) + { + g_print ("adding colormap window\n"); + gdk_window_add_colormap_windows (window); + } + break; + default: + break; + } + + size_hints.flags = PSize | PBaseSize; + size_hints.width = private->width; + size_hints.height = private->height; + size_hints.base_width = private->width; + size_hints.base_height = private->height; + + wm_hints.flags = InputHint | StateHint | WindowGroupHint; + wm_hints.window_group = gdk_leader_window; + wm_hints.input = True; + wm_hints.initial_state = NormalState; + + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); + XSetWMHints (private->xdisplay, private->xwindow, &wm_hints); + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = gdk_progname; + + if (XStringListToTextProperty (&title, 1, &text_property)) + { + XSetWMName (private->xdisplay, private->xwindow, &text_property); + XSetWMIconName (private->xdisplay, private->xwindow, &text_property); + XFree (text_property.value); + } + + if (attributes_mask & GDK_WA_WMCLASS) + { + class_hint = XAllocClassHint (); + class_hint->res_name = attributes->wmclass_name; + class_hint->res_class = attributes->wmclass_class; + XSetClassHint (private->xdisplay, private->xwindow, class_hint); + XFree (class_hint); + } + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + XWindowAttributes attrs; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + XGetWindowAttributes (gdk_display, anid, &attrs); + + private->parent = NULL; + private->xwindow = anid; + private->xdisplay = gdk_display; + private->x = attrs.x; + private->y = attrs.y; + private->width = attrs.width; + private->height = attrs.height; + private->resize_count = 0; + private->ref_count = 1; + if (anid == attrs.root) + private->window_type = GDK_WINDOW_ROOT; + else + private->window_type = GDK_WINDOW_TOPLEVEL; + /* the above is probably wrong, but it may not be worth the extra + X call to get it right */ + + private->destroyed = FALSE; + private->extension_events = 0; + + window->user_data = NULL; + + gdk_xid_table_insert (&private->xwindow, window); + + return window; +} + +void +gdk_window_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if(private->dnd_drag_data_numtypesavail > 0) + { + free(private->dnd_drag_data_typesavail); + private->dnd_drag_data_typesavail = NULL; + } + if(private->dnd_drop_data_numtypesavail > 0) + { + free(private->dnd_drop_data_typesavail); + private->dnd_drop_data_typesavail = NULL; + } + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (private->ref_count >= 1) + private->ref_count -= 1; + + if (!private->destroyed || (private->destroyed == 2)) + { + children = gdk_window_get_children (window); + tmp = children; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private && !temp_private->destroyed) + /* Removes some nice coredumps... /David */ + { + temp_private->destroyed = 2; + temp_private->ref_count += 1; + gdk_window_destroy (temp_window); + } + } + + g_list_free (children); + + if (!private->destroyed) + XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_PIXMAP: + g_warning ("called gdk_window_destroy on a pixmap (use gdk_pixmap_destroy)"); + gdk_pixmap_destroy (window); + break; + } +} + +void +gdk_window_real_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->ref_count == 0) + { + gdk_xid_table_remove (private->xwindow); + g_free (window); + } +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count += 1; + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_window_real_destroy (window); +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + XRaiseWindow (private->xdisplay, private->xwindow); + XMapWindow (private->xdisplay, private->xwindow); + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + XUnmapWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XMoveWindow (private->xdisplay, private->xwindow, x, y); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + XResizeWindow (private->xdisplay, private->xwindow, width, height); + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + XMoveResizeWindow (private->xdisplay, private->xwindow, x, y, width, height); + + if (!private->destroyed && + (private->window_type == GDK_WINDOW_CHILD)) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) new_parent; + + XReparentWindow (window_private->xdisplay, + window_private->xwindow, + parent_private->xwindow, + x, y); +} + +void +gdk_window_clear (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + XClearWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, False); +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, True); +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + XCopyArea (dest_private->xdisplay, src_private->xwindow, dest_private->xwindow, + gc_private->xgc, + source_x, source_y, + width, height, + x, y); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XRaiseWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XLowerWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + size_hints.flags = 0; + + if (flags & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + size_hints.x = x; + size_hints.y = y; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = min_width; + size_hints.min_height = min_height; + } + + if (flags & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = max_width; + size_hints.max_height = max_height; + } + + if (flags) + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XStoreName (private->xdisplay, private->xwindow, title); + XSetIconName (private->xdisplay, private->xwindow, title); +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XSetWindowBackground (private->xdisplay, private->xwindow, color->pixel); +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; + GdkPixmapPrivate *pixmap_private; + Pixmap xpixmap; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkPixmapPrivate*) pixmap; + + if (pixmap) + xpixmap = pixmap_private->xwindow; + else + xpixmap = None; + + if (parent_relative) + xpixmap = ParentRelative; + + XSetWindowBackgroundPixmap (window_private->xdisplay, window_private->xwindow, xpixmap); +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + Cursor xcursor; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + XDefineCursor (window_private->xdisplay, window_private->xwindow, xcursor); +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + XSetWindowColormap (window_private->xdisplay, + window_private->xwindow, + colormap_private->xcolormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowPrivate *window_private; + Window root; + gint tx; + gint ty; + guint twidth; + guint theight; + guint tborder_width; + guint tdepth; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + XGetGeometry (window_private->xdisplay, window_private->xwindow, + &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth); + + if (x) + *x = tx; + if (y) + *y = ty; + if (width) + *width = twidth; + if (height) + *height = theight; + if (depth) + *depth = tdepth; +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private) + { + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_visual_lookup (window_attributes.visual); + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_colormap_lookup (window_attributes.colormap); +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + Window child; + gint tx, ty; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + return_val = XTranslateCoordinates (private->xdisplay, + private->xwindow, + gdk_root_window, + 0, 0, &tx, &ty, + &child); + + if (x) + *x = tx; + if (y) + *y = ty; + + return return_val; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + Window root; + Window child; + int rootx, rooty; + int winx, winy; + unsigned int xmask; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + if (XQueryPointer (private->xdisplay, private->xwindow, &root, &child, + &rootx, &rooty, &winx, &winy, &xmask)) + { + if (x) *x = winx; + if (y) *y = winy; + if (mask) *mask = xmask; + + if (child) + return_val = gdk_window_lookup (child); + } + + return return_val; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindow *child; + GList *children; + Window root; + Window parent; + Window *xchildren; + unsigned int nchildren; + unsigned int i; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + XQueryTree (private->xdisplay, private->xwindow, + &root, &parent, &xchildren, &nchildren); + + children = NULL; + + if (nchildren > 0) + { + for (i = 0; i < nchildren; i++) + { + child = gdk_window_lookup (xchildren[i]); + if (child) + children = g_list_prepend (children, child); + } + + XFree (xchildren); + } + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + XWindowAttributes attrs; + GdkEventMask event_mask; + int i; + + XGetWindowAttributes (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + &attrs); + + event_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (attrs.your_event_mask & event_mask_table[i]) + event_mask |= 1 << (i + 1); + } + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + long xevent_mask; + int i; + + xevent_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + XSelectInput (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + xevent_mask); +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + GdkWindow *toplevel; + GdkWindowPrivate *toplevel_private; + GdkWindowPrivate *window_private; + Window *old_windows; + Window *new_windows; + int i, count; + + g_return_if_fail (window != NULL); + + toplevel = gdk_window_get_toplevel (window); + toplevel_private = (GdkWindowPrivate*) toplevel; + window_private = (GdkWindowPrivate*) window; + + if (!XGetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + &old_windows, &count)) + { + old_windows = NULL; + count = 0; + } + + for (i = 0; i < count; i++) + if (old_windows[i] == window_private->xwindow) + return; + + new_windows = g_new (Window, count + 1); + + for (i = 0; i < count; i++) + new_windows[i] = old_windows[i]; + new_windows[count] = window_private->xwindow; + + XSetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + new_windows, count + 1); + + g_free (new_windows); + if (old_windows) + XFree (old_windows); +} + +/* + * This needs the X11 shape extension. + * If not available, simply remove the call to + * XShapeCombineMask. Shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *pixmap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (mask != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkWindowPrivate*) mask; + + XShapeCombineMask (window_private->xdisplay, + window_private->xwindow, + ShapeBounding, + x, y, /* offset */ + (Pixmap)pixmap_private->xwindow, + ShapeSet); +} + +void +gdk_dnd_drag_addwindow (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + if (window_private->dnd_drag_enabled == 1 && gdk_dnd.drag_really == 0) + { + gdk_dnd.drag_numwindows++; + gdk_dnd.drag_startwindows = g_realloc (gdk_dnd.drag_startwindows, + gdk_dnd.drag_numwindows + * sizeof(GdkWindow *)); + gdk_dnd.drag_startwindows[gdk_dnd.drag_numwindows - 1] = window; + window_private->dnd_drag_accepted = 0; + } + else + g_warning ("dnd_really is 1 or drag is not enabled! can't addwindow\n"); +} + +void +gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes) +{ + GdkWindowPrivate *window_private; + int i, wasset = 0; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drag_enabled = drag_enable ? 1 : 0; + + if (drag_enable) + { + g_return_if_fail(typelist != NULL); + + if (window_private->dnd_drag_data_numtypesavail > 3) + wasset = 1; + window_private->dnd_drag_data_numtypesavail = numtypes; + + window_private->dnd_drag_data_typesavail = + g_realloc (window_private->dnd_drag_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + { + /* Allow blanket use of ALL to get anything... */ + if (strcmp (typelist[i], "ALL")) + window_private->dnd_drag_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + else + window_private->dnd_drag_data_typesavail[i] = None; + } + + /* + * set our extended type list if we need to + */ + if (numtypes > 3) + gdk_property_change(window, gdk_dnd.gdk_XdeTypelist, + XA_PRIMARY, 32, GDK_PROP_MODE_REPLACE, + (guchar *)(window_private->dnd_drag_data_typesavail + + (sizeof(GdkAtom) * 3)), + (numtypes - 3) * sizeof(GdkAtom)); + else if (wasset) + gdk_property_delete (window, gdk_dnd.gdk_XdeTypelist); + } + else + { + free (window_private->dnd_drag_data_typesavail); + window_private->dnd_drag_data_typesavail = NULL; + window_private->dnd_drag_data_numtypesavail = 0; + } +} + +void +gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op) +{ + GdkWindowPrivate *window_private; + int i; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drop_enabled = drop_enable ? 1 : 0; + if (drop_enable) + { + g_return_if_fail(typelist != NULL); + + window_private->dnd_drop_data_numtypesavail = numtypes; + + window_private->dnd_drop_data_typesavail = + g_realloc (window_private->dnd_drop_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + window_private->dnd_drop_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + + window_private->dnd_drop_destructive_op = destructive_op; + } +} + +/* + * This is used to reply to a GDK_DRAG_REQUEST event + * (which may be generated by XdeRequest or a confirmed drop... + */ +void +gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + GdkWindowPrivate *window_private; + XEvent sev; + GdkEventDropDataAvailable tmp_ev; + gchar *tmp; + + g_return_if_fail (window != NULL); + g_return_if_fail (event != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (data_numbytes > 0); + g_return_if_fail (event->type == GDK_DRAG_REQUEST); + + g_free (event->dragrequest.data_type); + event->dragrequest.data_type = NULL; + + window_private = (GdkWindowPrivate *) window; + g_return_if_fail (window_private->dnd_drag_accepted != 0); + + /* We set the property on our window... */ + gdk_property_change (window, window_private->dnd_drag_data_type, + XA_PRIMARY, 8, GDK_PROP_MODE_REPLACE, data, + data_numbytes); + tmp = gdk_atom_name(window_private->dnd_drag_data_type); + g_print("DnD type %s on window %ld\n", tmp, window_private->xwindow); + g_free(tmp); + + /* + * Then we send the event to tell the receiving window that the + * drop has happened + */ + tmp_ev.u.allflags = 0; + tmp_ev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tmp_ev.u.flags.isdrop = event->dragrequest.isdrop; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.window = event->dragrequest.requestor; + sev.xclient.message_type = gdk_dnd.gdk_XdeDataAvailable; + sev.xclient.data.l[0] = window_private->xwindow; + sev.xclient.data.l[1] = tmp_ev.u.allflags; + sev.xclient.data.l[2] = window_private->dnd_drag_data_type; + + if (event->dragrequest.isdrop) + sev.xclient.data.l[3] = event->dragrequest.drop_coords.x + + (event->dragrequest.drop_coords.y << 16); + else + sev.xclient.data.l[3] = 0; + + sev.xclient.data.l[4] = 0; + + XSendEvent (gdk_display, event->dragrequest.requestor, False, + NoEventMask, &sev); +} diff --git a/gdk/gdkx.h b/gdk/gdkx.h new file mode 100644 index 0000000000..cb8e33b44f --- /dev/null +++ b/gdk/gdkx.h @@ -0,0 +1,48 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GDK_X_H__ +#define __GDK_X_H__ + +#include <gdk/gdkprivate.h> + + +#define GDK_ROOT_WINDOW() gdk_root_window +#define GDK_ROOT_PARENT() &gdk_root_parent +#define GDK_DISPLAY() gdk_display +#define GDK_WINDOW_XDISPLAY(win) (((GdkWindowPrivate*) win)->xdisplay) +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) (((GdkImagePrivate*) image)->xdisplay) +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) (((GdkGCPrivate*) gc)->xdisplay) +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) (((GdkColormapPrivate*) cmap)->xdisplay) +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) (((GdkFontPrivate*) font)->xdisplay) +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Utility function in gdk.c - not sure where it belongs, but it's + needed in more than one place, so make it public */ +Window gdk_get_client_window (Display *dpy, + Window win); + + +#endif /* __GDK_X_H__ */ diff --git a/gdk/gdkxid.c b/gdk/gdkxid.c new file mode 100644 index 0000000000..7ee6075c53 --- /dev/null +++ b/gdk/gdkxid.c @@ -0,0 +1,74 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gdkprivate.h" + + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data; + + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/gxid.c b/gdk/gxid.c new file mode 100644 index 0000000000..219c08bfe0 --- /dev/null +++ b/gdk/gxid.c @@ -0,0 +1,844 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <X11/Xlib.h> +#include <X11/extensions/XInput.h> + +#include "gxid_proto.h" + +/* #define DEBUG_CLIENTS */ +/* #define DEBUG_EVENTS */ + +char *program_name; +Display *dpy; +Window root_window; /* default root window of dpy */ +int port = 0; /* port to listen on */ +int socket_fd = 0; /* file descriptor of socket */ +typedef struct GxidWindow_ GxidWindow; + +typedef struct GxidDevice_ GxidDevice; +struct GxidDevice_ { + XID id; + int exclusive; + int ispointer; + + XDevice *xdevice; + int motionnotify_type; + int changenotify_type; +}; + +struct GxidWindow_ { + Window xwindow; + /* Immediate child of root that is ancestor of window */ + Window root_child; + int num_devices; + GxidDevice **devices; +}; + +GxidDevice **devices = NULL; +int num_devices = 0; +GxidWindow **windows = NULL; +int num_windows = 0; + +void +handler(int signal) +{ + fprintf(stderr,"%s: dying on signal %d\n",program_name,signal); + if (socket_fd) + close(socket_fd); + exit(1); +} + +void +init_socket() +{ + struct sockaddr_in sin; + + socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (socket_fd < 0) + { + fprintf (stderr, "%s: error getting socket\n", + program_name); + exit(1); + } + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(socket_fd,(struct sockaddr *)(&sin), + sizeof(struct sockaddr_in)) < 0) + { + fprintf (stderr,"%s: cannot bind to port %d\n", + program_name,port); + exit(1); + } + + if (listen(socket_fd,5) < 0) + { + fprintf (stderr,"%s: error listening on socket\n", + program_name); + exit(1); + }; +} + +#define NUM_EVENTC 2 +static void +enable_device(GxidDevice *dev) +{ + XEventClass xevc[NUM_EVENTC]; + int num_eventc = NUM_EVENTC; + int i,j; + + if (!dev->xdevice) + { + if (dev->ispointer) return; + + dev->xdevice = XOpenDevice(dpy, dev->id); + if (!dev->xdevice) return; + + DeviceMotionNotify (dev->xdevice, dev->motionnotify_type, + xevc[0]); + ChangeDeviceNotify (dev->xdevice, dev->changenotify_type, + xevc[1]); + + /* compress out zero event classes */ + for (i=0,j=0;i<NUM_EVENTC;i++) + { + if (xevc[i]) { + xevc[j] = xevc[i]; + j++; + } + } + num_eventc = j; + + XSelectExtensionEvent (dpy, root_window, xevc, num_eventc); + } +} + +/* switch the core pointer from whatever it is now to something else, + return true on success, false otherwise */ +static int +switch_core_pointer() +{ + GxidDevice *old_pointer = 0; + GxidDevice *new_pointer = 0; + int result; + int i; + + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + old_pointer = devices[i]; + else + if (!new_pointer && !devices[i]->exclusive) + new_pointer = devices[i]; + } + + if (!old_pointer || !new_pointer) + return 0; + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Switching core from %ld to %ld\n", + old_pointer->id,new_pointer->id); +#endif + result = XChangePointerDevice(dpy,new_pointer->xdevice, 0, 1); + if (result != Success) + { + fprintf(stderr,"gxid: Error %d switching core from %ld to %ld\n", + result, old_pointer->id, new_pointer->id); + } + else + { + new_pointer->ispointer = 1; + old_pointer->ispointer = 0; + if (!old_pointer->xdevice) + enable_device(old_pointer); + } + + return 1; +} + +void +disable_device(GxidDevice *dev) +{ + if (dev->xdevice) + { + if (dev->ispointer) + return; + XCloseDevice(dpy,dev->xdevice); + dev->xdevice = 0; + } +} + +GxidDevice * +init_device(XDeviceInfo *xdevice) +{ + GxidDevice *dev = (GxidDevice *)malloc(sizeof(GxidDevice)); + XAnyClassPtr class; + int num_axes, i; + + dev->id = xdevice->id; + dev->exclusive = 0; + dev->xdevice = NULL; + + dev->ispointer = (xdevice->use == IsXPointer); + + /* step through the classes */ + + num_axes = 0; + class = xdevice->inputclassinfo; + for (i=0;i<xdevice->num_classes;i++) + { + if (class->class == ValuatorClass) + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + num_axes = xvi->num_axes; + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + + /* return NULL if insufficient axes */ + if (num_axes < 2) + { + free((void *)dev); + return NULL; + } + + if (!dev->ispointer) + enable_device(dev); + return dev; +} + +void +init_xinput() +{ + char **extensions; + XDeviceInfo *xdevices; + int num_xdevices; + int num_extensions; + int i; + + extensions = XListExtensions(dpy, &num_extensions); + for (i = 0; i < num_extensions && + (strcmp(extensions[i], "XInputExtension") != 0); i++); + XFreeExtensionList(extensions); + if (i == num_extensions) /* XInput extension not found */ + { + fprintf(stderr,"XInput extension not found\n"); + exit(1); + } + + xdevices = XListInputDevices(dpy, &num_xdevices); + devices = (GxidDevice **)malloc(num_xdevices * sizeof(GxidDevice *)); + + num_devices = 0; + for(i=0; i<num_xdevices; i++) + { + GxidDevice *dev = init_device(&xdevices[i]); + if (dev) + devices[num_devices++] = dev; + } + XFreeDeviceList(xdevices); +} + +/* If this routine needs fixing, the corresponding routine + in gdkinputgxi.h will need it too. */ + +Window +gxi_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +int +handle_claim_device(GxidClaimDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + int exclusive = ntohl(msg->exclusive); + GxidDevice *device = NULL; + GxidWindow *window = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld claimed (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + if (device->exclusive) + { + /* already in use */ + fprintf(stderr, + "%s: Device %ld already claimed in exclusive mode\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + if (exclusive) + { + for (i=0;i<num_windows;i++) + { + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j]->id == devid) + { + /* already in use */ + fprintf(stderr, + "%s: Can't establish exclusive use of device %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + } + if (device->ispointer) + if (!switch_core_pointer()) + { + fprintf(stderr, + "%s: Can't free up core pointer %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + device->exclusive = 1; + disable_device(device); + XSelectInput(dpy,winid,StructureNotifyMask); + } + else /* !exclusive */ + { + /* FIXME: this is a bit improper. We probably should do this only + when a window is first claimed. But we might be fooled if + an old client died without releasing it's windows. So until + we look for client-window closings, do it here + + (We do look for closings now...) + */ + + XSelectInput(dpy,winid,EnterWindowMask|StructureNotifyMask); + } + + for (i=0;i<num_windows;i++) + { + if (windows[i]->xwindow == winid) + { + window = windows[i]; + break; + } + } + + /* Create window structure if no devices have been previously + claimed on it */ + if (!window) + { + num_windows++; + windows = (GxidWindow **)realloc(windows, + sizeof(GxidWindow*)*num_windows); + window = (GxidWindow *)malloc(sizeof(GxidWindow)); + windows[num_windows-1] = window; + + window->xwindow = winid; + window->root_child = gxi_find_root_child(dpy,winid); + window->num_devices = 0; + window->devices = 0; + } + + + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == device) + return GXID_RETURN_OK; + } + + window->num_devices++; + window->devices = (GxidDevice **)realloc(window->devices, + sizeof(GxidDevice*)*num_devices); + /* we need add the device to the window */ + window->devices[i] = device; + + return GXID_RETURN_OK; +} + +int +handle_release_device(GxidReleaseDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + + GxidDevice *device = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + for (i=0;i<num_windows;i++) + { + GxidWindow *w = windows[i]; + + if (w->xwindow == winid) + for (j=0;j<w->num_devices;j++) + if (w->devices[j]->id == devid) + { + if (j<w->num_devices-1) + w->devices[j] = w->devices[w->num_devices-1]; + w->num_devices--; + + if (w->num_devices == 0) + { + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + } + + if (device->exclusive) + { + device->exclusive = 0; + enable_device(device); + } + return GXID_RETURN_OK; + } + } + + /* device/window combination not found */ + fprintf(stderr, + "%s: Device %ld not claimed for window 0x%lx\n", + program_name,devid,winid); + return GXID_RETURN_ERROR; +} + +void +handle_connection() +{ + GxidMessage msg; + GxidU32 type; + int length; + GxidI32 retval; + + int conn_fd; + struct sockaddr_in sin; + int sin_length; + int count; + + sin_length = sizeof(struct sockaddr_in); + conn_fd = accept(socket_fd,(struct sockaddr *)&sin,&sin_length); + if (conn_fd < 0) + { + fprintf(stderr,"%s: Error accepting connection\n", + program_name); + exit(1); + } + + /* read type and length of message */ + + count = read(conn_fd,(char *)&msg,2*sizeof(GxidU32)); + if (count != 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message header\n", + program_name); + close(conn_fd); + return; + } + type = ntohl(msg.any.type); + length = ntohl(msg.any.length); + + /* read rest of message */ + + if (length > sizeof(GxidMessage)) + { + fprintf(stderr,"%s: Bad message length\n", + program_name); + close(conn_fd); + return; + } + + count = read(conn_fd,2*sizeof(GxidU32) + (char *)&msg, + length - 2*sizeof(GxidU32)); + if (count != length - 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message body\n", + program_name); + close(conn_fd); + return; + } + + switch (type) + { + case GXID_CLAIM_DEVICE: + retval = handle_claim_device((GxidClaimDevice *)&msg); + break; + case GXID_RELEASE_DEVICE: + retval = handle_release_device((GxidReleaseDevice *)&msg); + break; + default: + fprintf(stderr,"%s: Unknown message type: %ld (ignoring)\n", + program_name,type); + close(conn_fd); + return; + } + + count = write(conn_fd,&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"%s: Error writing return code\n", + program_name); + } + + close(conn_fd); +} + +void +handle_motion_notify(XDeviceMotionEvent *event) +{ + int i,j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + Window w, root, child; + int root_x, root_y, x, y, mask; + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + + if (new_device && !new_device->exclusive && !new_device->ispointer) + { + /* make sure we aren't stealing the pointer back from a slow + client */ + child = root_window; + do + { + w = child; + /* FIXME: this fails disasterously if child vanishes between + calls. (Which is prone to happening since we get events + on root just as the client exits) */ + + XQueryPointer(dpy,w,&root,&child,&root_x,&root_y, + &x,&y,&mask); + } + while (child != None); + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == w) + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j] == new_device) + return; + + /* FIXME: do something smarter with axes */ + XChangePointerDevice(dpy,new_device->xdevice, 0, 1); + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_change_notify(XChangeDeviceNotifyEvent *event) +{ + int j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: ChangeNotify event; old = %ld; new = %ld\n", + old_device->id, new_device->id); +#endif + + if (old_device != new_device) + { + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_enter_notify(XEnterWindowEvent *event, GxidWindow *window) +{ + int i; + GxidDevice *old_pointer = NULL; + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + { + old_pointer = devices[i]; + break; + } + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Enter event; oldpointer = %ld\n", + old_pointer->id); +#endif + + if (old_pointer) + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == old_pointer) + { + switch_core_pointer(); + break; + } + } +} + +void +handle_destroy_notify(XDestroyWindowEvent *event) +{ + int i,j; + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == event->window) + { + GxidWindow *w = windows[i]; + + for (j=0;j<w->num_devices;j++) + { +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released on destruction of window 0x%lx.\n", + w->devices[j]->id,w->xwindow); +#endif + + if (w->devices[j]->exclusive) + { + w->devices[j]->exclusive = 0; + enable_device(devices[j]); + } + } + + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + if (w->devices) + free((void *)w->devices); + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + + return; + } +} + +void +handle_xevent() +{ + int i; + XEvent event; + + XNextEvent (dpy, &event); + +#ifdef DEBUG_EVENTS + fprintf(stderr,"Event - type = %d; window = 0x%lx\n", + event.type,event.xany.window); +#endif + + if (event.type == ConfigureNotify) + { +#ifdef DEBUG_EVENTS + XConfigureEvent *xce = (XConfigureEvent *)&event; + fprintf(stderr," configureNotify: window = 0x%lx\n",xce->window); +#endif + } + else if (event.type == EnterNotify) + { + /* pointer entered a claimed window */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_enter_notify((XEnterWindowEvent *)&event,windows[i]); + } + } + else if (event.type == DestroyNotify) + { + /* A claimed window was destroyed */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_destroy_notify((XDestroyWindowEvent *)&event); + } + } + else + for (i=0;i<num_devices;i++) + { + if (event.type == devices[i]->motionnotify_type) + { + handle_motion_notify((XDeviceMotionEvent *)&event); + break; + } + else if (event.type == devices[i]->changenotify_type) + { + handle_change_notify((XChangeDeviceNotifyEvent *)&event); + break; + } + } +} + +void +usage() +{ + fprintf(stderr,"Usage: %s [-d display] [-p --gxid-port port]\n", + program_name); + exit(1); +} + +int +main(int argc, char **argv) +{ + int i; + char *display_name = NULL; + fd_set readfds; + + program_name = argv[0]; + + for (i=1;i<argc;i++) + { + if (!strcmp(argv[i],"-d")) + { + if (++i >= argc) usage(); + display_name = argv[i]; + } + else if (!strcmp(argv[i],"--gxid-port") || + !strcmp(argv[i],"-p")) + { + if (++i >= argc) usage(); + port = atoi(argv[i]); + break; + } + else + usage(); + } + + if (!port) + { + char *t = getenv("GXID_PORT"); + if (t) + port = atoi(t); + else + port = 6951; + } + /* set up a signal handler so we can clean up if killed */ + + signal(SIGTERM,handler); + signal(SIGINT,handler); + + /* initialize the X connection */ + + dpy = XOpenDisplay (display_name); + if (!dpy) + { + fprintf (stderr, "%s: unable to open display '%s'\n", + program_name, XDisplayName (display_name)); + exit (1); + } + + root_window = DefaultRootWindow(dpy); + + /* We'll want to do this in the future if we are to support + gxid monitoring visibility information for clients */ +#if 0 + XSelectInput(dpy,root_window,SubstructureNotifyMask); +#endif + init_xinput(); + + /* set up our server connection */ + + init_socket(); + + /* main loop */ + + if (XPending(dpy)) /* this seems necessary to get things + in sync */ + handle_xevent(); + while (1) + { + + FD_ZERO(&readfds); + FD_SET(ConnectionNumber(dpy),&readfds); + FD_SET(socket_fd,&readfds); + + if (select(8*sizeof(readfds),&readfds, + (fd_set *)0,(fd_set *)0, (struct timeval *)0) < 0) + { + fprintf(stderr,"Error in select\n"); + exit(1); + } + + if (FD_ISSET(socket_fd,&readfds)) + handle_connection(socket_fd); + + while (XPending(dpy)) + handle_xevent(); + } + + XCloseDisplay (dpy); + exit (0); +} diff --git a/gdk/gxid_lib.c b/gdk/gxid_lib.c new file mode 100644 index 0000000000..357b764513 --- /dev/null +++ b/gdk/gxid_lib.c @@ -0,0 +1,116 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include "../config.h" + +#ifdef XINPUT_GXI + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +#include "gxid_lib.h" + +/* handles mechanics of communicating with a client */ +static int +gxid_send_message(char *host, int port, GxidMessage *msg) +{ + int socket_fd; + struct sockaddr_in sin; + int count; + GxidI32 retval; + struct hostent *he; + + if (!port) port = 6951; + + if (!host || strcmp(host,"localhost") ) + { + /* looking it up as localhost can be _SLOW_ on ppp systems */ + /* FIXME: Could localhost be anything other than loopback? */ + host = "127.0.0.1"; + } + + he = gethostbyname(host); + if (!he) + { + fprintf(stderr,"gxid_lib: error looking up %s\n",host); + return GXID_RETURN_ERROR; + } + + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + memcpy(&sin.sin_addr,he->h_addr_list[0],he->h_length); + + socket_fd = socket(AF_INET,SOCK_STREAM,0); + if (socket_fd < 0) + { + fprintf(stderr,"gxid_lib: can't get socket"); + return GXID_RETURN_ERROR; + } + + if (connect(socket_fd, (struct sockaddr *)&sin, + sizeof sin) < 0) + { + fprintf(stderr,"gxid_lib: can't connect to %s:%d\n",host,port); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + count = write(socket_fd,(char *)msg,ntohl(msg->any.length)); + if (count != ntohl(msg->any.length)) + { + fprintf(stderr,"gxid_lib: error writing"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + /* now read the return code */ + count = read(socket_fd,(char *)&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"gxid_lib: error reading return code"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + close (socket_fd); + return ntohl(retval); +} + +/* claim a device. If exclusive, device is claimed exclusively */ +int +gxid_claim_device(char *host, int port, GxidU32 device, GxidU32 window, + int exclusive) +{ + GxidClaimDevice msg; + msg.type = htonl(GXID_CLAIM_DEVICE); + msg.length = htonl(sizeof(GxidClaimDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + msg.exclusive = htonl(exclusive); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +/* release a device/window pair */ +int +gxid_release_device(char *host, int port, GxidU32 device, GxidU32 window) +{ + GxidReleaseDevice msg; + msg.type = htonl(GXID_RELEASE_DEVICE); + msg.length = htonl(sizeof(GxidReleaseDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +#endif /* XINPUT_GXI */ + diff --git a/gdk/gxid_lib.h b/gdk/gxid_lib.h new file mode 100644 index 0000000000..6a7103bbe0 --- /dev/null +++ b/gdk/gxid_lib.h @@ -0,0 +1,6 @@ +#include "gxid_proto.h" + +int gxid_claim_device(char *host, int port, + GxidU32 device, GxidU32 window, int exclusive); +int gxid_release_device(char *host, int port, GxidU32 device, + GxidU32 window); diff --git a/gdk/gxid_proto.h b/gdk/gxid_proto.h new file mode 100644 index 0000000000..24959b806c --- /dev/null +++ b/gdk/gxid_proto.h @@ -0,0 +1,39 @@ +#define GXID_CLAIM_DEVICE 1 +#define GXID_RELEASE_DEVICE 2 + +#define GXID_RETURN_OK 0 +#define GXID_RETURN_ERROR -1 + +typedef struct GxidClaimDevice_ GxidClaimDevice; +typedef struct GxidReleaseDevice_ GxidReleaseDevice; +typedef struct GxidMessageAny_ GxidMessageAny; +typedef union GxidMessage_ GxidMessage; + +typedef unsigned long GxidU32; +typedef long GxidI32; + +struct GxidClaimDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; + GxidU32 exclusive; +}; + +struct GxidReleaseDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; +}; + +struct GxidMessageAny_ { + GxidU32 type; + GxidU32 length; +}; + +union GxidMessage_ { + GxidMessageAny any; + GxidClaimDevice claim; + GxidReleaseDevice release; +}; diff --git a/gdk/makecursors b/gdk/makecursors new file mode 100755 index 0000000000..664776a2b7 --- /dev/null +++ b/gdk/makecursors @@ -0,0 +1,5 @@ +#!/bin/sh + +sed -f makecursors.sed $1 > .makecursors.tmp +awk '{printf "%s = %s,\n", $1, $2}' .makecursors.tmp +rm .makecursors.tmp diff --git a/gdk/makecursors.sed b/gdk/makecursors.sed new file mode 100644 index 0000000000..107d13f8dc --- /dev/null +++ b/gdk/makecursors.sed @@ -0,0 +1,3 @@ +/define/ ! d +/define/ y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ +s/^.*XC_/GDK_/g diff --git a/gdk/makekeysyms b/gdk/makekeysyms new file mode 100755 index 0000000000..40b49d4e88 --- /dev/null +++ b/gdk/makekeysyms @@ -0,0 +1,5 @@ +#!/bin/sh + +sed -f makekeysyms.sed $1 > .makekeysms.tmp +awk '{printf "#define %s %s\n", $1, $2}' .makekeysms.tmp +rm .makekeysms.tmp diff --git a/gdk/makekeysyms.sed b/gdk/makekeysyms.sed new file mode 100644 index 0000000000..bafbf76c02 --- /dev/null +++ b/gdk/makekeysyms.sed @@ -0,0 +1,3 @@ +/define/ ! d +s/^.*XK_/GDK_/g +s/0X/0x/g diff --git a/gdk/x11/gdkcolor-x11.c b/gdk/x11/gdkcolor-x11.c new file mode 100644 index 0000000000..5e66f089ba --- /dev/null +++ b/gdk/x11/gdkcolor-x11.c @@ -0,0 +1,718 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); + +static GHashTable *colormap_hash = NULL; + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + XColor default_colors[256]; + int size; + int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->visual = visual; + private->next_color = 0; + private->ref_count = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->private_val = private_cmap; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + for (i = 0; i < 256; i++) + default_colors[i].pixel = i; + + XQueryColors (private->xdisplay, + DefaultColormap (private->xdisplay, gdk_screen), + default_colors, visual->colormap_size); + + for (i = 0; i < visual->colormap_size; i++) + { + colormap->colors[i].pixel = default_colors[i].pixel; + colormap->colors[i].red = default_colors[i].red; + colormap->colors[i].green = default_colors[i].green; + colormap->colors[i].blue = default_colors[i].blue; + } + + gdk_colormap_change (colormap, visual->colormap_size); + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + private->private_val = TRUE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocAll); + + size = 1 << visual->red_prec; + for (i = 0; i < size; i++) + colormap->colors[i].red = i * 65535 / (size - 1); + + size = 1 << visual->green_prec; + for (i = 0; i < size; i++) + colormap->colors[i].green = i * 65535 / (size - 1); + + size = 1 << visual->blue_prec; + for (i = 0; i < size; i++) + colormap->colors[i].blue = i * 65535 / (size - 1); + + gdk_colormap_change (colormap, visual->colormap_size); + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + + if (private->ref_count > 0) + return; + + gdk_colormap_remove (colormap); + XFreeColormap (private->xdisplay, private->xcolormap); + g_free (colormap); +} + +void +gdk_colormap_destroy (GdkColormap *colormap) +{ + gdk_colormap_unref (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_if_fail (cmap != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = DefaultColormap (gdk_display, gdk_screen); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->next_color = 0; + private->ref_count = 1; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + return DisplayCells (gdk_display, gdk_screen); +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor palette[256]; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].pixel = colormap->colors[i].pixel; + palette[i].red = colormap->colors[i].red; + palette[i].green = colormap->colors[i].green; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoRed | DoGreen | DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors); + private->next_color = MAX (private->next_color, ncolors); + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + + shift = visual->red_shift; + max_colors = 1 << visual->red_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].red = colormap->colors[i].red; + palette[i].flags = DoRed; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->green_shift; + max_colors = 1 << visual->green_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].green = colormap->colors[i].green; + palette[i].flags = DoGreen; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->blue_shift; + max_colors = 1 << visual->blue_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + break; + + default: + break; + } +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gint +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = XAllocColorCells (private->xdisplay, private->xcolormap, + contiguous, planes, nplanes, pixels, npixels); + + return return_val; +} + +void +gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + GdkColormapPrivate *private; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + + XFreeColors (private->xdisplay, private->xcolormap, + pixels, npixels, planes); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = WhitePixel (gdk_display, gdk_screen); + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = BlackPixel (gdk_display, gdk_screen); + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gint return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (gdk_display, gdk_screen); + + if (XParseColor (gdk_display, xcolormap, spec, &xcolor)) + { + return_val = TRUE; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor xcolor; + gchar available[256]; + gint available_init; + gint return_val; + gint i, index; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.pixel = color->pixel; + xcolor.flags = DoRed | DoGreen | DoBlue; + + return_val = FALSE; + private = (GdkColormapPrivate*) colormap; + + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + if (private->private_val) + { + if (private->next_color > 255) + { + for (i = 0; i < 256; i++) + available[i] = TRUE; + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + *color = colormap->colors[index]; + return_val = TRUE; + } + else + { + return_val = FALSE; + } + } + else + { + xcolor.pixel = 255 - private->next_color; + color->pixel = xcolor.pixel; + private->next_color += 1; + + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + return_val = TRUE; + } + } + else + { + available_init = 1; + + while (1) + { + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + + colormap->colors[color->pixel] = *color; + + return_val = TRUE; + break; + } + else + { + if (available_init) + { + available_init = 0; + for (i = 0; i < 256; i++) + available[i] = TRUE; + } + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + xcolor.red = colormap->colors[index].red; + xcolor.green = colormap->colors[index].green; + xcolor.blue = colormap->colors[index].blue; + } + else + { + return_val = FALSE; + break; + } + } + } + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) + + ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) + + ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + color->pixel = xcolor.pixel; + return_val = TRUE; + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + return_val = TRUE; + } + else + return_val = FALSE; + break; + } + + return return_val; +} + +gint +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.pixel = color->pixel; + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.flags = DoRed | DoGreen | DoBlue; + + private = (GdkColormapPrivate*) colormap; + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + + return TRUE; +} + +gint +gdk_color_equal (GdkColor *colora, + GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +GdkColormap* +gdkx_colormap_get (Colormap xcolormap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + colormap = gdk_colormap_lookup (xcolormap); + if (colormap) + return colormap; + + if (xcolormap == DefaultColormap (gdk_display, gdk_screen)) + return gdk_colormap_get_system (); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = xcolormap; + private->visual = NULL; + private->private_val = TRUE; + private->next_color = 0; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + + return colormap; +} + + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < 256; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} diff --git a/gdk/x11/gdkcursor-x11.c b/gdk/x11/gdkcursor-x11.c new file mode 100644 index 0000000000..22bfd250b1 --- /dev/null +++ b/gdk/x11/gdkcursor-x11.c @@ -0,0 +1,52 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + Cursor xcursor; + + xcursor = XCreateFontCursor (gdk_display, cursor_type); + private = g_new (GdkCursorPrivate, 1); + private->xdisplay = gdk_display; + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + + private = (GdkCursorPrivate *) cursor; + XFreeCursor (private->xdisplay, private->xcursor); + + g_free (private); +} diff --git a/gdk/x11/gdkfont-x11.c b/gdk/x11/gdkfont-x11.c new file mode 100644 index 0000000000..e1b1e72549 --- /dev/null +++ b/gdk/x11/gdkfont-x11.c @@ -0,0 +1,379 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xos.h> +#include "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + private->xfont = XLoadQueryFont (private->xdisplay, font_name); + private->ref_count = 1; + + if (!private->xfont) + { + g_free (font); + return NULL; + } + else + { + font->type = GDK_FONT_FONT; + font->ascent = ((XFontStruct *) private->xfont)->ascent; + font->descent = ((XFontStruct *) private->xfont)->descent; + } + + gdk_xid_table_insert (&((XFontStruct *) private->xfont)->fid, font); + + return font; +} + +GdkFont* +gdk_fontset_load(gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + XFontSet fontset; + gint missing_charset_count; + gchar **missing_charset_list; + gchar *def_string; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + fontset = XCreateFontSet (gdk_display, fontset_name, + &missing_charset_list, &missing_charset_count, + &def_string); + + if (missing_charset_count) + { + g_print ("Missing charsets in FontSet creation"); + XFreeStringList (missing_charset_list); + } + + private->ref_count = 1; + + if (!fontset) + { + g_free (font); + return NULL; + } + else + { + XFontSetExtents *extent = XExtentsOfFontSet(fontset); + + private->xfont = fontset; + font->type = GDK_FONT_FONTSET; + /* how to define ascent and descent for fontset ??? */ + font->ascent = extent->max_logical_extent.height; + font->descent = font->ascent / 4 ; + } + return font; +} +void +gdk_font_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid); + XFreeFont (private->xdisplay, (XFontStruct *) private->xfont); + g_free (font); + } +} + +void +gdk_fontset_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + XFreeFontSet (private->xdisplay, (XFontSet) private->xfont); + g_free (font); + } +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +gint +gdk_font_id (GdkFont *font) +{ + GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + return ((XFontStruct *) font_private->xfont)->fid; + } + else + { + return 0; + } +} + +gint +gdk_font_equal (GdkFont *fonta, + GdkFont *fontb) +{ + GdkFontPrivate *privatea; + GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (GdkFontPrivate*) fonta; + privateb = (GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + { + return (((XFontStruct *) privatea->xfont)->fid == + ((XFontStruct *) privateb->xfont)->fid); + } + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + /* how to compare two fontsets ?? by basename or XFontSet ?? */ + return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont)); + } + else + /* fontset != font */ + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + GdkFontPrivate *font_private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + font_private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) font_private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, string, strlen (string)); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) font_private->xfont; + width = XmbTextEscapement (fontset, string, strlen(string)); + break; + default: + width = 0; + } + + return width; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, text, text_length); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, text, text_length); + break; + default: + width = 0; + } + return width; +} + +/* Problem: What if a character is a 16 bits character ?? */ +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + GdkFontPrivate *private; + XCharStruct *chars; + gint width; + guint ch = character & 0xff; /* get rid of sign-extension */ + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + /* only 8 bits characters are considered here */ + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && + (xfont->max_byte1 == 0) && + (ch >= xfont->min_char_or_byte2) && + (ch <= xfont->max_char_or_byte2)) + { + chars = xfont->per_char; + if (chars) + width = chars[ch - xfont->min_char_or_byte2].width; + else + width = xfont->min_bounds.width; + } + else + { + width = XTextWidth (xfont, &character, 1); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, &character, 1) ; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, log; + int direction; + int font_ascent; + int font_descent; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + width = overall.rbearing; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &log); + width = log.width; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_measure (font, &character, 1); +} diff --git a/gdk/x11/gdkglobals-x11.c b/gdk/x11/gdkglobals-x11.c new file mode 100644 index 0000000000..58f7bf8447 --- /dev/null +++ b/gdk/x11/gdkglobals-x11.c @@ -0,0 +1,47 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include <X11/Xlib.h> +#include "gdktypes.h" +#include "gdkprivate.h" + +gint gdk_debug_level = 0; +gint gdk_show_events = FALSE; +gint gdk_use_xshm = TRUE; +gchar *gdk_display_name = NULL; +Display *gdk_display = NULL; +gint gdk_screen; +Window gdk_root_window; +Window gdk_leader_window; +GdkWindowPrivate gdk_root_parent; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +Atom gdk_selection_property; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + None,None, + NULL, + 0, 0, + {0,0}}; +gchar *gdk_progname = NULL; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c new file mode 100644 index 0000000000..bcda3119fc --- /dev/null +++ b/gdk/x11/gdkimage-x11.c @@ -0,0 +1,492 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <sys/types.h> + +#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) +#define USE_SHM +#endif + +#ifdef USE_SHM +#include <sys/ipc.h> +#include <sys/shm.h> +#endif /* USE_SHM */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#ifdef USE_SHM +#include <X11/extensions/XShm.h> +#endif /* USE_SHM */ + +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + + +static GList *image_list = NULL; + + +void +gdk_image_exit () +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap, + 0, 0, w ,h, 8, 0); + private->ximage->data = data; + private->ximage->bitmap_bit_order = MSBFirst; + private->ximage->byte_order = MSBFirst; + image->byte_order = MSBFirst; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +static int +gdk_image_check_xshm(Display *display) +/* + * Desc: query the server for support for the MIT_SHM extension + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +{ +#ifdef USE_SHM + int major, minor, ignore; + Bool pixmaps; + + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) + { + return (pixmaps==True) ? 2 : 1; + } + } +#endif /* USE_SHM */ + return 0; +} + +void +gdk_image_init () +{ + if (gdk_use_xshm) + { + if (!gdk_image_check_xshm (gdk_display)) + { + g_warning ("MIT-SHM Extension not availible on server"); + gdk_use_xshm = False; + } + } +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + Visual *xvisual; + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + + if (!image) + image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = visual->depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + if (gdk_use_xshm) + { + private->image_put = gdk_image_put_shared; + + private->x_shm_info = g_new (XShmSegmentInfo, 1); + x_shm_info = private->x_shm_info; + + private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, NULL, x_shm_info, width, height); + if (private->ximage == NULL) + { + g_warning ("XShmCreateImage failed"); + + g_free (image); + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->shmid = shmget (IPC_PRIVATE, + private->ximage->bytes_per_line * private->ximage->height, + IPC_CREAT | 0777); + + if (x_shm_info->shmid == -1) + { + g_warning ("shmget failed!"); + + XDestroyImage (private->ximage); + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->readOnly = False; + x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0); + private->ximage->data = x_shm_info->shmaddr; + + if (x_shm_info->shmaddr == (char*) -1) + { + g_warning ("shmat failed!"); + + XDestroyImage (private->ximage); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + return NULL; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (x_shm_info->shmaddr != (char*) -1) + shmctl (x_shm_info->shmid, IPC_RMID, 0); +#endif + + gdk_error_code = 0; + gdk_error_warnings = 0; + + XShmAttach (private->xdisplay, x_shm_info); + XSync (private->xdisplay, False); + + gdk_error_warnings = 1; + if (gdk_error_code == -1) + { + g_warning ("XShmAttach failed!"); + + XDestroyImage (private->ximage); + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + return NULL; + } + + if (image) + image_list = g_list_prepend (image_list, image); + } + else + { + g_free (image); + return NULL; + } + break; +#else /* USE_SHM */ + g_free (image); + return NULL; +#endif /* USE_SHM */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, 0, 0, width, height, 32, 0); + + private->ximage->data = g_new (char, private->ximage->bytes_per_line * + private->ximage->height); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + if (image) + { + image->byte_order = private->ximage->byte_order; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + + switch (private->ximage->bits_per_pixel) + { + case 8: + image->bpp = 1; + break; + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + } + } + } + + return image; +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + private->ximage = XGetImage (private->xdisplay, + win_private->xwindow, + x, y, width, height, + AllPlanes, ZPixmap); + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + image->depth = private->ximage->depth; + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + pixel = XGetPixel (private->ximage, x, y); + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + pixel = XPutPixel (private->ximage, x, y, pixel); +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + switch (image->type) + { + case GDK_IMAGE_NORMAL: + XDestroyImage (private->ximage); + break; + + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + XShmDetach (private->xdisplay, private->x_shm_info); + XDestroyImage (private->ximage); + + x_shm_info = private->x_shm_info; + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + + image_list = g_list_remove (image_list, image); +#else /* USE_SHM */ + g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_NORMAL); + + XPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height); +} + +static void +gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ +#ifdef USE_SHM + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_SHARED); + + XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height, False); +#else /* USE_SHM */ + g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ +} diff --git a/gdk/x11/gdkinput-gxi.c b/gdk/x11/gdkinput-gxi.c new file mode 100644 index 0000000000..a30e05f956 --- /dev/null +++ b/gdk/x11/gdkinput-gxi.c @@ -0,0 +1,628 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#ifdef XINPUT_GXI + +/* #define DEBUG_SWITCHING */ + +#include <gxid_lib.h> + +/* Forward declarations */ +static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode); +static gint gdk_input_is_extension_device (guint32 deviceid); +static void gdk_input_gxi_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev); + +static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent); +static gint gdk_input_gxi_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static Window gdk_input_find_root_child(Display *dpy, Window w); +static void gdk_input_compute_obscuring(GdkInputWindow *input_window); +static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, + gdouble y); +static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_gxi_ungrab_pointer (guint32 time); + +/* Local variables */ + +static GdkDevicePrivate *gdk_input_current_device; +static GdkDevicePrivate *gdk_input_core_pointer; + +void +gdk_input_init(void) +{ + GList *tmp_list; + + gdk_input_vtable.set_mode = gdk_input_gxi_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_gxi_motion_events; + gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_gxi_configure_event; + gdk_input_vtable.enter_event = gdk_input_gxi_enter_event; + gdk_input_vtable.other_event = gdk_input_gxi_other_event; + gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event; + gdk_input_vtable.enable_window = gdk_input_gxi_enable_window; + gdk_input_vtable.disable_window = gdk_input_gxi_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_core_pointer = NULL; + + if (!gdk_input_gxid_host) + { + gdk_input_gxid_host = getenv("GXID_HOST"); + } + if (!gdk_input_gxid_port) + { + char *t = getenv("GXID_PORT"); + if (t) + gdk_input_gxid_port = atoi(t); + } + + gdk_input_common_init(TRUE); + + /* find initial core pointer */ + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdk_input_is_extension_device(gdkdev->info.deviceid)) + { + gdk_input_gxi_select_notify (gdkdev); + } + else + { + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + gdk_input_core_pointer = gdkdev; + } + } +} + +static void +gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev) +{ + XEventClass class; + + ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class); + + XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1); +} + +/* Set the core pointer. Device should already be enabled. */ +static gint +gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev) +{ + int x_axis,y_axis; + + g_return_val_if_fail(gdkdev->xdevice,FALSE); + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + + g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE); + + /* core_pointer might not be up to date so we check with the server + before change the pointer */ + + if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) ) + { +#if 0 + if (gdkdev != gdk_input_core_pointer) + g_warning("core pointer inconsistency"); +#endif + return TRUE; + } + + if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis) + != Success ) + { + return FALSE; + } + else + { + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + return TRUE; + } +} + + +/* FIXME, merge with gdk_input_xfree_set_mode */ + +static gint +gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (old_mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + if (mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + if (!gdk_input_enable_window(input_window->window, gdkdev)) + { + gdk_input_set_mode(deviceid, old_mode); + return FALSE; + } + } + } + + return TRUE; + +} + +gint +gdk_input_is_extension_device (guint32 deviceid) +{ + XDeviceInfo *devices; + int num_devices, loop; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + devices = XListInputDevices(gdk_display, &num_devices); + for(loop=0; loop<num_devices; loop++) + { + if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice)) + { + XFreeDeviceList(devices); + return TRUE; + } + } + + XFreeDeviceList(devices); + return FALSE; +} + +static void +gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window), + &root_x, &root_y, NULL, NULL); + input_window->root_x = root_x; + input_window->root_y = root_y; + gdk_input_compute_obscuring(input_window); +} + +static void +gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_compute_obscuring(input_window); +} + +static gint +gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (gdkdev->info.mode == GDK_MODE_DISABLED || + input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + if (gdkdev != gdk_input_current_device && + xevent->type != gdkdev->changenotify_type) + { + gdk_input_current_device = gdkdev; + } + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_MOTION_NOTIFY && + (!gdkdev->button_state) && (!input_window->grabbed) && + ((event->motion.x < 0) || (event->motion.y < 0) || + (event->motion.x > ((GdkWindowPrivate *)window)->width) || + (event->motion.y > ((GdkWindowPrivate *)window)->height) || + gdk_input_is_obscured(input_window,event->motion.x,event->motion.y))) + { +#ifdef DEBUG_SWITCHING + g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n", + gdkdev->info.deviceid,event->motion.x,event->motion.y); + g_print(" window geometry is: %dx%d\n", + ((GdkWindowPrivate *)window)->width, + ((GdkWindowPrivate *)window)->height); +#endif + gdk_input_gxi_set_core_pointer(gdkdev); + return FALSE; + } + else + return return_val; + +} + +static void +gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev) +{ + GList *t; + + if (gdk_input_is_extension_device (gdkdev->info.deviceid)) + { + if (!gdkdev->xdevice) + { + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + gdk_input_gxi_select_notify (gdkdev); + gdkdev->needs_update = 1; + } + if (gdkdev->needs_update && gdkdev->xdevice) + { + for (t = gdk_input_windows; t; t = t->next) + gdk_input_common_select_events (((GdkInputWindow *)t->data)->window, + gdkdev); + gdkdev->needs_update = 0; + } + } +} + +static gint +gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent) +{ + GdkDevicePrivate *gdkdev = + gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (xevent->type == gdkdev->changenotify_type) + { + if (gdk_input_core_pointer != gdkdev) + { +#ifdef DEBUG_SWITCHING + g_print("ChangeNotify from %d to %d:\n", + gdk_input_core_pointer->info.deviceid, + gdkdev->info.deviceid); +#endif + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + } + } + + return FALSE; +} + +static gint +gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (!gdkdev->claimed) + { + if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window), FALSE) != + GXID_RETURN_OK) + { + g_warning("Could not get device (is gxid running?)\n"); + return FALSE; + } + gdkdev->claimed = TRUE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (gdkdev->claimed) + { + gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window)); + + gdkdev->claimed = FALSE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y) +{ + int i; + for (i=0;i<input_window->num_obscuring;i++) + { + GdkRectangle *rect = &input_window->obscuring[i]; + if ((x >= rect->x) && + (y >= rect->y) && + (x < rect->x + rect->width) && + (y < rect->y + rect->height)) + return TRUE; + } + return FALSE; +} + +/* If this routine needs fixing, the corresponding routine + in gxid.c will need it too. */ + +static Window +gdk_input_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +void +gdk_input_compute_obscuring(GdkInputWindow *input_window) +{ + int i; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + Window root,parent; + Window *children; + int nchildren; + + Window w = GDK_WINDOW_XWINDOW(input_window->window); + Window root_child = gdk_input_find_root_child(gdk_display,w); + gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height); + + input_window->root_x = x; + input_window->root_y = y; + + XQueryTree(gdk_display,GDK_ROOT_WINDOW(), + &root,&parent,&children,&nchildren); + + + if (input_window->obscuring) + g_free(input_window->obscuring); + input_window->obscuring = 0; + input_window->num_obscuring = 0; + + for (i=0;i<nchildren;i++) + if (children[i] == root_child) + break; + + if (i>=nchildren-1) + { + if (nchildren) + XFree(children); + return; + } + + input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1)); + + for (i=i+1;i<nchildren;i++) + { + int xmin, xmax, ymin, ymax; + XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc, + &border_widthc, &depthc); + xmin = xc>x ? xc : x; + xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width; + ymin = yc>y ? yc : y; + ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height; + if ((xmin < xmax) && (ymin < ymax)) + { + XWindowAttributes attributes; + XGetWindowAttributes(gdk_display,children[i],&attributes); + if (attributes.map_state == IsViewable) + { + GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring]; + + /* we store the whole window, not just the obscuring part */ + rect->x = xc - x; + rect->y = yc - y; + rect->width = widthc; + rect->height = heightc; + input_window->num_obscuring++; + } + } + } + + if (nchildren) + XFree(children); +} + +static void +gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (gdkdev == gdk_input_core_pointer) + gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y, + pressure, xtilt, ytilt, mask); + else + gdk_input_common_get_pointer (window, deviceid, x, y, + pressure, xtilt, ytilt, mask); +} + +static GdkTimeCoord * +gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, NULL); + + + if (gdkdev == gdk_input_core_pointer) + return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop, + nevents_return); + else + return gdk_input_common_motion_events (window, deviceid, start, stop, + nevents_return); + +} + +static gint +gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + new_window = input_window; + + tmp_list = tmp_list->next; + } + + new_window->grabbed = TRUE; + return Success; +} + +static void +gdk_input_gxi_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + input_window->grabbed = FALSE; + tmp_list = tmp_list->next; + } +} + +#endif /* XINPUT_GXI */ diff --git a/gdk/x11/gdkinput-none.c b/gdk/x11/gdkinput-none.c new file mode 100644 index 0000000000..8ae8c4189a --- /dev/null +++ b/gdk/x11/gdkinput-none.c @@ -0,0 +1,72 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#ifdef XINPUT_NONE + +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +void +gdk_input_init () +{ + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + + gdk_input_devices = g_list_append (NULL, &gdk_input_core_info); + + gdk_input_ignore_core = FALSE; +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; +} + +#endif /* XINPUT_NONE */ diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c new file mode 100644 index 0000000000..5e457e0aa1 --- /dev/null +++ b/gdk/x11/gdkinput-x11.c @@ -0,0 +1,687 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#if defined(XINPUT_GXI) || defined(XINPUT_XFREE) + +/* Forward declarations */ +static void gdk_input_get_root_relative_geometry (Display *dpy, Window w, + int *x_ret, int *y_ret, + int *width_ret, + int *height_ret); +static GdkDevicePrivate *gdk_input_device_new(XDeviceInfo *device, + gint include_core); +static void gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes); +static void gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_translate_coordinates(GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, + gdouble *pressure, + gdouble *xtilt, gdouble *ytilt); +static guint gdk_input_translate_state(guint state, guint device_state); +static gint gdk_input_common_init(gint include_core); +static gint gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev); +static void gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes); +static GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +/* Global variables */ + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static void +gdk_input_get_root_relative_geometry(Display *dpy, Window w, int *x_ret, int *y_ret, + int *width_ret, int *height_ret) +{ + Window root,parent; + Window *children; + int nchildren; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&x,&y,&width,&height,&border_widthc, + &depthc); + x += border_widthc; + y += border_widthc; + + while (root != parent) + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&xc,&yc,&widthc,&heightc, + &border_widthc,&depthc); + x += xc + border_widthc; + y += yc + border_widthc; + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; + if (width_ret) + *width_ret = width; + if (height_ret) + *height_ret = height; +} + +static GdkDevicePrivate * +gdk_input_device_new(XDeviceInfo *device, gint include_core) +{ + GdkDevicePrivate *gdkdev; + gchar *tmp_name, *p; + XAnyClassPtr class; + gint i,j; + + gdkdev = g_new(GdkDevicePrivate,1); + + gdkdev->info.deviceid = device->id; + if (device->name[0]) { + gdkdev->info.name = g_new(char, strlen(device->name)+1); + strcpy(gdkdev->info.name,device->name); + } else { + /* XFree86 3.2 gives an empty name to the default core devices, + (fixed in 3.2A) */ + gdkdev->info.name = g_strdup("pointer"); + strcpy(gdkdev->info.name,"pointer"); + gdkdev->info.source = GDK_SOURCE_MOUSE; + } + + gdkdev->info.mode = GDK_MODE_DISABLED; + + /* Try to figure out what kind of device this is by its name - + could invite a very, very, long list... Lowercase name + for comparison purposes */ + + tmp_name = g_strdup(gdkdev->info.name); + for (p = tmp_name; *p; p++) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + } + + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + + g_free(tmp_name); + + gdkdev->xdevice = NULL; + + /* step through the classes */ + + gdkdev->info.num_axes = 0; + gdkdev->axes = 0; + gdkdev->info.has_cursor = 0; + gdkdev->needs_update = FALSE; + gdkdev->claimed = FALSE; + gdkdev->button_state = 0; + + class = device->inputclassinfo; + for (i=0;i<device->num_classes;i++) + { + switch (class->class) { + case ButtonClass: + { + break; + } + case ValuatorClass: + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + gdkdev->info.num_axes = xvi->num_axes; + gdkdev->axes = g_new(GdkAxisInfo, xvi->num_axes); + gdkdev->info.axes = g_new(GdkAxisUse, xvi->num_axes); + for (j=0;j<xvi->num_axes;j++) + { + gdkdev->axes[j].resolution = + gdkdev->axes[j].xresolution = xvi->axes[j].resolution; + gdkdev->axes[j].min_value = + gdkdev->axes[j].xmin_value = xvi->axes[j].min_value; + gdkdev->axes[j].max_value = + gdkdev->axes[j].xmax_value = xvi->axes[j].max_value; + gdkdev->info.axes[j] = GDK_AXIS_IGNORE; + } + j=0; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_X; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_Y; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_PRESSURE; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_XTILT; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_YTILT; + + /* set up reverse lookup on axis use */ + for (j=GDK_AXIS_IGNORE;j<GDK_AXIS_LAST;j++) + gdkdev->axis_for_use[j] = -1; + + for (j=0;j<xvi->num_axes;j++) + if (gdkdev->info.axes[j] != GDK_AXIS_IGNORE) + gdkdev->axis_for_use[gdkdev->info.axes[j]] = j; + + break; + } + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + /* return NULL if no axes */ + if (!gdkdev->info.num_axes || !gdkdev->axes || + (!include_core && device->use == IsXPointer)) + { + g_free(gdkdev->info.name); + if (gdkdev->axes) + g_free(gdkdev->axes); + g_free(gdkdev); + return NULL; + } + + if (device->use != IsXPointer) + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + + return gdkdev; +} + +static void +gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes) +{ + gint i; + XEventClass class; + + i = 0; + /* We have to track press and release events in pairs to keep + track of button state correctly and implement grabbing */ + if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK) + { + DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type, + class); + if (class != 0) + classes[i++] = class; + DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type, + class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_MASK) + { + DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_HINT_MASK) + { + /* We'll get into trouble if the macros change, but at least we'll + know about it, and we avoid warnings now */ + DevicePointerMotionHint (gdkdev->xdevice, 0, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_IN_MASK) + { + ProximityIn (gdkdev->xdevice, gdkdev->proximityin_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_OUT_MASK) + { + ProximityOut (gdkdev->xdevice, gdkdev->proximityout_type, class); + if (class != 0) + classes[i++] = class; + } + + *num_classes = i; +} + +static void +gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + XEventClass classes[6]; + gint num_classes; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes); + else + gdk_input_common_find_events(window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + classes, &num_classes); + + XSelectExtensionEvent (gdk_display, + GDK_WINDOW_XWINDOW(window), + classes, num_classes); +} + +gint +gdk_input_common_init(gint include_core) +{ + char **extensions; + XDeviceInfo *devices; + int num_devices; + int num_extensions, loop; + Display *display = gdk_display; + + /* Init global vars */ + gdk_window_get_geometry(NULL, /* use root window */ + NULL,NULL, + &gdk_input_root_width,&gdk_input_root_height, + NULL); + + /* Init XInput extension */ + + extensions = XListExtensions(display, &num_extensions); + for (loop = 0; loop < num_extensions && + (strcmp(extensions[loop], "XInputExtension") != 0); loop++); + XFreeExtensionList(extensions); + if (loop == num_extensions) /* XInput extension not found */ + return FALSE; + + gdk_input_devices = 0; + devices = XListInputDevices(display, &num_devices); + + for(loop=0; loop<num_devices; loop++) + { + GdkDevicePrivate *gdkdev = gdk_input_device_new(&devices[loop], + include_core); + if (gdkdev) + gdk_input_devices = g_list_append(gdk_input_devices, gdkdev); + } + XFreeDeviceList(devices); + + gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); + + return TRUE; +} + +static void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, gdouble *pressure, + gdouble *xtilt, gdouble *ytilt) +{ + GdkWindowPrivate *win_priv; + + int x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; + + double device_width, device_height; + double x_offset, y_offset, x_scale, y_scale; + + win_priv = (GdkWindowPrivate *) input_window->window; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = - input_window->root_x; + y_offset = - input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * win_priv->width >= win_priv->height) + { + /* device taller than window */ + x_scale = win_priv->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + win_priv->height)/2; + } + else + { + /* window taller than device */ + y_scale = win_priv->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = - (device_width * x_scale - win_priv->width)/2; + } + } + + if (x) *x = x_offset + x_scale*axis_data[x_axis]; + if (y) *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +/* combine the state of the core device and the device state + into one - for now we do this in a simple-minded manner - + we just take the keyboard portion of the core device and + the button portion (all of?) the device state. + Any button remapping should go on here. */ +static guint +gdk_input_translate_state(guint state, guint device_state) +{ + return device_state | (state & 0xFF); +} + +static gint +gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev) +{ + if ((xevent->type == gdkdev->buttonpress_type) || + (xevent->type == gdkdev->buttonrelease_type)) + { + XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent); + + if (xdbe->type == gdkdev->buttonpress_type) + { + event->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1 << xdbe->button; + } + else + { + event->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~(1 << xdbe->button); + } + event->button.window = input_window->window; + event->button.time = xdbe->time; + event->button.source = gdkdev->info.source; + event->button.deviceid = xdbe->deviceid; + + gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data, + &event->button.x,&event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state); + event->button.button = xdbe->button; + + return TRUE; + } + + if (xevent->type == gdkdev->motionnotify_type) + { + XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent); + + gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data, + &event->motion.x,&event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = input_window->window; + event->motion.time = xdme->time; + event->motion.deviceid = xdme->deviceid; + event->motion.state = gdk_input_translate_state(xdme->state, + xdme->device_state); + event->motion.source = gdkdev->info.source; + event->motion.deviceid = xdme->deviceid; + + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f hint: %s\n", + xdme->window, + xdme->deviceid, + event->motion.x, event->motion.y, + (xevent->xmotion.is_hint) ? "true" : "false"); + + + return TRUE; + } + + if (xevent->type == gdkdev->proximityin_type || + xevent->type == gdkdev->proximityout_type) + { + XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent); + + event->proximity.type = (xevent->type == gdkdev->proximityin_type)? + GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT; + event->proximity.window = input_window->window; + event->proximity.time = xpne->time; + event->proximity.source = gdkdev->info.source; + event->proximity.deviceid = xpne->deviceid; + + return TRUE; + } + + return -1; /* wasn't one of our event types */ +} + +static void +gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + for (i=GDK_AXIS_IGNORE;i<GDK_AXIS_LAST;i++) + { + gdkdev->axis_for_use[i] = -1; + } + + for (i=0;i<gdkdev->info.num_axes;i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static GdkTimeCoord * +gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkTimeCoord *coords; + XDeviceTimeCoord *device_coords; + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + + int mode_return; + int axis_count_return; + int i; + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_val_if_fail (gdkdev != NULL, NULL); + g_return_val_if_fail (gdkdev->xdevice != NULL, NULL); + g_return_val_if_fail (input_window != NULL, NULL); + + device_coords = XGetDeviceMotionEvents (gdk_display, + gdkdev->xdevice, + start, stop, + nevents_return, &mode_return, + &axis_count_return); + + if (device_coords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + + for (i=0; i<*nevents_return; i++) + { + gdk_input_translate_coordinates (gdkdev, input_window, + device_coords[i].data, + &coords[i].x, &coords[i].y, + &coords[i].pressure, + &coords[i].xtilt, &coords[i].ytilt); + } + XFreeDeviceMotionEvents (device_coords); + + return coords; + } + else + return NULL; +} + +static void +gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + XDeviceState *state; + XInputClass *input_class; + gint x_int, y_int; + gint i; + + /* we probably need to get the mask in any case */ + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_if_fail (gdkdev != NULL); + g_return_if_fail (gdkdev->xdevice != NULL); + g_return_if_fail (input_window != NULL); + + state = XQueryDeviceState (gdk_display, gdkdev->xdevice); + input_class = state->data; + for (i=0; i<state->num_classes; i++) + { + switch (input_class->class) + { + case ValuatorClass: + gdk_input_translate_coordinates(gdkdev, input_window, + ((XValuatorState *)input_class)->valuators, + x, y, pressure, + xtilt, ytilt); + + + break; + case ButtonClass: + if (mask) + { + *mask &= ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK); + for (i=0; i < ((XButtonState *)input_class)->num_buttons; i++) + { + if (((XButtonState *)input_class)->buttons[i]) + *mask |= GDK_BUTTON1_MASK << i; + } + } + break; + } + input_class = (XInputClass *)(((char *)input_class)+input_class->length); + } + } +} + +#endif diff --git a/gdk/x11/gdkinput-xfree.c b/gdk/x11/gdkinput-xfree.c new file mode 100644 index 0000000000..f742490088 --- /dev/null +++ b/gdk/x11/gdkinput-xfree.c @@ -0,0 +1,368 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +#ifdef XINPUT_XFREE + +/* forward declarations */ + +static gint gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode); +static void gdk_input_check_proximity(); +static void gdk_input_xfree_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_enable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_disable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_xfree_ungrab_pointer (guint32 time); + +void +gdk_input_init(void) +{ + gdk_input_vtable.set_mode = gdk_input_xfree_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_common_motion_events; + gdk_input_vtable.get_pointer = gdk_input_common_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_xfree_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_xfree_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_xfree_configure_event; + gdk_input_vtable.enter_event = gdk_input_xfree_enter_event; + gdk_input_vtable.other_event = gdk_input_xfree_other_event; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = gdk_input_xfree_enable_window; + gdk_input_vtable.disable_window = gdk_input_xfree_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_common_init(FALSE); +} + +static gint +gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; + +} + +static void +gdk_input_check_proximity() +{ + gint new_proximity = 0; + GList *tmp_list = gdk_input_devices; + + while (tmp_list && !new_proximity) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.mode != GDK_MODE_DISABLED + && gdkdev->info.deviceid != GDK_CORE_POINTER + && gdkdev->xdevice) + { + XDeviceState *state = XQueryDeviceState(GDK_DISPLAY(), + gdkdev->xdevice); + XInputClass *xic; + int i; + + xic = state->data; + for (i=0; i<state->num_classes; i++) + { + if (xic->class == ValuatorClass) + { + XValuatorState *xvs = (XValuatorState *)xic; + if ((xvs->mode & ProximityState) == InProximity) + { + new_proximity = TRUE; + } + break; + } + xic = (XInputClass *)((char *)xic + xic->length); + } + } + tmp_list = tmp_list->next; + } + + gdk_input_ignore_core = new_proximity; +} + +static void +gdk_input_xfree_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_check_proximity(); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static gint +gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + /* FIXME: It would be nice if we could just get rid of the events + entirely, instead of having to ignore them */ + if (gdkdev->info.mode == GDK_MODE_DISABLED || + (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)) + return FALSE; + + if (!gdk_input_ignore_core) + gdk_input_check_proximity(); + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_PROXIMITY_OUT && + gdk_input_ignore_core) + gdk_input_check_proximity(); + + /* Do a passive button grab. We have to be careful not to release + an explicit grab, if any. Doubling the grab should be harmless, + but we check anyways. */ + + /* FIXME, finding the proper events here is going to be SLOW - but + we might have different sets for each window/device combination */ + + if (return_val> 0 && !input_window->grabbed) + { + if (event->type == GDK_BUTTON_PRESS) + { + XEventClass event_classes[6]; + gint num_classes; + + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, event->button.time); + } + else if (event->type == GDK_BUTTON_RELEASE) + XUngrabDevice( GDK_DISPLAY(), gdkdev->xdevice, event->button.time); + } + + return return_val; +} + +static gint +gdk_input_xfree_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + /* FIXME: watchout, gdkdev might be core pointer, never opened */ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + XEventClass event_classes[6]; + gint num_classes; + + tmp_list = gdk_input_windows; + new_window = NULL; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + { + new_window = input_window; + break; + } + + tmp_list = tmp_list->next; + } + + g_return_if_fail (new_window == NULL); + + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + /* FIXME: we should do something on failure */ + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + } + tmp_list = tmp_list->next; + } + + return Success; +} + +static void +gdk_input_xfree_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + XUngrabDevice( gdk_display, gdkdev->xdevice, time); + } + tmp_list = tmp_list->next; + } + } +} + +#endif /* XINPUT_XFREE */ diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c new file mode 100644 index 0000000000..ad4b1fcc93 --- /dev/null +++ b/gdk/x11/gdkinput.c @@ -0,0 +1,324 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "../config.h" +#include "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 id); + + +/* Incorporate the specific routines depending on compilation options */ + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +gchar *gdk_input_gxid_host; +gint gdk_input_gxid_port; +gint gdk_input_ignore_core; + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; + +#include "gdkinputnone.h" +#include "gdkinputcommon.h" +#include "gdkinputxfree.h" +#include "gdkinputgxi.h" + +GList * +gdk_input_list_devices () +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +gint +gdk_input_set_mode (guint32 deviceid, GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode(deviceid,mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes) + gdk_input_vtable.set_axes (deviceid, axes); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + XTimeCoord *xcoords; + GdkTimeCoord *coords; + int i; + + if (deviceid == GDK_CORE_POINTER) + { + xcoords = XGetMotionEvents (gdk_display, + ((GdkWindowPrivate *)window)->xwindow, + start, stop, nevents_return); + if (xcoords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + for (i=0; i<*nevents_return; i++) + { + coords[i].time = xcoords[i].time; + coords[i].x = xcoords[i].x; + coords[i].y = xcoords[i].y; + coords[i].pressure = 0.5; + coords[i].xtilt = 0.0; + coords[i].ytilt = 0.0; + } + + XFree(xcoords); + + return coords; + } + else + return NULL; + } + else + { + if (gdk_input_vtable.motion_events) + { + return gdk_input_vtable.motion_events(window, + deviceid, start, stop, + nevents_return); + } + else + { + *nevents_return = 0; + return NULL; + } + } +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find(GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, gint mask, + GdkExtensionMode mode) +{ + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new(GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->obscuring = NULL; + iw->num_obscuring = 0; + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append(gdk_input_windows,iw); + ((GdkWindowPrivate *)window)->extension_events = mask; + + /* Add enter window events to the event mask */ + /* FIXME, this is not needed for XINPUT_NONE */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove(gdk_input_windows,iw); + g_free(iw); + } + + ((GdkWindowPrivate *)window)->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window(window,gdkdev); + else + gdk_input_disable_window(window,gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove(gdk_input_windows,input_window); + g_free(input_window); +} + +void +gdk_input_exit (void) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED); + + g_free(gdkdev->info.name); +#ifndef XINPUT_NONE + g_free(gdkdev->axes); +#endif + g_free(gdkdev->info.axes); + g_free(gdkdev); + } + } + + g_list_free(gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free(tmp_list->data); + } + g_list_free(gdk_input_windows); +} + +static GdkDevicePrivate * +gdk_input_find_device(guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c new file mode 100644 index 0000000000..d5f85dd1ef --- /dev/null +++ b/gdk/x11/gdkmain-x11.c @@ -0,0 +1,2897 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <ctype.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif /* HAVE_SYS_SELECT_H_ */ + +#define XLIB_ILLEGAL_ACCESS +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xos.h> +#include <X11/Xutil.h> +#include <X11/Xmu/WinUtil.h> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +#ifndef X_GETTIMEOFDAY +#define X_GETTIMEOFDAY(tv) gettimeofday (tv, NULL) +#endif /* X_GETTIMEOFDAY */ + + +#define DOUBLE_CLICK_TIME 250 +#define TRIPLE_CLICK_TIME 500 +#define DOUBLE_CLICK_DIST 5 +#define TRIPLE_CLICK_DIST 5 + + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else +# ifndef _AIX + typedef long fd_mask; +# endif +# if defined(_IBMR2) +# define SELECT_MASK void +# else +# define SELECT_MASK int +# endif +#endif + + +typedef struct _GdkInput GdkInput; +typedef struct _GdkPredicate GdkPredicate; + +struct _GdkInput +{ + gint tag; + gint source; + GdkInputCondition condition; + GdkInputFunction function; + gpointer data; +}; + +struct _GdkPredicate +{ + GdkEventFunc func; + gpointer data; +}; + +/* + * Private function declarations + */ +static gint gdk_event_wait (void); +static gint gdk_event_translate (GdkEvent *event, + XEvent *xevent); +static Bool gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg); +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +static void gdk_dnd_drag_begin (GdkWindow *initial_window); +static void gdk_dnd_drag_enter (Window dest); +static void gdk_dnd_drag_leave (Window dest); +static void gdk_dnd_drag_end (Window dest, + GdkPoint coords); +static GdkAtom gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent); +static void gdk_print_atom (GdkAtom anatom); + +/* + * old junk from offix, we might use it though so leave it + */ +static Window gdk_drop_get_client_window (Display *dpy, + Window win); +static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y); +static void gdk_exit_func (void); +static int gdk_x_error (Display *display, + XErrorEvent *error); +static int gdk_x_io_error (Display *display); +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +static int connection_number = 0; /* The file descriptor number of our + * connection to the X server. This + * is used so that we may determine + * when events are pending by using + * the "select" system call. + */ + +static gint received_destroy_notify = FALSE; /* Did we just receive a destroy notify + * event? If so, we need to actually + * destroy the window which received + * it now. + */ +static GdkWindow *window_to_destroy = NULL; /* If we previously received a destroy + * notify event then this is the window + * which received that event. + */ + +static struct timeval start; /* The time at which the library was + * last initialized. + */ +static struct timeval timer; /* Timeout interval to use in the call + * to "select". This is used in + * conjunction with "timerp" to create + * a maximum time to wait for an event + * to arrive. + */ +static struct timeval *timerp; /* The actual timer passed to "select" + * This may be NULL, in which case + * "select" will block until an event + * arrives. + */ +static guint32 timer_val; /* The timeout length as specified by + * the user in milliseconds. + */ +static GList *inputs; /* A list of the input file descriptors + * that we care about. Each list node + * contains a GdkInput struct that describes + * when we are interested in the specified + * file descriptor. That is, when it is + * available for read, write or has an + * exception pending. + */ +static guint32 button_click_time[2]; /* The last 2 button click times. Used + * to determine if the latest button click + * is part of a double or triple click. + */ +static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. + * Also used to determine if the latest button + * click is part of a double or triple click. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ + +#define OTHER_XEVENT_BUFSIZE 4 +static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */ +static int other_xevent_i = 0; +static GList *putback_events = NULL; + +static gulong base_id; +static gint autorepeat; + + +/* + *-------------------------------------------------------------- + * gdk_init + * + * Initialize the library for use. + * + * Arguments: + * "argc" is the number of arguments. + * "argv" is an array of strings. + * + * Results: + * "argc" and "argv" are modified to reflect any arguments + * which were not handled. (Such arguments should either + * be handled by the application or dismissed). + * + * Side effects: + * The library is initialized. + * + *-------------------------------------------------------------- + */ + +void +gdk_init (int *argc, + char ***argv) +{ + XKeyboardState keyboard_state; + int synchronize; + int i, j, k; + XClassHint *class_hint; + int argc_orig = *argc; + char **argv_orig; + + argv_orig = malloc ((argc_orig + 1) * sizeof (char*)); + for (i = 0; i < argc_orig; i++) + argv_orig[i] = g_strdup ((*argv)[i]); + argv_orig[argc_orig] = NULL; + + X_GETTIMEOFDAY (&start); + + signal (SIGHUP, gdk_signal); + signal (SIGINT, gdk_signal); + signal (SIGQUIT, gdk_signal); + signal (SIGBUS, gdk_signal); + signal (SIGSEGV, gdk_signal); + signal (SIGPIPE, gdk_signal); + signal (SIGTERM, gdk_signal); + + gdk_display_name = NULL; + + XSetErrorHandler (gdk_x_error); + XSetIOErrorHandler (gdk_x_io_error); + + synchronize = FALSE; + + if (argc && argv) + { + if (*argc > 0) + gdk_progname = (*argv)[0]; + + for (i = 1; i < *argc;) + { + if (strcmp ("--display", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + + if ((i + 1) < *argc) + { + gdk_display_name = g_strdup ((*argv)[i + 1]); + (*argv)[i + 1] = NULL; + i += 1; + } + } + else if (strcmp ("--sync", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + synchronize = TRUE; + } + else if (strcmp ("--show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = TRUE; + } + else if (strcmp ("--no-show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = FALSE; + } + else if (strcmp ("--no-xshm", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_use_xshm = FALSE; + } + else if (strcmp ("--debug-level", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_debug_level = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("-name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progname = (*argv)[i]; + (*argv)[i] = NULL; + } + } + else if (strcmp ("-class", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progclass = (*argv)[i]; + (*argv)[i] = NULL; + } + } +#ifdef XINPUT_GXI + else if (strcmp ("--gxid_host", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_host = ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("--gxid_port", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_port = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } +#endif + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + gdk_progname = "<unknown>"; + } + + gdk_display = XOpenDisplay (gdk_display_name); + if (!gdk_display) + g_error ("cannot open display: %s", XDisplayName (gdk_display_name)); + + /* This is really crappy. We have to look into the display structure + * to find the base resource id. This is only needed for recording + * and playback of events. + */ + /* base_id = RESOURCE_BASE; */ + base_id = 0; + if (gdk_show_events) + g_print ("base id: %lu\n", base_id); + + connection_number = ConnectionNumber (gdk_display); + if (gdk_debug_level >= 1) + g_print ("connection number: %d\n", connection_number); + + if (synchronize) + XSynchronize (gdk_display, True); + + gdk_screen = DefaultScreen (gdk_display); + gdk_root_window = RootWindow (gdk_display, gdk_screen); + + gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window, + 10, 10, 10, 10, 0, 0 , 0); + class_hint = XAllocClassHint(); + class_hint->res_name = gdk_progname; + class_hint->res_class = gdk_progclass; + XSetClassHint(gdk_display, gdk_leader_window, class_hint); + XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig); + XFree (class_hint); + + gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True); + gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True); + gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True); + gdk_wm_window_protocols[0] = gdk_wm_delete_window; + gdk_wm_window_protocols[1] = gdk_wm_take_focus; + gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False); + + gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE); + gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE); + gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE); + gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE); + gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE); + gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity); + gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart); + + XGetKeyboardControl (gdk_display, &keyboard_state); + autorepeat = keyboard_state.global_auto_repeat; + + timer.tv_sec = 0; + timer.tv_usec = 0; + timerp = NULL; + + button_click_time[0] = 0; + button_click_time[1] = 0; + button_window[0] = NULL; + button_window[1] = NULL; + button_number[0] = -1; + button_number[1] = -1; + + if (ATEXIT (gdk_exit_func)) + g_warning ("unable to register exit function"); + + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + + initialized = 1; +} + +/* + *-------------------------------------------------------------- + * gdk_exit + * + * Restores the library to an un-itialized state and exits + * the program using the "exit" system call. + * + * Arguments: + * "errorcode" is the error value to pass to "exit". + * + * Results: + * Allocated structures are freed and the program exits + * cleanly. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_exit (int errorcode) +{ + /* de-initialisation is done by the gdk_exit_funct(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale () +{ + if (!setlocale (LC_ALL,"")) + g_print ("locale not supported by C library\n"); + + if (!XSupportsLocale ()) + { + g_print ("locale not supported by Xlib, locale set to C\n"); + setlocale (LC_ALL, "C"); + } + + if (!XSetLocaleModifiers ("")) + { + g_print ("can not set locale modifiers\n"); + } + + return setlocale (LC_ALL,NULL); +} + +/* + *-------------------------------------------------------------- + * gdk_events_pending + * + * Returns the number of events pending on the queue. + * These events have already been read from the server + * connection. + * + * Arguments: + * + * Results: + * Returns the number of events on XLib's event queue. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_events_pending () +{ + return XPending (gdk_display); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * "event" is used to hold the received event. + * If "event" is NULL an event is received as normal + * however it is not placed in "event" (and thus no + * error occurs). + * + * Results: + * Returns TRUE if an event was received that we care about + * and FALSE otherwise. This function will also return + * before an event is received if the timeout interval + * runs out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data) +{ + GdkEvent *temp_event; + GdkPredicate event_pred; + GList *temp_list; + XEvent xevent; + + /* If the last event we received was a destroy notify + * event then we will actually destroy the "gdk" data + * structures now. We don't want to destroy them at the + * time of receiving the event since the main program + * may try to access them and may need to destroy user + * data that has been attached to the window + */ + if (received_destroy_notify) + { + if (gdk_show_events) + g_print ("destroying window:\twindow: %ld\n", + ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id); + + gdk_window_real_destroy (window_to_destroy); + received_destroy_notify = FALSE; + window_to_destroy = NULL; + } + + /* Initially we haven't received an event and want to + * return FALSE. If "event" is non-NULL, then initialize + * it to the nothing event. + */ + if (event) + { + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + } + + if (pred) + { + temp_list = putback_events; + while (temp_list) + { + temp_event = temp_list->data; + + if ((* pred) (temp_event, data)) + { + if (event) + *event = *temp_event; + putback_events = g_list_remove_link (putback_events, temp_list); + g_list_free (temp_list); + return TRUE; + } + + temp_list = temp_list->next; + } + + event_pred.func = pred; + event_pred.data = data; + + if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred)) + if (event) + return gdk_event_translate (event, &xevent); + } + else + { + if (putback_events) + { + temp_event = putback_events->data; + *event = *temp_event; + + temp_list = putback_events; + putback_events = putback_events->next; + if (putback_events) + putback_events->prev = NULL; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + g_free (temp_event); + + return TRUE; + } + + /* Wait for an event to occur or the timeout to elapse. + * If an event occurs "gdk_event_wait" will return TRUE. + * If the timeout elapses "gdk_event_wait" will return + * FALSE. + */ + if (gdk_event_wait ()) + { + /* If we get here we can rest assurred that an event + * has occurred. Read it. + */ + XNextEvent (gdk_display, &xevent); + + event->any.send_event = xevent.xany.send_event; + + /* If "event" non-NULL. + */ + if (event) + return gdk_event_translate (event, &xevent); + } + } + + return FALSE; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_if_fail (event != NULL); + + new_event = g_new (GdkEvent, 1); + *new_event = *event; + + putback_events = g_list_prepend (putback_events, new_event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_copy + * + * Copy a event structure into new storage. + * + * Arguments: + * "event" is the event struct to copy. + * + * Results: + * A new event structure. Free it with gdk_event_free. + * + * Side effects: + * The reference count of the window in the event is increased. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *event_chunk; + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_val_if_fail (event != NULL, NULL); + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEvent), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEvent, event_chunk); + *new_event = *event; + gdk_window_ref (new_event->any.window); + return new_event; +} + +/* + *-------------------------------------------------------------- + * gdk_event_free + * + * Free a event structure obtained from gdk_event_copy. Do not use + * with other event structures. + * + * Arguments: + * "event" is the event struct to free. + * + * Results: + * + * Side effects: + * The reference count of the window in the event is decreased and + * might be freed, too. + * + *-------------------------------------------------------------- */ + +void +gdk_event_free (GdkEvent *event) +{ + g_assert (event_chunk != NULL); + g_return_if_fail (event != NULL); + + gdk_window_unref (event->any.window); + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_set_debug_level + * + * Sets the debugging level. + * + * Arguments: + * "level" is the new debugging level. + * + * Results: + * + * Side effects: + * Other function calls to "gdk" use the debugging + * level to determine what kind of debugging information + * to print out. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_debug_level (int level) +{ + gdk_debug_level = level; +} + +/* + *-------------------------------------------------------------- + * gdk_set_show_events + * + * Turns on/off the showing of events. + * + * Arguments: + * "show_events" is a boolean describing whether or + * not to show the events gdk receives. + * + * Results: + * + * Side effects: + * When "show_events" is TRUE, calls to "gdk_event_get" + * will output debugging informatin regarding the event + * received to stdout. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_show_events (int show_events) +{ + gdk_show_events = show_events; +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + gdk_use_xshm = use_xshm; +} + +gint +gdk_get_debug_level () +{ + return gdk_debug_level; +} + +gint +gdk_get_show_events () +{ + return gdk_show_events; +} + +gint +gdk_get_use_xshm () +{ + return gdk_use_xshm; +} + +/* + *-------------------------------------------------------------- + * gdk_time_get + * + * Get the number of milliseconds since the library was + * initialized. + * + * Arguments: + * + * Results: + * The time since the library was initialized is returned. + * This time value is accurate to milliseconds even though + * a more accurate time down to the microsecond could be + * returned. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_time_get () +{ + struct timeval end; + struct timeval elapsed; + guint32 milliseconds; + + X_GETTIMEOFDAY (&end); + + if (start.tv_usec > end.tv_usec) + { + end.tv_usec += 1000000; + end.tv_sec--; + } + elapsed.tv_sec = end.tv_sec - start.tv_sec; + elapsed.tv_usec = end.tv_usec - start.tv_usec; + + milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000); + + return milliseconds; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_get + * + * Returns the current timer. + * + * Arguments: + * + * Results: + * Returns the current timer interval. This interval is + * in units of milliseconds. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_timer_get () +{ + return timer_val; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_set + * + * Sets the timer interval. + * + * Arguments: + * "milliseconds" is the new value for the timer. + * + * Results: + * + * Side effects: + * Calls to "gdk_event_get" will last for a maximum + * of time of "milliseconds". However, a value of 0 + * milliseconds will cause "gdk_event_get" to block + * indefinately until an event is received. + * + *-------------------------------------------------------------- + */ + +void +gdk_timer_set (guint32 milliseconds) +{ + timer_val = milliseconds; + timer.tv_sec = milliseconds / 1000; + timer.tv_usec = (milliseconds % 1000) * 1000; + +} + +void +gdk_timer_enable () +{ + timerp = &timer; +} + +void +gdk_timer_disable () +{ + timerp = NULL; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + static gint next_tag = 1; + GList *list; + GdkInput *input; + gint tag; + + tag = 0; + list = inputs; + + while (list) + { + input = list->data; + list = list->next; + + if ((input->source == source) && (input->condition == condition)) + { + input->function = function; + input->data = data; + tag = input->tag; + } + } + + if (!tag) + { + input = g_new (GdkInput, 1); + input->tag = next_tag++; + input->source = source; + input->condition = condition; + input->function = function; + input->data = data; + tag = input->tag; + + inputs = g_list_prepend (inputs, input); + } + + return tag; +} + +void +gdk_input_remove (gint tag) +{ + GList *list; + GList *temp_list; + GdkInput *input; + + list = inputs; + while (list) + { + input = list->data; + + if (input->tag == tag) + { + temp_list = list; + + if (list->next) + list->next->prev = list->prev; + if (list->prev) + list->prev->next = list->next; + if (inputs == list) + inputs = list->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + + g_free (temp_list->data); + g_list_free (temp_list); + break; + } + + list = list->next; + } +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + gint return_val; + GdkWindowPrivate *window_private; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + guint xevent_mask; + Window xwindow; + Window xconfine_to; + Cursor xcursor; + int i; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to) + xconfine_to = None; + else + xconfine_to = confine_to_private->xwindow; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + + xevent_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + if (((GdkWindowPrivate *)window)->extension_events && + gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success;; + + if (return_val == Success) + return_val = XGrabPointer (window_private->xdisplay, + xwindow, + owner_events, + xevent_mask, + GrabModeAsync, GrabModeAsync, + xconfine_to, + xcursor, + time); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); + + XUngrabPointer (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + GdkWindowPrivate *window_private; + Window xwindow; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + xwindow = window_private->xwindow; + + return XGrabKeyboard (window_private->xdisplay, + xwindow, + owner_events, + GrabModeAsync, GrabModeAsync, + time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + XUngrabKeyboard (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width () +{ + gint return_val; + + return_val = DisplayWidth (gdk_display, gdk_screen); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height () +{ + gint return_val; + + return_val = DisplayHeight (gdk_display, gdk_screen); + + return return_val; +} + +void +gdk_key_repeat_disable () +{ + XAutoRepeatOff (gdk_display); +} + +void +gdk_key_repeat_restore () +{ + if (autorepeat) + XAutoRepeatOn (gdk_display); + else + XAutoRepeatOff (gdk_display); +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void gdk_flush () +{ + XSync (gdk_display, False); +} + + +void +gdk_beep () +{ + XBell(gdk_display, 100); +} + + +/* + *-------------------------------------------------------------- + * gdk_event_wait + * + * Waits until an event occurs or the timer runs out. + * + * Arguments: + * + * Results: + * Returns TRUE if an event is ready to be read and FALSE + * if the timer ran out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static gint +gdk_event_wait () +{ + GList *list; + GdkInput *input; + GdkInputCondition condition; + SELECT_MASK readfds; + SELECT_MASK writefds; + SELECT_MASK exceptfds; + int max_input; + int nfd; + + /* If there are no events pending we will wait for an event. + * The time we wait is dependant on the "timer". If no timer + * has been specified then we'll block until an event arrives. + * If a timer has been specified we'll block until an event + * arrives or the timer expires. (This is all done using the + * "select" system call). + */ + + if (XPending (gdk_display) == 0) + { + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_ZERO (&exceptfds); + + FD_SET (connection_number, &readfds); + max_input = connection_number; + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + if (input->condition & GDK_INPUT_READ) + FD_SET (input->source, &readfds); + if (input->condition & GDK_INPUT_WRITE) + FD_SET (input->source, &writefds); + if (input->condition & GDK_INPUT_EXCEPTION) + FD_SET (input->source, &exceptfds); + + max_input = MAX (max_input, input->source); + } + + nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp); + + timerp = NULL; + timer_val = 0; + + if (nfd > 0) + { + if (FD_ISSET (connection_number, &readfds)) + { + if (XPending (gdk_display) == 0) + { + if (nfd == 1) + { + XNoOp (gdk_display); + XFlush (gdk_display); + } + return FALSE; + } + else + return TRUE; + } + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + condition = 0; + if (FD_ISSET (input->source, &readfds)) + condition |= GDK_INPUT_READ; + if (FD_ISSET (input->source, &writefds)) + condition |= GDK_INPUT_WRITE; + if (FD_ISSET (input->source, &exceptfds)) + condition |= GDK_INPUT_EXCEPTION; + + if (condition && input->function) + (* input->function) (input->data, input->source, condition); + } + } + } + else + return TRUE; + + return FALSE; +} + +static gint +gdk_event_translate (GdkEvent *event, + XEvent *xevent) +{ + + GdkWindow *window; + GdkWindowPrivate *window_private; + XComposeStatus compose; + int charcount; + char buf[16]; + gint return_val; + + /* Are static variables used for this purpose thread-safe? */ + static GdkPoint dnd_drag_start = {0,0}, + dnd_drag_oldpos = {0,0}; + static GdkRectangle dnd_drag_dropzone = {0,0,0,0}; + static gint dnd_drag_perhaps = 0; + static GdkWindowPrivate *real_sw = NULL; + static Window dnd_drag_curwin = None, dnd_drag_target = None; + + return_val = FALSE; + + /* Find the GdkWindow that this event occurred in. + * All events occur in some GdkWindow (otherwise, why + * would we be receiving them). It really is an error + * to receive an event for which we cannot find the + * corresponding GdkWindow. We handle events with window=None + * specially - they are generated by XFree86's XInput under + * some circumstances. + */ + + if ((xevent->xany.window == None) && + gdk_input_vtable.window_none_event) + { + return_val = gdk_input_vtable.window_none_event (event,xevent); + + if (return_val >= 0) /* was handled */ + return return_val; + else + return_val = FALSE; + } + + window = gdk_window_lookup (xevent->xany.window); + window_private = (GdkWindowPrivate *) window; + + /* We do a "manual" conversion of the XEvent to a + * GdkEvent. The structures are mostly the same so + * the conversion is fairly straightforward. We also + * optionally print debugging info regarding events + * received. + */ + /* Addendum: + * During drag & drop you get events where the pointer is + * in other windows. Need to just do finer-grained checking + */ + switch (xevent->type) + { + case KeyPress: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key press:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_PRESS; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case KeyRelease: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key release:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_RELEASE; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case ButtonPress: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } + if(window_private + && window_private->dnd_drag_enabled + && !dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + dnd_drag_perhaps = 1; + dnd_drag_start.x = xevent->xbutton.x_root; + dnd_drag_start.y = xevent->xbutton.y_root; + real_sw = window_private; + + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; + + { + /* Set motion mask for first DnD'd window, since it + will be the one that is actually dragged */ + XWindowAttributes dnd_winattr; + XSetWindowAttributes dnd_setwinattr; + Status rv; + + /* We need to get motion events while the button is down, so + we can know whether to really start dragging or not... */ + XGetWindowAttributes(gdk_display, (Window)window_private->xwindow, + &dnd_winattr); + + window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; + dnd_setwinattr.event_mask = + window_private->dnd_drag_eventmask = ButtonMotionMask; + XChangeWindowAttributes(gdk_display, window_private->xwindow, + CWEventMask, &dnd_setwinattr); + } + } + return_val = window_private?(!window_private->destroyed):FALSE; + break; + + case ButtonRelease: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if(dnd_drag_perhaps) + { + if(gdk_dnd.drag_really) + { + GdkPoint foo = {xevent->xbutton.x_root, + xevent->xbutton.y_root}; + XUngrabPointer(gdk_display, CurrentTime); + + if(dnd_drag_target != None) + gdk_dnd_drag_end(dnd_drag_target, foo); + gdk_dnd.drag_really = 0; + + if(gdk_dnd.drag_numwindows) + { + XSetWindowAttributes attrs; + /* Reset event mask to pre-drag value, assuming event_mask + doesn't change during drag */ + attrs.event_mask = real_sw->dnd_drag_savedeventmask; + XChangeWindowAttributes(gdk_display, real_sw->xwindow, + CWEventMask, &attrs); + } + + gdk_dnd.drag_numwindows = 0; + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + + real_sw = NULL; + } + + dnd_drag_perhaps = 0; + dnd_drag_start.x = dnd_drag_start.y = 0; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_curwin = None; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case MotionNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n", + xevent->xmotion.window - base_id, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false", + dnd_drag_perhaps, gdk_dnd.drag_really); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + event->motion.time = xevent->xmotion.time; + event->motion.x = xevent->xmotion.x; + event->motion.y = xevent->xmotion.y; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = (GdkModifierType) xevent->xmotion.state; + event->motion.is_hint = xevent->xmotion.is_hint; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + +#define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \ + && cy >= dnd_drag_dropzone.y \ + && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \ + && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height)) + + if(dnd_drag_perhaps && gdk_dnd.drag_really) + { + /* First, we have to find what window the motion was in... */ + /* XXX there has to be a better way to do this, perhaps with + XTranslateCoordinates or XQueryTree - I don't know how, + and this sort of works */ + Window curwin, childwin = gdk_root_window, rootwinret; + int x, y; + unsigned int mask; + while(childwin != None) + { + curwin = childwin; + XQueryPointer(gdk_display, curwin, &rootwinret, &childwin, + &x, &y, &x, &y, &mask); + } + if(curwin != dnd_drag_curwin) + { + /* We have left one window and entered another + (do leave & enter bits) */ + if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None) + gdk_dnd_drag_leave(dnd_drag_curwin); + dnd_drag_curwin = curwin; + gdk_dnd_drag_enter(dnd_drag_curwin); + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_target = None; + XChangeActivePointerGrab(gdk_display, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragdefault, + CurrentTime); + } + else if(dnd_drag_dropzone.width > 0 + && dnd_drag_dropzone.height > 0) + { + /* Handle all that dropzone stuff - thanks John ;-) */ + if(dnd_drag_target != None + && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y) + && !IS_IN_ZONE(xevent->xmotion.x_root, + xevent->xmotion.y_root)) + { + /* We were in the drop zone and moved out */ + dnd_drag_target = None; + gdk_dnd_drag_leave(curwin); + } + else + { + /* We were outside drop zone but in the window + - have to send enter events */ + gdk_dnd_drag_enter(curwin); + dnd_drag_curwin = curwin; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_target = None; + } + } else + dnd_drag_curwin = None; + return_val = FALSE; + } + else + return_val = window?(!window_private->destroyed):FALSE; + break; + + case EnterNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow - base_id); + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&xevent->xcrossing, window); + + event->crossing.type = GDK_ENTER_NOTIFY; + event->crossing.window = window; + + /* If the subwindow field of the XEvent is non-NULL, then + * lookup the corresponding GdkWindow. + */ + if (xevent->xcrossing.subwindow != None) + event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + if(dnd_drag_perhaps + && gdk_dnd.drag_really + && xevent->xcrossing.window == real_sw->xwindow) + { + gdk_dnd.drag_really = 0; + XUngrabPointer(gdk_display, CurrentTime); + } + + return_val = (window ? !window_private->destroyed : FALSE); + break; + + case LeaveNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + if(dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + gdk_dnd_drag_addwindow((GdkWindow *) real_sw); + gdk_dnd_drag_begin((GdkWindow *) real_sw); + XGrabPointer(gdk_display, real_sw->xwindow, False, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + GrabModeAsync, GrabModeAsync, gdk_root_window, + gdk_dnd.gdk_cursor_dragdefault, CurrentTime); + gdk_dnd.drag_really = 1; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case FocusIn: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus in:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = TRUE; + + return_val = !window_private->destroyed; + break; + + case FocusOut: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus out:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = FALSE; + + return_val = !window_private->destroyed; + break; + + case KeymapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("keymap notify\n"); + + /* Not currently handled */ + break; + + case Expose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n", + xevent->xexpose.window - base_id, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xexpose.x; + event->expose.area.y = xevent->xexpose.y; + event->expose.area.width = xevent->xexpose.width; + event->expose.area.height = xevent->xexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case GraphicsExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("graphics expose:\tdrawable: %ld\n", + xevent->xgraphicsexpose.drawable - base_id); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xgraphicsexpose.x; + event->expose.area.y = xevent->xgraphicsexpose.y; + event->expose.area.width = xevent->xgraphicsexpose.width; + event->expose.area.height = xevent->xgraphicsexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case NoExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("no expose:\t\tdrawable: %ld\n", + xevent->xnoexpose.drawable - base_id); + + /* Not currently handled */ + break; + + case VisibilityNotify: + /* Print debugging info. + */ + if (gdk_show_events) + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + g_print ("visibility notify:\twindow: %ld none\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityPartiallyObscured: + g_print ("visibility notify:\twindow: %ld partial\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityUnobscured: + g_print ("visibility notify:\twindow: %ld full\n", + xevent->xvisibility.window - base_id); + break; + } + + /* Not currently handled */ + break; + + case CreateNotify: + /* Not currently handled */ + break; + + case DestroyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("destroy notify:\twindow: %ld\n", + xevent->xdestroywindow.window - base_id); + + event->any.type = GDK_DESTROY; + event->any.window = window; + + /* Remeber which window received the destroy notify + * event so that we can destroy our associated + * data structures the next time the user asks + * us for an event. + */ + received_destroy_notify = TRUE; + window_to_destroy = window; + + return_val = !window_private->destroyed; + break; + + case UnmapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("unmap notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case MapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("map notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case ReparentNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("reparent notify:\twindow: %ld\n", + xevent->xreparent.window - base_id); + + /* Not currently handled */ + break; + + case ConfigureNotify: + /* Print debugging info. + */ + while ((XPending(gdk_display) > 0) && + XCheckTypedWindowEvent(gdk_display, xevent->xany.window, + ConfigureNotify, xevent)) + /*XSync(gdk_display, 0)*/; + + if (gdk_show_events) + g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d\n", + xevent->xconfigure.window - base_id, + xevent->xconfigure.x, xevent->xconfigure.y, + xevent->xconfigure.width, xevent->xconfigure.height); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&xevent->xconfigure, window); + + if ((window_private->window_type != GDK_WINDOW_CHILD) && + ((window_private->width != xevent->xconfigure.width) || + (window_private->height != xevent->xconfigure.height))) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = xevent->xconfigure.x; + event->configure.y = xevent->xconfigure.y; + event->configure.width = xevent->xconfigure.width; + event->configure.height = xevent->xconfigure.height; + + window_private->x = xevent->xconfigure.x; + window_private->y = xevent->xconfigure.y; + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + } + break; + + case PropertyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("property notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = xevent->xproperty.atom; + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + + return_val = !window_private->destroyed; + break; + + case SelectionClear: + if (gdk_show_events) + g_print ("selection clear:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->xselectionclear.selection; + event->selection.time = xevent->xselectionclear.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionRequest: + if (gdk_show_events) + g_print ("selection request:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = xevent->xselectionrequest.selection; + event->selection.target = xevent->xselectionrequest.target; + event->selection.property = xevent->xselectionrequest.property; + event->selection.requestor = xevent->xselectionrequest.requestor; + event->selection.time = xevent->xselectionrequest.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionNotify: + if (gdk_show_events) + g_print ("selection notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->xselection.selection; + event->selection.target = xevent->xselection.target; + event->selection.property = xevent->xselection.property; + event->selection.time = xevent->xselection.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case ColormapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("colormap notify:\twindow: %ld\n", + xevent->xcolormap.window - base_id); + + /* Not currently handled */ + break; + + case ClientMessage: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("client message:\twindow: %ld\n", + xevent->xclient.window - base_id); + + /* Client messages are the means of the window manager + * communicating with a program. We'll first check to + * see if this is really the window manager talking + * to us. + */ + if (xevent->xclient.message_type == gdk_wm_protocols) + { + if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) + { + /* The delete window request specifies a window + * to delete. We don't actually destroy the + * window because "it is only a request". (The + * window might contain vital data that the + * program does not want destroyed). Instead + * the event is passed along to the program, + * which should then destroy the window. + */ + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("delete window:\t\twindow: %ld\n", + xevent->xclient.window - base_id); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !window_private->destroyed; + } + else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) + { + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter) + { + Atom reptype = 0; + + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + if (gdk_show_events) + g_print ("GDK_DROP_ENTER\n"); + return_val = FALSE; + + /* Now figure out if we really want this drop... + * If someone is trying funky clipboard stuff, ignore + */ + if (window_private + && window_private->dnd_drop_enabled + && event->dropenter.u.flags.sendreply + && (reptype = gdk_dnd_check_types (window, xevent))) + { + XEvent replyev; + + replyev.xclient.type = ClientMessage; + replyev.xclient.window = xevent->xclient.data.l[0]; + replyev.xclient.format = 32; + replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest; + replyev.xclient.data.l[0] = window_private->xwindow; + + event->dragrequest.u.allflags = 0; + event->dragrequest.u.flags.protocol_version = + DND_PROTOCOL_VERSION; + event->dragrequest.u.flags.willaccept = 1; + event->dragrequest.u.flags.delete_data = + (window_private->dnd_drop_destructive_op) ? 1 : 0; + + replyev.xclient.data.l[1] = event->dragrequest.u.allflags; + replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0; + replyev.xclient.data.l[4] = reptype; + + XSendEvent (gdk_display, replyev.xclient.window, + False, NoEventMask, &replyev); + + event->any.type = GDK_DROP_ENTER; + event->dropenter.requestor = replyev.xclient.window; + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave) + { + if (gdk_show_events) + g_print ("GDK_DROP_LEAVE\n"); + if (window_private && window_private->dnd_drop_enabled) + { + event->dropleave.type = GDK_DROP_LEAVE; + event->dropleave.window = window; + event->dropleave.requestor = xevent->xclient.data.l[0]; + event->dropleave.u.allflags = xevent->xclient.data.l[1]; + return_val = TRUE; + } + else + return_val = FALSE; + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest) + { + /* + * make sure to only handle requests from the window the cursor is + * over + */ + if (gdk_show_events) + g_print ("GDK_DRAG_REQUEST\n"); + event->dragrequest.u.allflags = xevent->xclient.data.l[1]; + return_val = FALSE; + + if (window && gdk_dnd.drag_really && + xevent->xclient.data.l[0] == dnd_drag_curwin && + event->dragrequest.u.flags.sendreply == 0) + { + /* Got request - do we need to ask user? */ + if (!event->dragrequest.u.flags.willaccept + && event->dragrequest.u.flags.senddata) + { + /* Yes we do :) */ + event->dragrequest.type = GDK_DRAG_REQUEST; + event->dragrequest.window = window; + event->dragrequest.requestor = xevent->xclient.data.l[0]; + event->dragrequest.isdrop = 0; + event->dragrequest.drop_coords.x = + event->dragrequest.drop_coords.y = 0; + return_val = TRUE; + } + else if (event->dragrequest.u.flags.willaccept) + { + window_private->dnd_drag_destructive_op = + event->dragrequest.u.flags.delete_data; + window_private->dnd_drag_accepted = 1; + window_private->dnd_drag_data_type = + xevent->xclient.data.l[4]; + + dnd_drag_target = dnd_drag_curwin; + XChangeActivePointerGrab (gdk_display, + ButtonMotionMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragok, + CurrentTime); + } + dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535; + dnd_drag_dropzone.y = + (xevent->xclient.data.l[2] >> 16) & 65535; + dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535; + dnd_drag_dropzone.height = + (xevent->xclient.data.l[3] >> 16) & 65535; + } + } + else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable) + { + gint tmp_int; Atom tmp_atom; + gulong tmp_long; + guchar *tmp_charptr; + gpointer tmp_ptr; + + if(gdk_show_events) + g_print("GDK_DROP_DATA_AVAIL\n"); + event->dropdataavailable.u.allflags = xevent->xclient.data.l[1]; + if(window + /* No preview of data ATM */ + && event->dropdataavailable.u.flags.isdrop) + { + event->dropdataavailable.type = GDK_DROP_DATA_AVAIL; + event->dropdataavailable.window = window; + event->dropdataavailable.requestor = xevent->xclient.data.l[0]; + event->dropdataavailable.data_type = + gdk_atom_name(xevent->xclient.data.l[2]); + if(XGetWindowProperty (gdk_display, + event->dropdataavailable.requestor, + xevent->xclient.data.l[2], + 0, LONG_MAX - 1, + False, XA_PRIMARY, &tmp_atom, + &tmp_int, + &event->dropdataavailable.data_numbytes, + &tmp_long, + &tmp_charptr) + != Success) + { + g_warning("XGetWindowProperty on %#x may have failed\n", + event->dropdataavailable.requestor); + event->dropdataavailable.data = NULL; + } + else + { + g_print("XGetWindowProperty got us %d bytes\n", + event->dropdataavailable.data_numbytes); + event->dropdataavailable.data = + g_malloc(event->dropdataavailable.data_numbytes); + memcpy(event->dropdataavailable.data, + tmp_charptr, event->dropdataavailable.data_numbytes); + XFree(tmp_charptr); + return_val = TRUE; + } + return_val = TRUE; + } + } else { + /* Send unknown ClientMessage's on to Gtk for it to use */ + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->xclient.message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + return_val = TRUE; + } + return_val = return_val && !window_private->destroyed; + break; + + case MappingNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("mapping notify\n"); + + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&xevent->xmapping); + break; + + default: + /* something else - (e.g., a Xinput event) */ + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.other_event) + return_val = gdk_input_vtable.other_event(event, xevent, window); + + if (return_val < 0) /* not an XInput event, convert */ + { + event->other.type = GDK_OTHER_EVENT; + event->other.window = window; + event->other.xevent = &other_xevent[other_xevent_i]; + memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent)); + other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE; + return_val = TRUE; + } + + return_val = return_val && !window_private->destroyed; + break; + } + + return return_val; +} + +static Bool +gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg) +{ + GdkEvent event; + GdkPredicate *pred; + + if (gdk_event_translate (&event, xevent)) + { + pred = (GdkPredicate*) arg; + return (* pred->func) (&event, pred->data); + } + + return FALSE; +} + +static void +gdk_synthesize_click (GdkEvent *event, + gint nclicks) +{ + GdkEvent temp_event; + + g_return_if_fail (event != NULL); + + temp_event = *event; + temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; + + gdk_event_put (&temp_event); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func () +{ + if (initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + + XCloseDisplay (gdk_display); + initialized = 0; + } +} + +/* + *-------------------------------------------------------------- + * gdk_x_error + * + * The X error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * "error" is the XErrorEvent that we are handling. + * + * Results: + * Either we were expecting some sort of error to occur, + * in which case we set the "gdk_error_code" flag, or this + * error was unexpected, in which case we will print an + * error message and exit. (Since trying to continue will + * most likely simply lead to more errors). + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_error (Display *display, + XErrorEvent *error) +{ + char buf[64]; + + if (gdk_error_warnings) + { + XGetErrorText (display, error->error_code, buf, 63); + g_error ("%s", buf); + } + + gdk_error_code = -1; + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_x_io_error + * + * The X I/O error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * + * Results: + * An X I/O error basically means we lost our connection + * to the X server. There is not much we can do to + * continue, so simply print an error message and exit. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_io_error (Display *display) +{ + g_error ("an x io error occurred"); + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_signal + * + * The signal handler. + * + * Arguments: + * "sig_num" is the number of the signal we received. + * + * Results: + * The signals we catch are all fatal. So we simply build + * up a nice little error message and print it and exit. + * If in the process of doing so another signal is received + * we notice that we are already exiting and simply kill + * our process. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static RETSIGTYPE +gdk_signal (int sig_num) +{ + static int caught_fatal_sig = 0; + char *sig; + + if (caught_fatal_sig) + kill (getpid (), sig_num); + caught_fatal_sig = 1; + + switch (sig_num) + { + case SIGHUP: + sig = "sighup"; + break; + case SIGINT: + sig = "sigint"; + break; + case SIGQUIT: + sig = "sigquit"; + break; + case SIGBUS: + sig = "sigbus"; + break; + case SIGSEGV: + sig = "sigsegv"; + break; + case SIGPIPE: + sig = "sigpipe"; + break; + case SIGTERM: + sig = "sigterm"; + break; + default: + sig = "unknown signal"; + break; + } + + g_print ("\n** ERROR **: %s caught\n", sig); + gdk_exit (1); +} + +static void +gdk_dnd_drag_begin (GdkWindow *initial_window) +{ + GdkEventDragBegin tev; + tev.type = GDK_DRAG_BEGIN; + tev.window = initial_window; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + + gdk_event_put ((GdkEvent *) &tev); +} + +static void +gdk_dnd_drag_enter (Window dest) +{ + XEvent sev; + GdkEventDropEnter tev; + int i; + GdkWindowPrivate *wp; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeEnter; + sev.xclient.window = dest; + + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.u.flags.sendreply = 1; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_data_numtypesavail) + { + sev.xclient.data.l[0] = wp->xwindow; + tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0; + sev.xclient.data.l[1] = tev.u.allflags; + sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0]; + if (wp->dnd_drag_data_numtypesavail > 1) + { + sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1]; + if (wp->dnd_drag_data_numtypesavail > 2) + { + sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2]; + } + else + sev.xclient.data.l[4] = None; + } + else + sev.xclient.data.l[3] = sev.xclient.data.l[4] = None; + XSendEvent (gdk_display, dest, False, NoEventMask, &sev); + } + + } +} + +static void +gdk_dnd_drag_leave (Window dest) +{ + XEvent sev; + GdkEventDropLeave tev; + int i; + GdkWindowPrivate *wp; + + tev.u.allflags = 0; + + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + sev.xclient.type = ClientMessage; + sev.xclient.window = dest; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeLeave; + sev.xclient.data.l[1] = tev.u.allflags; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + sev.xclient.data.l[0] = wp->xwindow; + XSendEvent(gdk_display, dest, False, NoEventMask, &sev); + wp->dnd_drag_accepted = 0; + } +} + +/* + * when a drop occurs, we go through the list of windows being dragged and + * tell them that it has occurred, so that they can set things up and reply + * to 'dest' window + */ +static void +gdk_dnd_drag_end (Window dest, + GdkPoint coords) +{ + GdkWindowPrivate *wp; + GdkEventDragRequest tev; + gchar *tmp_cptr; + int i; + + tev.type = GDK_DRAG_REQUEST; + tev.drop_coords = coords; + tev.requestor = dest; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.isdrop = 1; + + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_accepted) + { + tev.window = (GdkWindow *) wp; + tev.u.flags.delete_data = wp->dnd_drag_destructive_op; + tev.data_type = + gdk_atom_name(wp->dnd_drag_data_type); + + gdk_event_put((GdkEvent *) &tev); + } + } +} + +static GdkAtom +gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent) +{ + GdkWindowPrivate *wp = (GdkWindowPrivate *) window; + int i, j; + GdkEventDropEnter event; + + g_return_val_if_fail(window != NULL, 0); + g_return_val_if_fail(xevent != NULL, 0); + g_return_val_if_fail(xevent->type == ClientMessage, 0); + g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0); + + if(wp->dnd_drop_data_numtypesavail <= 0 || + !wp->dnd_drop_data_typesavail) + return 0; + + for (i = 2; i <= 4; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j]) + return xevent->xclient.data.l[i]; + } + } + + /* Now we get the extended type list if it's available */ + event.u.allflags = xevent->xclient.data.l[1]; + if (event.u.flags.extended_typelist) + { + Atom *exttypes, realtype; + gulong nitems, nbar; + gint realfmt; + + if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0], + gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1, + False, AnyPropertyType, &realtype, &realfmt, + &nitems, &nbar, (unsigned char **) &exttypes) + != Success) + return 0; + + if (realfmt != (sizeof(Atom) * 8)) + { + g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n", + realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]); + return 0; + } + + for (i = 0; i <= nitems; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (exttypes[i] == wp->dnd_drop_data_typesavail[j]) + { + XFree (exttypes); + return exttypes[i]; + } + } + } + XFree (exttypes); + } + return 0; +} + +/* + * used for debugging only + */ +static void +gdk_print_atom (GdkAtom anatom) +{ + gchar *tmpstr = NULL; + tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)"; + g_print("Atom %lu has name %s\n", anatom, tmpstr); + if(tmpstr) + g_free(tmpstr); +} + +/* + * used only by below routine and itself + */ +static Window +getchildren (Display *dpy, + Window win, + Atom WM_STATE) +{ + Window root, parent, *children, inf = 0; + Atom type = None; + unsigned int nchildren, i; + int format; + unsigned long nitems, after; + unsigned char *data; + + if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) + return 0; + + for (i = 0; !inf && (i < nchildren); i++) + { + XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + if (type != 0) + inf = children[i]; + } + + for (i = 0; !inf && (i < nchildren); i++) + inf = getchildren (dpy, children[i], WM_STATE); + + if (children != 0) + XFree ((char *) children); + + return inf; +} + +/* + * find a window with WM_STATE, else return win itself, as per ICCCM + * + * modification of the XmuClientWindow() routine from X11R6.3 + */ +Window +gdk_get_client_window (Display *dpy, + Window win) +{ + Atom WM_STATE; + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window inf; + + if (win == 0) + return DefaultRootWindow(dpy); + + if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0) + return win; + + XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data); + if (type) + return win; + + inf = getchildren (dpy, win, WM_STATE); + + if (inf == 0) + return win; + else + return inf; +} + +static GdkWindow * +gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y) +{ + GdkWindow *retval = w; + GdkWindowPrivate *awin; + GList *children; + gint16 myx = *x, myy = *y; + + g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL); + + myx = *x; + myy = *y; + +descend: + for (children = gdk_window_get_children(retval); + children && children->next; + children = children->next) + { + awin = (GdkWindowPrivate *) children->data; + if ((myx >= awin->x) && (myy >= awin->y) + && (myx < (awin->x + awin->width)) + && (myy < (awin->y + awin->height))) + { + retval = (GdkWindow *) awin; + myx -= awin->x; + myy -= awin->y; + goto descend; + } + } + + *x = myx; + *y = myy; + + return retval; +} + +/* Sends a ClientMessage to all toplevel client windows */ +void +gdk_event_send_clientmessage_toall(GdkEvent *event) +{ + XEvent sev; + Window *ret_children, ret_root, ret_parent, curwin; + unsigned int ret_nchildren; + int i; + + g_return_if_fail(event != NULL); + + /* Set up our event to send, with the exception of its target window */ + sev.xclient.type = ClientMessage; + sev.xclient.display = gdk_display; + sev.xclient.format = event->client.data_format; + sev.xclient.serial = CurrentTime; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + /* OK, we're all set, now let's find some windows to send this to */ + if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent, + &ret_children, &ret_nchildren) != True) + return; + + /* foreach true child window of the root window, send an event to it */ + for(i = 0; i < ret_nchildren; i++) { + curwin = gdk_get_client_window(gdk_display, ret_children[i]); + sev.xclient.window = curwin; + XSendEvent(gdk_display, curwin, False, NoEventMask, &sev); + } + + XFree(ret_children); +} diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c new file mode 100644 index 0000000000..d2d96b6daf --- /dev/null +++ b/gdk/x11/gdkpixmap-x11.c @@ -0,0 +1,657 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <X11/Xlib.h> + +#include "gdk.h" +#include "gdkprivate.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow, + width, height, depth); + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreateBitmapFromData (private->xdisplay, + window_private->xwindow, + data, width, height); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (fg != NULL, NULL); + g_return_val_if_fail (bg != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay, + window_private->xwindow, + data, width, height, + fg->pixel, bg->pixel, depth); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%s", instr); + fscanf(infile, "%s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gchar b, oldb; + + while (!feof (infile)) + { + fscanf(infile, "%c", &b); + if (c != b && b == '/') + { + fscanf (infile, "%c", &b); + if (b == '*') + { + oldb = b; + while (!feof (infile) && !(oldb == '*' && b == '/')) + { + oldb = b; + fscanf (infile, "%c", &b); + } + fscanf (infile, "%c", &b); + } + } + if (c == b) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + int *buffer_size) +{ + gchar c; + gint cnt = 0; + + if ((*buffer) == NULL) + { + (*buffer_size) = 10 * sizeof (gchar); + (*buffer) = (gchar *) malloc (*buffer_size); + } + + do + fscanf (infile, "%c", &c); + while (!feof (infile) && c != '"'); + + if (c != '"') + return FALSE; + + while (!feof (infile)) + { + fscanf (infile, "%c", &c); + + if (cnt == (*buffer_size)) + { + (*buffer_size) *= 2; + (*buffer) = (gchar *) realloc ((*buffer), *buffer_size); + } + + if (c != '"') + (*buffer)[cnt++] = c; + else + { + (*buffer)[cnt++] = 0; + return TRUE; + } + } + + return FALSE; +} + +gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, finished = FALSE, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[128], *retcol; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + if (ptr == NULL) + return NULL; + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + retcol = g_new(gchar, strlen (ptr) + 1); + strcpy (retcol, ptr); + return retcol; + } + + color[0] = 0; + numnames = 0; + + while (finished == FALSE) + { + sscanf (ptr, "%s", temp); + + if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 || + strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0) + finished = TRUE; + else + { + if (numnames > 0) + strcat (color, " "); + strcat (color, temp); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_new(gchar, strlen (color) + 1); + strcpy (retcol, color); + return retcol; +} + + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + FILE *infile = NULL; + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt; + gchar *buffer = NULL, *color_name = NULL, pixel_str[32]; + guint buffer_size = 0; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + infile = fopen (filename, "rb"); + if (infile != NULL) + { + if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE) + { + if (gdk_pixmap_seek_char (infile,'{') == TRUE) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + } + + fclose (infile); + free (buffer); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i; + gchar *buffer, *color_name = NULL, pixel_str[32]; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + i = 0; + buffer = data[i++]; + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + buffer = data[i++]; + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = data[i++]; + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + + return pixmap; +} + +void +gdk_pixmap_destroy (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private; + + g_return_if_fail (pixmap != NULL); + + private = (GdkPixmapPrivate*) pixmap; + if (private->ref_count <= 0) + { + XFreePixmap (private->xdisplay, private->xwindow); + gdk_xid_table_remove (private->xwindow); + g_free (pixmap); + } + else + { + private->ref_count -= 1; + } +} diff --git a/gdk/x11/gdkproperty-x11.c b/gdk/x11/gdkproperty-x11.c new file mode 100644 index 0000000000..35d8a50cf1 --- /dev/null +++ b/gdk/x11/gdkproperty-x11.c @@ -0,0 +1,194 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + return XInternAtom (gdk_display, atom_name, only_if_exists); +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar *t; + gchar *name; + + /* If this atom doesn't exist, we'll die with an X error unless + we take precautions */ + + gdk_error_warnings = 0; + t = XGetAtomName (gdk_display, atom); + gdk_error_warnings = 1; + + if (gdk_error_code == -1) + { + return NULL; + } + else + { + name = g_strdup (t); + XFree (t); + + return name; + } +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + Atom ret_prop_type; + gint ret_format; + gulong ret_nitems; + gulong ret_bytes_after; + gulong ret_length; + guchar *ret_data; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XGetWindowProperty (xdisplay, xwindow, property, + offset, (length + 3) / 4, pdelete, + type, &ret_prop_type, &ret_format, + &ret_nitems, &ret_bytes_after, + &ret_data); + + if ((ret_prop_type == None) && (ret_format == 0)) + return FALSE; + + if (actual_property_type) + *actual_property_type = ret_prop_type; + if (actual_format_type) + *actual_format_type = ret_format; + + if (ret_prop_type != property) + { + XFree (ret_data); + return FALSE; + } + + /* FIXME: ignoring bytes_after could have very bad effects */ + + if (data) + { + switch (ret_format) + { + case 8: + ret_length = ret_nitems; + break; + case 16: + ret_length = 2 * ret_nitems; + break; + case 32: + ret_length = 4 * ret_nitems; + break; + default: + g_warning ("unknown property return format: %d", ret_format); + XFree (ret_data); + return FALSE; + } + + *data = g_new (guchar, ret_length); + memcpy (*data, ret_data, ret_length); + if (actual_length) + *actual_length = ret_length; + } + + XFree (ret_data); + + return TRUE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XChangeProperty (xdisplay, xwindow, property, type, + format, mode, data, nelements); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XDeleteProperty (xdisplay, xwindow, property); +} diff --git a/gdk/x11/gdkselection-x11.c b/gdk/x11/gdkselection-x11.c new file mode 100644 index 0000000000..6bd4251100 --- /dev/null +++ b/gdk/x11/gdkselection-x11.c @@ -0,0 +1,168 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (owner) + { + private = (GdkWindowPrivate*) owner; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = None; + } + + XSetSelectionOwner (xdisplay, selection, xwindow, time); + + return (XGetSelectionOwner (xdisplay, selection) == xwindow); +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + Window xwindow; + + xwindow = XGetSelectionOwner (gdk_display, selection); + if (xwindow == None) + return NULL; + + return gdk_window_lookup (xwindow); +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + XConvertSelection (private->xdisplay, selection, target, + gdk_selection_property, private->xwindow, time); +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkWindowPrivate *private; + gulong nitems; + gulong nbytes; + gulong length; + GdkAtom prop_type; + gint prop_format; + guchar *t; + + g_return_val_if_fail (requestor != NULL, 0); + + /* If retrieved chunks are typically small, (and the ICCM says the + should be) it would be a win to try first with a buffer of + moderate length, to avoid two round trips to the server */ + + private = (GdkWindowPrivate*) requestor; + + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, 0, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (ret_type) + *ret_type = prop_type; + if (ret_format) + *ret_format = prop_format; + + if (prop_type == None) + { + *data = NULL; + return 0; + } + + XFree (t); + + /* Add on an extra byte to handle null termination. X guarantees + that t will be 1 longer than nbytes and null terminated */ + length = nbytes + 1; + + /* We can't delete the selection here, because it might be the INCR + protocol, in which case the client has to make sure they'll be + notified of PropertyChange events _before_ the property is deleted. + Otherwise there's no guarantee we'll win the race ... */ + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, (nbytes + 3) / 4, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (prop_type != None) + { + *data = g_new (guchar, length); + memcpy (*data, t, length); + XFree (t); + return length-1; + } + else + { + *data = NULL; + return 0; + } +} + + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + XSelectionEvent xevent; + + xevent.type = SelectionNotify; + xevent.serial = 0; + xevent.send_event = True; + xevent.display = gdk_display; + xevent.requestor = requestor; + xevent.selection = selection; + xevent.target = target; + xevent.property = property; + xevent.time = time; + + XSendEvent (gdk_display, requestor, False, NoEventMask, (XEvent*) &xevent); +} diff --git a/gdk/x11/gdkvisual-x11.c b/gdk/x11/gdkvisual-x11.c new file mode 100644 index 0000000000..22acee6f13 --- /dev/null +++ b/gdk/x11/gdkvisual-x11.c @@ -0,0 +1,431 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xutil.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[4]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +static char* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init () +{ + static gint possible_depths[5] = { 32, 24, 16, 15, 8 }; + static GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static gint npossible_depths = 5; + static gint npossible_types = 6; + + XVisualInfo *visual_list; + XVisualInfo visual_template; + GdkVisualPrivate temp_visual; + Visual *default_xvisual; + int nxvisuals; + int i, j; + + visual_template.screen = gdk_screen; + visual_list = XGetVisualInfo (gdk_display, VisualScreenMask, &visual_template, &nxvisuals); + visuals = g_new (GdkVisualPrivate, nxvisuals); + + default_xvisual = DefaultVisual (gdk_display, gdk_screen); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (visual_list[i].depth >= 8) + { +#ifdef __cplusplus + switch (visual_list[i].c_class) +#else /* __cplusplus */ + switch (visual_list[i].class) +#endif /* __cplusplus */ + { + case StaticGray: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + break; + case GrayScale: + visuals[nvisuals].visual.type = GDK_VISUAL_GRAYSCALE; + break; + case StaticColor: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + break; + case PseudoColor: + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + break; + case TrueColor: + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + break; + case DirectColor: + visuals[nvisuals].visual.type = GDK_VISUAL_DIRECT_COLOR; + break; + } + + visuals[nvisuals].visual.depth = visual_list[i].depth; + visuals[nvisuals].visual.byte_order = + (ImageByteOrder(gdk_display) == LSBFirst) ? + GDK_LSB_FIRST : GDK_MSB_FIRST; + visuals[nvisuals].visual.red_mask = visual_list[i].red_mask; + visuals[nvisuals].visual.green_mask = visual_list[i].green_mask; + visuals[nvisuals].visual.blue_mask = visual_list[i].blue_mask; + visuals[nvisuals].visual.colormap_size = visual_list[i].colormap_size; + visuals[nvisuals].visual.bits_per_rgb = visual_list[i].bits_per_rgb; + visuals[nvisuals].xvisual = visual_list[i].visual; + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + + nvisuals += 1; + } + } + + XFree (visual_list); + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + if (gdk_debug_level >= 1) + for (i = 0; i < nvisuals; i++) + g_print ("visual: %s: %d\n", + visual_names[visuals[i].visual.type], + visuals[i].visual.depth); + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable visual type"); +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth () +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type () +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system () +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best () +{ + return ((GdkVisual*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +void +gdk_query_visuals (GdkVisual **visual_return, + gint *count) +{ + *count = nvisuals; + *visual_return = (GdkVisual*) visuals; +} + + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c new file mode 100644 index 0000000000..aef1367d93 --- /dev/null +++ b/gdk/x11/gdkwindow-x11.c @@ -0,0 +1,1358 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/shape.h> +#include <netinet/in.h> +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include <stdlib.h> + +int nevent_masks = 16; +int event_mask_table[18] = +{ + ExposureMask, + PointerMotionMask, + PointerMotionHintMask, + ButtonMotionMask, + Button1MotionMask, + Button2MotionMask, + Button3MotionMask, + ButtonPressMask | OwnerGrabButtonMask, + ButtonReleaseMask | OwnerGrabButtonMask, + KeyPressMask, + KeyReleaseMask, + EnterWindowMask, + LeaveWindowMask, + FocusChangeMask, + StructureNotifyMask, + PropertyChangeMask, + 0, /* PROXIMITY_IN */ + 0 /* PROXIMTY_OUT */ +}; + + +void +gdk_window_init () +{ + XWindowAttributes xattributes; + unsigned int width; + unsigned int height; + unsigned int border_width; + unsigned int depth; + int x, y; + + XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window, + &x, &y, &width, &height, &border_width, &depth); + XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes); + + gdk_root_parent.xdisplay = gdk_display; + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + GdkColormap *colormap; + Display *parent_display; + Window xparent; + Visual *xvisual; + XSetWindowAttributes xattributes; + long xattributes_mask; + XSizeHints size_hints; + XWMHints wm_hints; + XTextProperty text_property; + XClassHint *class_hint; + int x, y, depth; + unsigned int class; + char *title; + int i; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + xparent = parent_private->xwindow; + parent_display = parent_private->xdisplay; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + private->xdisplay = parent_display; + private->destroyed = FALSE; + private->resize_count = 0; + private->ref_count = 1; + xattributes_mask = 0; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->window_type = attributes->window_type; + private->extension_events = FALSE; + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + xattributes.event_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (attributes->event_mask & (1 << (i + 1))) + xattributes.event_mask |= event_mask_table[i]; + } + + if (xattributes.event_mask) + xattributes_mask |= CWEventMask; + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + class = InputOutput; + depth = visual->depth; + + if (attributes_mask & GDK_WA_COLORMAP) + colormap = attributes->colormap; + else + colormap = gdk_colormap_get_system (); + + xattributes.background_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes_mask |= CWBorderPixel | CWBackPixel; + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_CHILD: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + break; + + case GDK_WINDOW_DIALOG: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_TEMP: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + + xattributes.save_under = True; + xattributes.override_redirect = True; + xattributes.cursor = None; + xattributes_mask |= CWSaveUnder | CWOverrideRedirect; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + } + else + { + depth = 1; + class = InputOnly; + colormap = NULL; + } + + private->xwindow = XCreateWindow (private->xdisplay, xparent, + x, y, private->width, private->height, + 0, depth, class, xvisual, + xattributes_mask, &xattributes); + gdk_xid_table_insert (&private->xwindow, window); + + switch (private->window_type) + { + case GDK_WINDOW_DIALOG: + XSetTransientForHint (private->xdisplay, private->xwindow, xparent); + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_TEMP: + XSetWMProtocols (private->xdisplay, private->xwindow, gdk_wm_window_protocols, 2); + break; + case GDK_WINDOW_CHILD: + if ((attributes->wclass == GDK_INPUT_OUTPUT) && + (colormap != gdk_colormap_get_system ()) && + (colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window)))) + { + g_print ("adding colormap window\n"); + gdk_window_add_colormap_windows (window); + } + break; + default: + break; + } + + size_hints.flags = PSize | PBaseSize; + size_hints.width = private->width; + size_hints.height = private->height; + size_hints.base_width = private->width; + size_hints.base_height = private->height; + + wm_hints.flags = InputHint | StateHint | WindowGroupHint; + wm_hints.window_group = gdk_leader_window; + wm_hints.input = True; + wm_hints.initial_state = NormalState; + + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); + XSetWMHints (private->xdisplay, private->xwindow, &wm_hints); + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = gdk_progname; + + if (XStringListToTextProperty (&title, 1, &text_property)) + { + XSetWMName (private->xdisplay, private->xwindow, &text_property); + XSetWMIconName (private->xdisplay, private->xwindow, &text_property); + XFree (text_property.value); + } + + if (attributes_mask & GDK_WA_WMCLASS) + { + class_hint = XAllocClassHint (); + class_hint->res_name = attributes->wmclass_name; + class_hint->res_class = attributes->wmclass_class; + XSetClassHint (private->xdisplay, private->xwindow, class_hint); + XFree (class_hint); + } + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + XWindowAttributes attrs; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + XGetWindowAttributes (gdk_display, anid, &attrs); + + private->parent = NULL; + private->xwindow = anid; + private->xdisplay = gdk_display; + private->x = attrs.x; + private->y = attrs.y; + private->width = attrs.width; + private->height = attrs.height; + private->resize_count = 0; + private->ref_count = 1; + if (anid == attrs.root) + private->window_type = GDK_WINDOW_ROOT; + else + private->window_type = GDK_WINDOW_TOPLEVEL; + /* the above is probably wrong, but it may not be worth the extra + X call to get it right */ + + private->destroyed = FALSE; + private->extension_events = 0; + + window->user_data = NULL; + + gdk_xid_table_insert (&private->xwindow, window); + + return window; +} + +void +gdk_window_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if(private->dnd_drag_data_numtypesavail > 0) + { + free(private->dnd_drag_data_typesavail); + private->dnd_drag_data_typesavail = NULL; + } + if(private->dnd_drop_data_numtypesavail > 0) + { + free(private->dnd_drop_data_typesavail); + private->dnd_drop_data_typesavail = NULL; + } + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (private->ref_count >= 1) + private->ref_count -= 1; + + if (!private->destroyed || (private->destroyed == 2)) + { + children = gdk_window_get_children (window); + tmp = children; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private && !temp_private->destroyed) + /* Removes some nice coredumps... /David */ + { + temp_private->destroyed = 2; + temp_private->ref_count += 1; + gdk_window_destroy (temp_window); + } + } + + g_list_free (children); + + if (!private->destroyed) + XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_PIXMAP: + g_warning ("called gdk_window_destroy on a pixmap (use gdk_pixmap_destroy)"); + gdk_pixmap_destroy (window); + break; + } +} + +void +gdk_window_real_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->ref_count == 0) + { + gdk_xid_table_remove (private->xwindow); + g_free (window); + } +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count += 1; + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_window_real_destroy (window); +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + XRaiseWindow (private->xdisplay, private->xwindow); + XMapWindow (private->xdisplay, private->xwindow); + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + XUnmapWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XMoveWindow (private->xdisplay, private->xwindow, x, y); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + XResizeWindow (private->xdisplay, private->xwindow, width, height); + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + XMoveResizeWindow (private->xdisplay, private->xwindow, x, y, width, height); + + if (!private->destroyed && + (private->window_type == GDK_WINDOW_CHILD)) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) new_parent; + + XReparentWindow (window_private->xdisplay, + window_private->xwindow, + parent_private->xwindow, + x, y); +} + +void +gdk_window_clear (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + XClearWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, False); +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, True); +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + XCopyArea (dest_private->xdisplay, src_private->xwindow, dest_private->xwindow, + gc_private->xgc, + source_x, source_y, + width, height, + x, y); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XRaiseWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XLowerWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + size_hints.flags = 0; + + if (flags & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + size_hints.x = x; + size_hints.y = y; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = min_width; + size_hints.min_height = min_height; + } + + if (flags & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = max_width; + size_hints.max_height = max_height; + } + + if (flags) + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XStoreName (private->xdisplay, private->xwindow, title); + XSetIconName (private->xdisplay, private->xwindow, title); +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XSetWindowBackground (private->xdisplay, private->xwindow, color->pixel); +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; + GdkPixmapPrivate *pixmap_private; + Pixmap xpixmap; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkPixmapPrivate*) pixmap; + + if (pixmap) + xpixmap = pixmap_private->xwindow; + else + xpixmap = None; + + if (parent_relative) + xpixmap = ParentRelative; + + XSetWindowBackgroundPixmap (window_private->xdisplay, window_private->xwindow, xpixmap); +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + Cursor xcursor; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + XDefineCursor (window_private->xdisplay, window_private->xwindow, xcursor); +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + XSetWindowColormap (window_private->xdisplay, + window_private->xwindow, + colormap_private->xcolormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowPrivate *window_private; + Window root; + gint tx; + gint ty; + guint twidth; + guint theight; + guint tborder_width; + guint tdepth; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + XGetGeometry (window_private->xdisplay, window_private->xwindow, + &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth); + + if (x) + *x = tx; + if (y) + *y = ty; + if (width) + *width = twidth; + if (height) + *height = theight; + if (depth) + *depth = tdepth; +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private) + { + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_visual_lookup (window_attributes.visual); + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_colormap_lookup (window_attributes.colormap); +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + Window child; + gint tx, ty; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + return_val = XTranslateCoordinates (private->xdisplay, + private->xwindow, + gdk_root_window, + 0, 0, &tx, &ty, + &child); + + if (x) + *x = tx; + if (y) + *y = ty; + + return return_val; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + Window root; + Window child; + int rootx, rooty; + int winx, winy; + unsigned int xmask; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + if (XQueryPointer (private->xdisplay, private->xwindow, &root, &child, + &rootx, &rooty, &winx, &winy, &xmask)) + { + if (x) *x = winx; + if (y) *y = winy; + if (mask) *mask = xmask; + + if (child) + return_val = gdk_window_lookup (child); + } + + return return_val; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindow *child; + GList *children; + Window root; + Window parent; + Window *xchildren; + unsigned int nchildren; + unsigned int i; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + XQueryTree (private->xdisplay, private->xwindow, + &root, &parent, &xchildren, &nchildren); + + children = NULL; + + if (nchildren > 0) + { + for (i = 0; i < nchildren; i++) + { + child = gdk_window_lookup (xchildren[i]); + if (child) + children = g_list_prepend (children, child); + } + + XFree (xchildren); + } + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + XWindowAttributes attrs; + GdkEventMask event_mask; + int i; + + XGetWindowAttributes (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + &attrs); + + event_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (attrs.your_event_mask & event_mask_table[i]) + event_mask |= 1 << (i + 1); + } + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + long xevent_mask; + int i; + + xevent_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + XSelectInput (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + xevent_mask); +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + GdkWindow *toplevel; + GdkWindowPrivate *toplevel_private; + GdkWindowPrivate *window_private; + Window *old_windows; + Window *new_windows; + int i, count; + + g_return_if_fail (window != NULL); + + toplevel = gdk_window_get_toplevel (window); + toplevel_private = (GdkWindowPrivate*) toplevel; + window_private = (GdkWindowPrivate*) window; + + if (!XGetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + &old_windows, &count)) + { + old_windows = NULL; + count = 0; + } + + for (i = 0; i < count; i++) + if (old_windows[i] == window_private->xwindow) + return; + + new_windows = g_new (Window, count + 1); + + for (i = 0; i < count; i++) + new_windows[i] = old_windows[i]; + new_windows[count] = window_private->xwindow; + + XSetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + new_windows, count + 1); + + g_free (new_windows); + if (old_windows) + XFree (old_windows); +} + +/* + * This needs the X11 shape extension. + * If not available, simply remove the call to + * XShapeCombineMask. Shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *pixmap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (mask != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkWindowPrivate*) mask; + + XShapeCombineMask (window_private->xdisplay, + window_private->xwindow, + ShapeBounding, + x, y, /* offset */ + (Pixmap)pixmap_private->xwindow, + ShapeSet); +} + +void +gdk_dnd_drag_addwindow (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + if (window_private->dnd_drag_enabled == 1 && gdk_dnd.drag_really == 0) + { + gdk_dnd.drag_numwindows++; + gdk_dnd.drag_startwindows = g_realloc (gdk_dnd.drag_startwindows, + gdk_dnd.drag_numwindows + * sizeof(GdkWindow *)); + gdk_dnd.drag_startwindows[gdk_dnd.drag_numwindows - 1] = window; + window_private->dnd_drag_accepted = 0; + } + else + g_warning ("dnd_really is 1 or drag is not enabled! can't addwindow\n"); +} + +void +gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes) +{ + GdkWindowPrivate *window_private; + int i, wasset = 0; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drag_enabled = drag_enable ? 1 : 0; + + if (drag_enable) + { + g_return_if_fail(typelist != NULL); + + if (window_private->dnd_drag_data_numtypesavail > 3) + wasset = 1; + window_private->dnd_drag_data_numtypesavail = numtypes; + + window_private->dnd_drag_data_typesavail = + g_realloc (window_private->dnd_drag_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + { + /* Allow blanket use of ALL to get anything... */ + if (strcmp (typelist[i], "ALL")) + window_private->dnd_drag_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + else + window_private->dnd_drag_data_typesavail[i] = None; + } + + /* + * set our extended type list if we need to + */ + if (numtypes > 3) + gdk_property_change(window, gdk_dnd.gdk_XdeTypelist, + XA_PRIMARY, 32, GDK_PROP_MODE_REPLACE, + (guchar *)(window_private->dnd_drag_data_typesavail + + (sizeof(GdkAtom) * 3)), + (numtypes - 3) * sizeof(GdkAtom)); + else if (wasset) + gdk_property_delete (window, gdk_dnd.gdk_XdeTypelist); + } + else + { + free (window_private->dnd_drag_data_typesavail); + window_private->dnd_drag_data_typesavail = NULL; + window_private->dnd_drag_data_numtypesavail = 0; + } +} + +void +gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op) +{ + GdkWindowPrivate *window_private; + int i; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drop_enabled = drop_enable ? 1 : 0; + if (drop_enable) + { + g_return_if_fail(typelist != NULL); + + window_private->dnd_drop_data_numtypesavail = numtypes; + + window_private->dnd_drop_data_typesavail = + g_realloc (window_private->dnd_drop_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + window_private->dnd_drop_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + + window_private->dnd_drop_destructive_op = destructive_op; + } +} + +/* + * This is used to reply to a GDK_DRAG_REQUEST event + * (which may be generated by XdeRequest or a confirmed drop... + */ +void +gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + GdkWindowPrivate *window_private; + XEvent sev; + GdkEventDropDataAvailable tmp_ev; + gchar *tmp; + + g_return_if_fail (window != NULL); + g_return_if_fail (event != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (data_numbytes > 0); + g_return_if_fail (event->type == GDK_DRAG_REQUEST); + + g_free (event->dragrequest.data_type); + event->dragrequest.data_type = NULL; + + window_private = (GdkWindowPrivate *) window; + g_return_if_fail (window_private->dnd_drag_accepted != 0); + + /* We set the property on our window... */ + gdk_property_change (window, window_private->dnd_drag_data_type, + XA_PRIMARY, 8, GDK_PROP_MODE_REPLACE, data, + data_numbytes); + tmp = gdk_atom_name(window_private->dnd_drag_data_type); + g_print("DnD type %s on window %ld\n", tmp, window_private->xwindow); + g_free(tmp); + + /* + * Then we send the event to tell the receiving window that the + * drop has happened + */ + tmp_ev.u.allflags = 0; + tmp_ev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tmp_ev.u.flags.isdrop = event->dragrequest.isdrop; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.window = event->dragrequest.requestor; + sev.xclient.message_type = gdk_dnd.gdk_XdeDataAvailable; + sev.xclient.data.l[0] = window_private->xwindow; + sev.xclient.data.l[1] = tmp_ev.u.allflags; + sev.xclient.data.l[2] = window_private->dnd_drag_data_type; + + if (event->dragrequest.isdrop) + sev.xclient.data.l[3] = event->dragrequest.drop_coords.x + + (event->dragrequest.drop_coords.y << 16); + else + sev.xclient.data.l[3] = 0; + + sev.xclient.data.l[4] = 0; + + XSendEvent (gdk_display, event->dragrequest.requestor, False, + NoEventMask, &sev); +} diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h new file mode 100644 index 0000000000..cb8e33b44f --- /dev/null +++ b/gdk/x11/gdkx.h @@ -0,0 +1,48 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GDK_X_H__ +#define __GDK_X_H__ + +#include <gdk/gdkprivate.h> + + +#define GDK_ROOT_WINDOW() gdk_root_window +#define GDK_ROOT_PARENT() &gdk_root_parent +#define GDK_DISPLAY() gdk_display +#define GDK_WINDOW_XDISPLAY(win) (((GdkWindowPrivate*) win)->xdisplay) +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) (((GdkImagePrivate*) image)->xdisplay) +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) (((GdkGCPrivate*) gc)->xdisplay) +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) (((GdkColormapPrivate*) cmap)->xdisplay) +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) (((GdkFontPrivate*) font)->xdisplay) +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Utility function in gdk.c - not sure where it belongs, but it's + needed in more than one place, so make it public */ +Window gdk_get_client_window (Display *dpy, + Window win); + + +#endif /* __GDK_X_H__ */ diff --git a/gdk/x11/gdkxid.c b/gdk/x11/gdkxid.c new file mode 100644 index 0000000000..7ee6075c53 --- /dev/null +++ b/gdk/x11/gdkxid.c @@ -0,0 +1,74 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gdkprivate.h" + + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data; + + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/x11/gxid.c b/gdk/x11/gxid.c new file mode 100644 index 0000000000..219c08bfe0 --- /dev/null +++ b/gdk/x11/gxid.c @@ -0,0 +1,844 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <X11/Xlib.h> +#include <X11/extensions/XInput.h> + +#include "gxid_proto.h" + +/* #define DEBUG_CLIENTS */ +/* #define DEBUG_EVENTS */ + +char *program_name; +Display *dpy; +Window root_window; /* default root window of dpy */ +int port = 0; /* port to listen on */ +int socket_fd = 0; /* file descriptor of socket */ +typedef struct GxidWindow_ GxidWindow; + +typedef struct GxidDevice_ GxidDevice; +struct GxidDevice_ { + XID id; + int exclusive; + int ispointer; + + XDevice *xdevice; + int motionnotify_type; + int changenotify_type; +}; + +struct GxidWindow_ { + Window xwindow; + /* Immediate child of root that is ancestor of window */ + Window root_child; + int num_devices; + GxidDevice **devices; +}; + +GxidDevice **devices = NULL; +int num_devices = 0; +GxidWindow **windows = NULL; +int num_windows = 0; + +void +handler(int signal) +{ + fprintf(stderr,"%s: dying on signal %d\n",program_name,signal); + if (socket_fd) + close(socket_fd); + exit(1); +} + +void +init_socket() +{ + struct sockaddr_in sin; + + socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (socket_fd < 0) + { + fprintf (stderr, "%s: error getting socket\n", + program_name); + exit(1); + } + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(socket_fd,(struct sockaddr *)(&sin), + sizeof(struct sockaddr_in)) < 0) + { + fprintf (stderr,"%s: cannot bind to port %d\n", + program_name,port); + exit(1); + } + + if (listen(socket_fd,5) < 0) + { + fprintf (stderr,"%s: error listening on socket\n", + program_name); + exit(1); + }; +} + +#define NUM_EVENTC 2 +static void +enable_device(GxidDevice *dev) +{ + XEventClass xevc[NUM_EVENTC]; + int num_eventc = NUM_EVENTC; + int i,j; + + if (!dev->xdevice) + { + if (dev->ispointer) return; + + dev->xdevice = XOpenDevice(dpy, dev->id); + if (!dev->xdevice) return; + + DeviceMotionNotify (dev->xdevice, dev->motionnotify_type, + xevc[0]); + ChangeDeviceNotify (dev->xdevice, dev->changenotify_type, + xevc[1]); + + /* compress out zero event classes */ + for (i=0,j=0;i<NUM_EVENTC;i++) + { + if (xevc[i]) { + xevc[j] = xevc[i]; + j++; + } + } + num_eventc = j; + + XSelectExtensionEvent (dpy, root_window, xevc, num_eventc); + } +} + +/* switch the core pointer from whatever it is now to something else, + return true on success, false otherwise */ +static int +switch_core_pointer() +{ + GxidDevice *old_pointer = 0; + GxidDevice *new_pointer = 0; + int result; + int i; + + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + old_pointer = devices[i]; + else + if (!new_pointer && !devices[i]->exclusive) + new_pointer = devices[i]; + } + + if (!old_pointer || !new_pointer) + return 0; + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Switching core from %ld to %ld\n", + old_pointer->id,new_pointer->id); +#endif + result = XChangePointerDevice(dpy,new_pointer->xdevice, 0, 1); + if (result != Success) + { + fprintf(stderr,"gxid: Error %d switching core from %ld to %ld\n", + result, old_pointer->id, new_pointer->id); + } + else + { + new_pointer->ispointer = 1; + old_pointer->ispointer = 0; + if (!old_pointer->xdevice) + enable_device(old_pointer); + } + + return 1; +} + +void +disable_device(GxidDevice *dev) +{ + if (dev->xdevice) + { + if (dev->ispointer) + return; + XCloseDevice(dpy,dev->xdevice); + dev->xdevice = 0; + } +} + +GxidDevice * +init_device(XDeviceInfo *xdevice) +{ + GxidDevice *dev = (GxidDevice *)malloc(sizeof(GxidDevice)); + XAnyClassPtr class; + int num_axes, i; + + dev->id = xdevice->id; + dev->exclusive = 0; + dev->xdevice = NULL; + + dev->ispointer = (xdevice->use == IsXPointer); + + /* step through the classes */ + + num_axes = 0; + class = xdevice->inputclassinfo; + for (i=0;i<xdevice->num_classes;i++) + { + if (class->class == ValuatorClass) + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + num_axes = xvi->num_axes; + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + + /* return NULL if insufficient axes */ + if (num_axes < 2) + { + free((void *)dev); + return NULL; + } + + if (!dev->ispointer) + enable_device(dev); + return dev; +} + +void +init_xinput() +{ + char **extensions; + XDeviceInfo *xdevices; + int num_xdevices; + int num_extensions; + int i; + + extensions = XListExtensions(dpy, &num_extensions); + for (i = 0; i < num_extensions && + (strcmp(extensions[i], "XInputExtension") != 0); i++); + XFreeExtensionList(extensions); + if (i == num_extensions) /* XInput extension not found */ + { + fprintf(stderr,"XInput extension not found\n"); + exit(1); + } + + xdevices = XListInputDevices(dpy, &num_xdevices); + devices = (GxidDevice **)malloc(num_xdevices * sizeof(GxidDevice *)); + + num_devices = 0; + for(i=0; i<num_xdevices; i++) + { + GxidDevice *dev = init_device(&xdevices[i]); + if (dev) + devices[num_devices++] = dev; + } + XFreeDeviceList(xdevices); +} + +/* If this routine needs fixing, the corresponding routine + in gdkinputgxi.h will need it too. */ + +Window +gxi_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +int +handle_claim_device(GxidClaimDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + int exclusive = ntohl(msg->exclusive); + GxidDevice *device = NULL; + GxidWindow *window = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld claimed (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + if (device->exclusive) + { + /* already in use */ + fprintf(stderr, + "%s: Device %ld already claimed in exclusive mode\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + if (exclusive) + { + for (i=0;i<num_windows;i++) + { + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j]->id == devid) + { + /* already in use */ + fprintf(stderr, + "%s: Can't establish exclusive use of device %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + } + if (device->ispointer) + if (!switch_core_pointer()) + { + fprintf(stderr, + "%s: Can't free up core pointer %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + device->exclusive = 1; + disable_device(device); + XSelectInput(dpy,winid,StructureNotifyMask); + } + else /* !exclusive */ + { + /* FIXME: this is a bit improper. We probably should do this only + when a window is first claimed. But we might be fooled if + an old client died without releasing it's windows. So until + we look for client-window closings, do it here + + (We do look for closings now...) + */ + + XSelectInput(dpy,winid,EnterWindowMask|StructureNotifyMask); + } + + for (i=0;i<num_windows;i++) + { + if (windows[i]->xwindow == winid) + { + window = windows[i]; + break; + } + } + + /* Create window structure if no devices have been previously + claimed on it */ + if (!window) + { + num_windows++; + windows = (GxidWindow **)realloc(windows, + sizeof(GxidWindow*)*num_windows); + window = (GxidWindow *)malloc(sizeof(GxidWindow)); + windows[num_windows-1] = window; + + window->xwindow = winid; + window->root_child = gxi_find_root_child(dpy,winid); + window->num_devices = 0; + window->devices = 0; + } + + + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == device) + return GXID_RETURN_OK; + } + + window->num_devices++; + window->devices = (GxidDevice **)realloc(window->devices, + sizeof(GxidDevice*)*num_devices); + /* we need add the device to the window */ + window->devices[i] = device; + + return GXID_RETURN_OK; +} + +int +handle_release_device(GxidReleaseDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + + GxidDevice *device = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + for (i=0;i<num_windows;i++) + { + GxidWindow *w = windows[i]; + + if (w->xwindow == winid) + for (j=0;j<w->num_devices;j++) + if (w->devices[j]->id == devid) + { + if (j<w->num_devices-1) + w->devices[j] = w->devices[w->num_devices-1]; + w->num_devices--; + + if (w->num_devices == 0) + { + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + } + + if (device->exclusive) + { + device->exclusive = 0; + enable_device(device); + } + return GXID_RETURN_OK; + } + } + + /* device/window combination not found */ + fprintf(stderr, + "%s: Device %ld not claimed for window 0x%lx\n", + program_name,devid,winid); + return GXID_RETURN_ERROR; +} + +void +handle_connection() +{ + GxidMessage msg; + GxidU32 type; + int length; + GxidI32 retval; + + int conn_fd; + struct sockaddr_in sin; + int sin_length; + int count; + + sin_length = sizeof(struct sockaddr_in); + conn_fd = accept(socket_fd,(struct sockaddr *)&sin,&sin_length); + if (conn_fd < 0) + { + fprintf(stderr,"%s: Error accepting connection\n", + program_name); + exit(1); + } + + /* read type and length of message */ + + count = read(conn_fd,(char *)&msg,2*sizeof(GxidU32)); + if (count != 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message header\n", + program_name); + close(conn_fd); + return; + } + type = ntohl(msg.any.type); + length = ntohl(msg.any.length); + + /* read rest of message */ + + if (length > sizeof(GxidMessage)) + { + fprintf(stderr,"%s: Bad message length\n", + program_name); + close(conn_fd); + return; + } + + count = read(conn_fd,2*sizeof(GxidU32) + (char *)&msg, + length - 2*sizeof(GxidU32)); + if (count != length - 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message body\n", + program_name); + close(conn_fd); + return; + } + + switch (type) + { + case GXID_CLAIM_DEVICE: + retval = handle_claim_device((GxidClaimDevice *)&msg); + break; + case GXID_RELEASE_DEVICE: + retval = handle_release_device((GxidReleaseDevice *)&msg); + break; + default: + fprintf(stderr,"%s: Unknown message type: %ld (ignoring)\n", + program_name,type); + close(conn_fd); + return; + } + + count = write(conn_fd,&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"%s: Error writing return code\n", + program_name); + } + + close(conn_fd); +} + +void +handle_motion_notify(XDeviceMotionEvent *event) +{ + int i,j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + Window w, root, child; + int root_x, root_y, x, y, mask; + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + + if (new_device && !new_device->exclusive && !new_device->ispointer) + { + /* make sure we aren't stealing the pointer back from a slow + client */ + child = root_window; + do + { + w = child; + /* FIXME: this fails disasterously if child vanishes between + calls. (Which is prone to happening since we get events + on root just as the client exits) */ + + XQueryPointer(dpy,w,&root,&child,&root_x,&root_y, + &x,&y,&mask); + } + while (child != None); + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == w) + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j] == new_device) + return; + + /* FIXME: do something smarter with axes */ + XChangePointerDevice(dpy,new_device->xdevice, 0, 1); + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_change_notify(XChangeDeviceNotifyEvent *event) +{ + int j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: ChangeNotify event; old = %ld; new = %ld\n", + old_device->id, new_device->id); +#endif + + if (old_device != new_device) + { + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_enter_notify(XEnterWindowEvent *event, GxidWindow *window) +{ + int i; + GxidDevice *old_pointer = NULL; + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + { + old_pointer = devices[i]; + break; + } + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Enter event; oldpointer = %ld\n", + old_pointer->id); +#endif + + if (old_pointer) + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == old_pointer) + { + switch_core_pointer(); + break; + } + } +} + +void +handle_destroy_notify(XDestroyWindowEvent *event) +{ + int i,j; + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == event->window) + { + GxidWindow *w = windows[i]; + + for (j=0;j<w->num_devices;j++) + { +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released on destruction of window 0x%lx.\n", + w->devices[j]->id,w->xwindow); +#endif + + if (w->devices[j]->exclusive) + { + w->devices[j]->exclusive = 0; + enable_device(devices[j]); + } + } + + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + if (w->devices) + free((void *)w->devices); + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + + return; + } +} + +void +handle_xevent() +{ + int i; + XEvent event; + + XNextEvent (dpy, &event); + +#ifdef DEBUG_EVENTS + fprintf(stderr,"Event - type = %d; window = 0x%lx\n", + event.type,event.xany.window); +#endif + + if (event.type == ConfigureNotify) + { +#ifdef DEBUG_EVENTS + XConfigureEvent *xce = (XConfigureEvent *)&event; + fprintf(stderr," configureNotify: window = 0x%lx\n",xce->window); +#endif + } + else if (event.type == EnterNotify) + { + /* pointer entered a claimed window */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_enter_notify((XEnterWindowEvent *)&event,windows[i]); + } + } + else if (event.type == DestroyNotify) + { + /* A claimed window was destroyed */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_destroy_notify((XDestroyWindowEvent *)&event); + } + } + else + for (i=0;i<num_devices;i++) + { + if (event.type == devices[i]->motionnotify_type) + { + handle_motion_notify((XDeviceMotionEvent *)&event); + break; + } + else if (event.type == devices[i]->changenotify_type) + { + handle_change_notify((XChangeDeviceNotifyEvent *)&event); + break; + } + } +} + +void +usage() +{ + fprintf(stderr,"Usage: %s [-d display] [-p --gxid-port port]\n", + program_name); + exit(1); +} + +int +main(int argc, char **argv) +{ + int i; + char *display_name = NULL; + fd_set readfds; + + program_name = argv[0]; + + for (i=1;i<argc;i++) + { + if (!strcmp(argv[i],"-d")) + { + if (++i >= argc) usage(); + display_name = argv[i]; + } + else if (!strcmp(argv[i],"--gxid-port") || + !strcmp(argv[i],"-p")) + { + if (++i >= argc) usage(); + port = atoi(argv[i]); + break; + } + else + usage(); + } + + if (!port) + { + char *t = getenv("GXID_PORT"); + if (t) + port = atoi(t); + else + port = 6951; + } + /* set up a signal handler so we can clean up if killed */ + + signal(SIGTERM,handler); + signal(SIGINT,handler); + + /* initialize the X connection */ + + dpy = XOpenDisplay (display_name); + if (!dpy) + { + fprintf (stderr, "%s: unable to open display '%s'\n", + program_name, XDisplayName (display_name)); + exit (1); + } + + root_window = DefaultRootWindow(dpy); + + /* We'll want to do this in the future if we are to support + gxid monitoring visibility information for clients */ +#if 0 + XSelectInput(dpy,root_window,SubstructureNotifyMask); +#endif + init_xinput(); + + /* set up our server connection */ + + init_socket(); + + /* main loop */ + + if (XPending(dpy)) /* this seems necessary to get things + in sync */ + handle_xevent(); + while (1) + { + + FD_ZERO(&readfds); + FD_SET(ConnectionNumber(dpy),&readfds); + FD_SET(socket_fd,&readfds); + + if (select(8*sizeof(readfds),&readfds, + (fd_set *)0,(fd_set *)0, (struct timeval *)0) < 0) + { + fprintf(stderr,"Error in select\n"); + exit(1); + } + + if (FD_ISSET(socket_fd,&readfds)) + handle_connection(socket_fd); + + while (XPending(dpy)) + handle_xevent(); + } + + XCloseDisplay (dpy); + exit (0); +} diff --git a/gdk/x11/gxid_lib.c b/gdk/x11/gxid_lib.c new file mode 100644 index 0000000000..357b764513 --- /dev/null +++ b/gdk/x11/gxid_lib.c @@ -0,0 +1,116 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include "../config.h" + +#ifdef XINPUT_GXI + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +#include "gxid_lib.h" + +/* handles mechanics of communicating with a client */ +static int +gxid_send_message(char *host, int port, GxidMessage *msg) +{ + int socket_fd; + struct sockaddr_in sin; + int count; + GxidI32 retval; + struct hostent *he; + + if (!port) port = 6951; + + if (!host || strcmp(host,"localhost") ) + { + /* looking it up as localhost can be _SLOW_ on ppp systems */ + /* FIXME: Could localhost be anything other than loopback? */ + host = "127.0.0.1"; + } + + he = gethostbyname(host); + if (!he) + { + fprintf(stderr,"gxid_lib: error looking up %s\n",host); + return GXID_RETURN_ERROR; + } + + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + memcpy(&sin.sin_addr,he->h_addr_list[0],he->h_length); + + socket_fd = socket(AF_INET,SOCK_STREAM,0); + if (socket_fd < 0) + { + fprintf(stderr,"gxid_lib: can't get socket"); + return GXID_RETURN_ERROR; + } + + if (connect(socket_fd, (struct sockaddr *)&sin, + sizeof sin) < 0) + { + fprintf(stderr,"gxid_lib: can't connect to %s:%d\n",host,port); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + count = write(socket_fd,(char *)msg,ntohl(msg->any.length)); + if (count != ntohl(msg->any.length)) + { + fprintf(stderr,"gxid_lib: error writing"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + /* now read the return code */ + count = read(socket_fd,(char *)&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"gxid_lib: error reading return code"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + close (socket_fd); + return ntohl(retval); +} + +/* claim a device. If exclusive, device is claimed exclusively */ +int +gxid_claim_device(char *host, int port, GxidU32 device, GxidU32 window, + int exclusive) +{ + GxidClaimDevice msg; + msg.type = htonl(GXID_CLAIM_DEVICE); + msg.length = htonl(sizeof(GxidClaimDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + msg.exclusive = htonl(exclusive); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +/* release a device/window pair */ +int +gxid_release_device(char *host, int port, GxidU32 device, GxidU32 window) +{ + GxidReleaseDevice msg; + msg.type = htonl(GXID_RELEASE_DEVICE); + msg.length = htonl(sizeof(GxidReleaseDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +#endif /* XINPUT_GXI */ + diff --git a/gdk/x11/gxid_lib.h b/gdk/x11/gxid_lib.h new file mode 100644 index 0000000000..6a7103bbe0 --- /dev/null +++ b/gdk/x11/gxid_lib.h @@ -0,0 +1,6 @@ +#include "gxid_proto.h" + +int gxid_claim_device(char *host, int port, + GxidU32 device, GxidU32 window, int exclusive); +int gxid_release_device(char *host, int port, GxidU32 device, + GxidU32 window); diff --git a/gdk/x11/gxid_proto.h b/gdk/x11/gxid_proto.h new file mode 100644 index 0000000000..24959b806c --- /dev/null +++ b/gdk/x11/gxid_proto.h @@ -0,0 +1,39 @@ +#define GXID_CLAIM_DEVICE 1 +#define GXID_RELEASE_DEVICE 2 + +#define GXID_RETURN_OK 0 +#define GXID_RETURN_ERROR -1 + +typedef struct GxidClaimDevice_ GxidClaimDevice; +typedef struct GxidReleaseDevice_ GxidReleaseDevice; +typedef struct GxidMessageAny_ GxidMessageAny; +typedef union GxidMessage_ GxidMessage; + +typedef unsigned long GxidU32; +typedef long GxidI32; + +struct GxidClaimDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; + GxidU32 exclusive; +}; + +struct GxidReleaseDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; +}; + +struct GxidMessageAny_ { + GxidU32 type; + GxidU32 length; +}; + +union GxidMessage_ { + GxidMessageAny any; + GxidClaimDevice claim; + GxidReleaseDevice release; +}; diff --git a/glib/.cvsignore b/glib/.cvsignore new file mode 100644 index 0000000000..e0d0bd21d6 --- /dev/null +++ b/glib/.cvsignore @@ -0,0 +1,11 @@ +*.lo +config.log +libtool +config.status +stamp-h +Makefile +.deps +_libs +libglib.la +testglib +glibconfig.h diff --git a/glib/AUTHORS b/glib/AUTHORS new file mode 100644 index 0000000000..67f4e56178 --- /dev/null +++ b/glib/AUTHORS @@ -0,0 +1 @@ +Peter Mattis (petm@xcf.berkeley.edu) diff --git a/glib/COPYING b/glib/COPYING new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/glib/COPYING diff --git a/glib/ChangeLog b/glib/ChangeLog new file mode 100644 index 0000000000..b119426ca6 --- /dev/null +++ b/glib/ChangeLog @@ -0,0 +1,10 @@ +Tue Dec 17 13:14:07 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * glib.h: Changed 'g_return_if_fail' and 'g_return_val_if_fail' to + not call 'g_string' but to simply stringify the + expression. Calling 'g_string' causes the expression to be + expanded which is undesired. + +Sun Dec 1 01:30:48 1996 Peter Mattis <pmattis@charnley.HIP.Berkeley.EDU> + + * Started ChangeLog diff --git a/glib/INSTALL b/glib/INSTALL new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/glib/INSTALL diff --git a/glib/Makefile.am b/glib/Makefile.am new file mode 100644 index 0000000000..18afb93a59 --- /dev/null +++ b/glib/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to produce Makefile.in + +lib_LTLIBRARIES = libglib.la + +libglib_la_SOURCES = \ + garray.c \ + gcache.c \ + gerror.c \ + ghash.c \ + glist.c \ + gmem.c \ + gprimes.c \ + gslist.c \ + gtimer.c \ + gtree.c \ + gutils.c \ + gstring.c + +include_HEADERS = \ + glib.h \ + glibconfig.h + +libglib_la_LDFLAGS = -version-info 1:0:0 + +INCLUDES = + +noinst_PROGRAMS = testglib +testglib_LDADD = $(top_builddir)/libglib.la + +.PHONY: files release + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done + +release: + $(MAKE) dist distdir=$(PACKAGE)`date +"%y%m%d"` diff --git a/glib/NEWS b/glib/NEWS new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/glib/NEWS diff --git a/glib/README b/glib/README new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/glib/README diff --git a/glib/acconfig.h b/glib/acconfig.h new file mode 100644 index 0000000000..48ca75f8df --- /dev/null +++ b/glib/acconfig.h @@ -0,0 +1,62 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +/* acconfig.h + This file is in the public domain. + + Descriptive text for the C preprocessor macros that + the distributed Autoconf macros can define. + No software package will use all of them; autoheader copies the ones + your configure.in uses into your configuration header file templates. + + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). Although this order + can split up related entries, it makes it easier to check whether + a given entry is in the file. + + Leave the following blank line there!! Autoheader needs it. */ + + +/* Other stuff */ +#undef HAVE_DOPRNT +#undef HAVE_FLOAT_H +#undef HAVE_LIMITS_H +#undef HAVE_LONG_DOUBLE +#undef HAVE_SYS_SELECT_H +#undef HAVE_STRERROR +#undef HAVE_STRSIGNAL +#undef HAVE_VALUES_H +#undef HAVE_VPRINTF + +#undef NO_FD_SET +#undef NO_SYS_ERRLIST +#undef NO_SYS_SIGLIST + +#undef SIZEOF_CHAR +#undef SIZEOF_SHORT +#undef SIZEOF_LONG +#undef SIZEOF_INT +#undef SIZEOF_VOID_P + +/* #undef PACKAGE */ +/* #undef VERSION */ + + +/* Leave that blank line there!! Autoheader needs it. + If you're adding to this file, keep in mind: + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). */ diff --git a/glib/aclocal.m4 b/glib/aclocal.m4 new file mode 100644 index 0000000000..9f99ab8e72 --- /dev/null +++ b/glib/aclocal.m4 @@ -0,0 +1,395 @@ +dnl aclocal.m4 generated automatically by aclocal 1.2 + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AM_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") +AC_DEFINE_UNQUOTED(VERSION, "$VERSION")) +AM_SANITY_CHECK +AC_ARG_PROGRAM +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_PROG_MAKE_SET]) + + +# serial 1 + +AC_DEFUN(AM_PROG_INSTALL, +[AC_REQUIRE([AC_PROG_INSTALL]) +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl +]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$@" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<<am_indx=1 +for am_file in <<$1>>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +# serial 17 AM_PROG_LIBTOOL +AC_DEFUN(AM_PROG_LIBTOOL, +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_RANLIB]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AM_PROG_LD]) +AC_REQUIRE([AM_PROG_NM]) +AC_REQUIRE([AC_PROG_LN_S]) + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL) + +dnl Allow the --disable-shared flag to stop us from building shared libs. +AC_ARG_ENABLE(shared, +[ --enable-shared build shared libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_shared=no +else + libtool_enable_shared=yes +fi]) +test -n "$libtool_enable_shared" && enable_shared="$libtool_enable_shared" +libtool_shared= +test "$enable_shared" = no && libtool_shared=" --disable-shared" + +dnl Allow the --disable-static flag to stop us from building static libs. +AC_ARG_ENABLE(static, +[ --enable-static build static libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_static=no +else + libtool_enable_static=yes +fi]) +test -n "$libtool_enable_static" && enable_static="$libtool_enable_static" +libtool_static= +test "$enable_static" = no && libtool_static=" --disable-static" + +libtool_flags="$libtool_shared$libtool_static" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +[case "$host" in +*-*-irix6*) + ac_save_CFLAGS="$CFLAGS" + flag_passed=no + for f in -32 -64 -n32 ABI -cckr -mips1 -mips2 -mips3 -mips4; do + case "$f" in + ABI) + test -n "$SGI_ABI" && flag_passed=yes + if test "$flag_passed" = no && test "$ac_cv_prog_gcc" = yes; then + # Choose the ABI flag according to GCC's specs. + if $CC -dumpspecs 2>&1 | sed '/^\*link:$/,/^$/!d' | egrep -e '[ ]-32' >/dev/null; then + LD="${LD-ld} -32" + else + LD="${LD-ld} -n32" + fi + fi + ;; + + *) + if echo " $CC $CFLAGS " | egrep -e "[ ]$f[ ]" > /dev/null; then + flag_passed=yes + LD="${LD-ld} $f" + fi + ;; + esac + done + CFLAGS="$ac_save_CFLAGS" + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + CFLAGS="$CFLAGS -belf" + ;; +esac] + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) +]) + +# AM_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AM_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC]) +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_SUBST(LD) +AM_PROG_LD_GNU +]) + +AC_DEFUN(AM_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AM_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AM_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[case "$NM" in +/*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +AC_SUBST(NM) +]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# serial 1 + +AC_DEFUN(AM_MAINTAINER_MODE, +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT($USE_MAINTAINER_MODE) + if test $USE_MAINTAINER_MODE = yes; then + MAINT= + else + MAINT='#M#' + fi + AC_SUBST(MAINT)dnl +] +) + + +# serial 1 + +# @defmac AC_PROG_CC_STDC +# @maindex PROG_CC_STDC +# @ovindex CC +# If the C compiler in not in ANSI C mode by default, try to add an option +# to output variable @code{CC} to make it so. This macro tries various +# options that select ANSI C on some system or another. It considers the +# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and +# handles function prototypes correctly. +# +# If you use this macro, you should check after calling it whether the C +# compiler has been set to accept ANSI C; if not, the shell variable +# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source +# code in ANSI C, you can make an un-ANSIfied copy of it by using the +# program @code{ansi2knr}, which comes with Ghostscript. +# @end defmac + +AC_DEFUN(AM_PROG_CC_STDC, +[AC_REQUIRE([AC_PROG_CC]) +AC_BEFORE([$0], [AC_C_INLINE]) +AC_BEFORE([$0], [AC_C_CONST]) +AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C) +AC_CACHE_VAL(am_cv_prog_cc_stdc, +[am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + AC_TRY_COMPILE( +[#if !defined(__STDC__) || __STDC__ != 1 +choke me +#endif +/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */ +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/stat.h> +#endif +], [ +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);};], +[am_cv_prog_cc_stdc="$ac_arg"; break]) +done +CC="$ac_save_CC" +]) +if test -z "$am_cv_prog_cc_stdc"; then + AC_MSG_RESULT([none needed]) +else + AC_MSG_RESULT($am_cv_prog_cc_stdc) +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac +]) + diff --git a/glib/config.guess b/glib/config.guess new file mode 100755 index 0000000000..413ed41c0f --- /dev/null +++ b/glib/config.guess @@ -0,0 +1,883 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# +# This file 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. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner <bothner@cygnus.com>. +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <<EOF >dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[3478]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;; + 9000/8?? ) HP_ARCH=hppa1.0 ;; + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo i386-pc-cygwin32 + exit 0 ;; + i*:MINGW*:*) + echo i386-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <<EOF >dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c <<EOF +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c <<EOF +#include <features.h> +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/glib/config.sub b/glib/config.sub new file mode 100755 index 0000000000..213a6d47d6 --- /dev/null +++ b/glib/config.sub @@ -0,0 +1,954 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[3456]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[3456]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/glib/configure b/glib/configure new file mode 100755 index 0000000000..becb1c7034 --- /dev/null +++ b/glib/configure @@ -0,0 +1,2921 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# 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-gnu-ld assume the C compiler uses GNU ld [default=no]" +ac_help="$ac_help + --enable-shared build shared libraries [default=yes]" +ac_help="$ac_help + --enable-static build static libraries [default=yes]" +ac_help="$ac_help + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer" +ac_help="$ac_help + --enable-debug turn on debugging [default=no]" +ac_help="$ac_help + --enable-ansi turn on strict ansi [default=no]" + +# 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= +# 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.12" + 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=glib.h + +# 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 $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +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 + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; 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 $srcdir $srcdir/.. $srcdir/../.." 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. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:566: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + + +PACKAGE=glib + +VERSION=971109 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <<EOF +#define PACKAGE "$PACKAGE" +EOF + +cat >> confdefs.h <<EOF +#define VERSION "$VERSION" +EOF + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:635: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +missing_dir=`cd $ac_aux_dir && pwd` +echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 +echo "configure:682: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:695: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:708: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:721: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:734: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:747: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +# Specify a configuration file + + + + + +# Make sure we can run config.sub. +if $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:786: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$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=`$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 + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:809: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# 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:838: 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="${IFS}:" + for ac_dir in $PATH; 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:867: 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="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; 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 + + 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:915: 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 $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <<EOF +#line 925 "configure" +#include "confdefs.h" +main(){return(0);} +EOF +if { (eval echo configure:929: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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* + +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:949: 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:954: 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 <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:963: \"$ac_try\") 1>&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 + 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:978: 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 + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + + +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 +echo "configure:1018: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 +echo "configure:1036: checking for GNU ld" >&5 +else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 +echo "configure:1039: checking for non-GNU ld" >&5 +fi +if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$ac_cv_path_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } + +echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 +echo "configure:1075: checking if the linker ($LD) is GNU ld" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6 + + +echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 +echo "configure:1091: checking for BSD-compatible nm" >&5 +if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$NM" in +/*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac +fi + +NM="$ac_cv_path_NM" +echo "$ac_t""$NM" 1>&6 + + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:1126: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + + + + + + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + if test "$enableval" = no; then + libtool_enable_shared=no +else + libtool_enable_shared=yes +fi +fi + +test -n "$libtool_enable_shared" && enable_shared="$libtool_enable_shared" +libtool_shared= +test "$enable_shared" = no && libtool_shared=" --disable-shared" + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + if test "$enableval" = no; then + libtool_enable_static=no +else + libtool_enable_static=yes +fi +fi + +test -n "$libtool_enable_static" && enable_static="$libtool_enable_static" +libtool_static= +test "$enable_static" = no && libtool_static=" --disable-static" + +libtool_flags="$libtool_shared$libtool_static" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$host" in +*-*-irix6*) + ac_save_CFLAGS="$CFLAGS" + flag_passed=no + for f in -32 -64 -n32 ABI -cckr -mips1 -mips2 -mips3 -mips4; do + case "$f" in + ABI) + test -n "$SGI_ABI" && flag_passed=yes + if test "$flag_passed" = no && test "$ac_cv_prog_gcc" = yes; then + # Choose the ABI flag according to GCC's specs. + if $CC -dumpspecs 2>&1 | sed '/^\*link:$/,/^$/!d' | egrep -e '[ ]-32' >/dev/null; then + LD="${LD-ld} -32" + else + LD="${LD-ld} -n32" + fi + fi + ;; + + *) + if echo " $CC $CFLAGS " | egrep -e "[ ]$f[ ]" > /dev/null; then + flag_passed=yes + LD="${LD-ld} $f" + fi + ;; + esac + done + CFLAGS="$ac_save_CFLAGS" + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + CFLAGS="$CFLAGS -belf" + ;; +esac + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| { echo "configure: error: libtool configure failed" 1>&2; exit 1; } + + +echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 +echo "configure:1236: checking whether to enable maintainer-specific portions of Makefiles" >&5 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6 + if test $USE_MAINTAINER_MODE = yes; then + MAINT= + else + MAINT='#M#' + fi + + + + +# Make sure we can run config.sub. +if $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:1261: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$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=`$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 + + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + if eval "test x$enable_debug = xyes"; then + DEBUGFLAG="-g" +fi +fi + + +# Check whether --enable-ansi or --disable-ansi was given. +if test "${enable_ansi+set}" = set; then + enableval="$enable_ansi" + : +else + enable_ansi=no +fi + + +if test -n "$DEBUGFLAG"; then + CFLAGS="$DEBUGFLAG" +fi + +# Checks for programs. +# 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:1308: 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="${IFS}:" + for ac_dir in $PATH; 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:1337: 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="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; 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 + + 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:1385: 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 $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <<EOF +#line 1395 "configure" +#include "confdefs.h" +main(){return(0);} +EOF +if { (eval echo configure:1399: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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* + +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:1419: 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:1424: 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 <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1433: \"$ac_try\") 1>&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 + 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:1448: 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 + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + + + + +echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6 +echo "configure:1479: checking for ${CC-cc} option to accept ANSI C" >&5 +if eval "test \"`echo '$''{'am_cv_prog_cc_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + cat > conftest.$ac_ext <<EOF +#line 1495 "configure" +#include "confdefs.h" +#if !defined(__STDC__) || __STDC__ != 1 +choke me +#endif +/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */ +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/stat.h> +#endif + +int main() { + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +; return 0; } +EOF +if { (eval echo configure:1513: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + am_cv_prog_cc_stdc="$ac_arg"; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done +CC="$ac_save_CC" + +fi + +if test -z "$am_cv_prog_cc_stdc"; then + echo "$ac_t""none needed" 1>&6 +else + echo "$ac_t""$am_cv_prog_cc_stdc" 1>&6 +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1547: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +if eval "test x$GCC = xyes"; then + test `echo "$CFLAGS" | grep "\-Wall" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -Wall" + fi + + if eval "test x$enable_ansi = xyes"; then + test `echo "$CFLAGS" | grep "\-ansi" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -ansi" + fi + + test `echo "$CFLAGS" | grep "\-pedantic" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -pedantic" + fi + fi +fi + +# Checks for header files. +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1618: 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 <<EOF +#line 1633 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1639: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +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 <<EOF +#line 1650 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1656: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +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* + 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 ANSI C header files""... $ac_c" 1>&6 +echo "configure:1679: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1684 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1692: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1709 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1727 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 1748 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1759: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + + +# Checks for library functions. +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:1785: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1790 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char vprintf(); below. */ +#include <assert.h> +/* 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 vprintf(); + +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_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1813: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:1837: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1842 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt(); below. */ +#include <assert.h> +/* 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 _doprnt(); + +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__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1865: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + + +echo $ac_n "checking size of char""... $ac_c" 1>&6 +echo "configure:1891: checking size of char" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_char'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1899 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(char)); + exit(0); +} +EOF +if { (eval echo configure:1910: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_char=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_char=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_char" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_CHAR $ac_cv_sizeof_char +EOF + + +echo $ac_n "checking size of short""... $ac_c" 1>&6 +echo "configure:1930: checking size of short" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1938 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(short)); + exit(0); +} +EOF +if { (eval echo configure:1949: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_short=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_short=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_short" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +EOF + + +echo $ac_n "checking size of long""... $ac_c" 1>&6 +echo "configure:1969: checking size of long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1977 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(long)); + exit(0); +} +EOF +if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_LONG $ac_cv_sizeof_long +EOF + + +echo $ac_n "checking size of int""... $ac_c" 1>&6 +echo "configure:2008: checking size of int" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2016 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(int)); + exit(0); +} +EOF +if { (eval echo configure:2027: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_INT $ac_cv_sizeof_int +EOF + + +echo $ac_n "checking size of void *""... $ac_c" 1>&6 +echo "configure:2047: checking size of void *" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_void_p'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2055 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(void *)); + exit(0); +} +EOF +if { (eval echo configure:2066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_void_p=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_void_p=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_void_p" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_VOID_P $ac_cv_sizeof_void_p +EOF + + + +echo $ac_n "checking for long double""... $ac_c" 1>&6 +echo "configure:2087: checking for long double" >&5 +if eval "test \"`echo '$''{'ac_cv_c_long_double'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$GCC" = yes; then + ac_cv_c_long_double=yes +else +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2098 "configure" +#include "confdefs.h" +int main() { +/* The Stardent Vistra knows sizeof(long double), but does not support it. */ +long double foo = 0.0; +/* On Ultrix 4.3 cc, long double is 4 and double is 8. */ +exit(sizeof(long double) < sizeof(double)); } +EOF +if { (eval echo configure:2106: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_c_long_double=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_long_double=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_long_double" 1>&6 +if test $ac_cv_c_long_double = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_LONG_DOUBLE 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2130: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2135 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2184: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:2205: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <<EOF +#line 2212 "configure" +#include "confdefs.h" + +int main() { +} $ac_kw foo() { +; return 0; } +EOF +if { (eval echo configure:2219: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <<EOF +#define inline $ac_cv_c_inline +EOF + ;; +esac + + +for ac_hdr in float.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2249: 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 +#line 2254 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2259: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +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 <<EOF +#define $ac_tr_hdr 1 +EOF + cat >> confdefs.h <<\EOF +#define HAVE_FLOAT_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in limits.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2292: 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 +#line 2297 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2302: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +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 <<EOF +#define $ac_tr_hdr 1 +EOF + cat >> confdefs.h <<\EOF +#define HAVE_LIMITS_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in values.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2335: 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 +#line 2340 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2345: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +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 <<EOF +#define $ac_tr_hdr 1 +EOF + cat >> confdefs.h <<\EOF +#define HAVE_VALUES_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +# Check for strerror and strsignal functions +for ac_func in strerror strsignal +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2379: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2384 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* 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 $ac_func(); + +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_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2407: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +# Check for sys_errlist +echo $ac_n "checking sys_errlist""... $ac_c" 1>&6 +echo "configure:2434: checking sys_errlist" >&5 +cat > conftest.$ac_ext <<EOF +#line 2436 "configure" +#include "confdefs.h" + +int main() { + +extern char *sys_errlist[]; +extern int sys_nerr; +sys_errlist[sys_nerr-1][0] = 0; + +; return 0; } +EOF +if { (eval echo configure:2447: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + glib_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + glib_ok=no +fi +rm -f conftest* +echo "$ac_t""$glib_ok" 1>&6 +if test $glib_ok = no; then + cat >> confdefs.h <<\EOF +#define NO_SYS_ERRLIST 1 +EOF + +fi + +# Check for sys_siglist +echo $ac_n "checking sys_siglist""... $ac_c" 1>&6 +echo "configure:2467: checking sys_siglist" >&5 +cat > conftest.$ac_ext <<EOF +#line 2469 "configure" +#include "confdefs.h" + +int main() { + +extern char *sys_siglist[]; +sys_siglist[1][0] = 0; + +; return 0; } +EOF +if { (eval echo configure:2479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + glib_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + glib_ok=no +fi +rm -f conftest* +echo "$ac_t""$glib_ok" 1>&6 +if test $glib_ok = no; then + cat >> confdefs.h <<\EOF +#define NO_SYS_SIGLIST 1 +EOF + +fi + +# Check for sys/select.h + +echo $ac_n "checking fd_set and sys/select""... $ac_c" 1>&6 +echo "configure:2500: checking fd_set and sys/select" >&5 +cat > conftest.$ac_ext <<EOF +#line 2502 "configure" +#include "confdefs.h" +#include <sys/types.h> +int main() { +fd_set readMask, writeMask; +; return 0; } +EOF +if { (eval echo configure:2509: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + gtk_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gtk_ok=no +fi +rm -f conftest* +if test $gtk_ok = no; then + cat > conftest.$ac_ext <<EOF +#line 2521 "configure" +#include "confdefs.h" +#include <sys/select.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "fd_mask" >/dev/null 2>&1; then + rm -rf conftest* + gtk_ok=yes +fi +rm -f conftest* + + if test $gtk_ok = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_SELECT_H 1 +EOF + + fi +fi +echo "$ac_t""$gtk_ok" 1>&6 +if test $gtk_ok = no; then + cat >> confdefs.h <<\EOF +#define NO_FD_SET 1 +EOF + +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) 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 <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/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.12" + 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 +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile glibconfig.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%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%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%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%@RANLIB@%$RANLIB%g +s%@CC@%$CC%g +s%@LD@%$LD%g +s%@NM@%$NM%g +s%@LN_S@%$LN_S%g +s%@LIBTOOL@%$LIBTOOL%g +s%@MAINT@%$MAINT%g +s%@CPP@%$CPP%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 <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile"} +EOF +cat >> $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 + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + 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 +s%@INSTALL@%$INSTALL%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 <<EOF + CONFIG_HEADERS="glibconfig.h" +EOF +cat >> $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 <<CEOF' >> $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 <<EOF + + +EOF +cat >> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +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/glib/configure.in b/glib/configure.in new file mode 100644 index 0000000000..d97b441bce --- /dev/null +++ b/glib/configure.in @@ -0,0 +1,116 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(glib.h) + +dnl Initialize automake stuff +AM_INIT_AUTOMAKE(glib, 971109) + +# Specify a configuration file +AM_CONFIG_HEADER(glibconfig.h) + +dnl Initialize libtool +AM_PROG_LIBTOOL + +dnl Initialize maintainer mode +AM_MAINTAINER_MODE + +AC_CANONICAL_HOST + +AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]], +if eval "test x$enable_debug = xyes"; then + DEBUGFLAG="-g" +fi) + +AC_ARG_ENABLE(ansi, [ --enable-ansi turn on strict ansi [default=no]], + , enable_ansi=no) + +if test -n "$DEBUGFLAG"; then + CFLAGS="$DEBUGFLAG" +fi + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_STDC +AC_PROG_INSTALL + +if eval "test x$GCC = xyes"; then + test `echo "$CFLAGS" | grep "\-Wall" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -Wall" + fi + + if eval "test x$enable_ansi = xyes"; then + test `echo "$CFLAGS" | grep "\-ansi" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -ansi" + fi + + test `echo "$CFLAGS" | grep "\-pedantic" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -pedantic" + fi + fi +fi + +# Checks for header files. +AC_HEADER_STDC + +# Checks for library functions. +AC_FUNC_VPRINTF + +AC_CHECK_SIZEOF(char) +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(void *) + +AC_C_LONG_DOUBLE +AC_C_CONST +AC_C_INLINE + +AC_CHECK_HEADERS(float.h, AC_DEFINE(HAVE_FLOAT_H)) +AC_CHECK_HEADERS(limits.h, AC_DEFINE(HAVE_LIMITS_H)) +AC_CHECK_HEADERS(values.h, AC_DEFINE(HAVE_VALUES_H)) + +# Check for strerror and strsignal functions +AC_CHECK_FUNCS(strerror strsignal) + +# Check for sys_errlist +AC_MSG_CHECKING(sys_errlist) +AC_TRY_LINK(, [ +extern char *sys_errlist[]; +extern int sys_nerr; +sys_errlist[sys_nerr-1][0] = 0; +], glib_ok=yes, glib_ok=no) +AC_MSG_RESULT($glib_ok) +if test $glib_ok = no; then + AC_DEFINE(NO_SYS_ERRLIST) +fi + +# Check for sys_siglist +AC_MSG_CHECKING(sys_siglist) +AC_TRY_LINK(, [ +extern char *sys_siglist[]; +sys_siglist[1][0] = 0; +], glib_ok=yes, glib_ok=no) +AC_MSG_RESULT($glib_ok) +if test $glib_ok = no; then + AC_DEFINE(NO_SYS_SIGLIST) +fi + +# Check for sys/select.h + +AC_MSG_CHECKING([fd_set and sys/select]) +AC_TRY_COMPILE([#include <sys/types.h>], + [fd_set readMask, writeMask;], gtk_ok=yes, gtk_ok=no) +if test $gtk_ok = no; then + AC_HEADER_EGREP(fd_mask, sys/select.h, gtk_ok=yes) + if test $gtk_ok = yes; then + AC_DEFINE(HAVE_SYS_SELECT_H) + fi +fi +AC_MSG_RESULT($gtk_ok) +if test $gtk_ok = no; then + AC_DEFINE(NO_FD_SET) +fi + +AC_OUTPUT(Makefile) diff --git a/glib/garray.c b/glib/garray.c new file mode 100644 index 0000000000..3700848439 --- /dev/null +++ b/glib/garray.c @@ -0,0 +1,142 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include "glib.h" + + +#define MIN_ARRAY_SIZE 16 + + +typedef struct _GRealArray GRealArray; + +struct _GRealArray +{ + guint8 *data; + guint len; + guint alloc; + guint zero_terminated; +}; + + +static gint g_nearest_pow (gint num); +static void g_array_maybe_expand (GRealArray *array, + gint len); + + +static GMemChunk *array_mem_chunk = NULL; + + +GArray* +g_array_new (zero_terminated) +{ + GRealArray *array; + + if (!array_mem_chunk) + array_mem_chunk = g_mem_chunk_new ("array mem chunk", + sizeof (GRealArray), + 1024, G_ALLOC_AND_FREE); + + array = g_chunk_new (GRealArray, array_mem_chunk); + + array->data = NULL; + array->len = 0; + array->alloc = 0; + array->zero_terminated = (zero_terminated ? 1 : 0); + + return (GArray*) array; +} + +void +g_array_free (GArray *array, + gint free_segment) +{ + if (free_segment) + g_free (array->data); + + g_mem_chunk_free (array_mem_chunk, array); +} + +GArray* +g_rarray_append (GArray *array, + gpointer data, + gint size) +{ + g_array_maybe_expand ((GRealArray*) array, size); + + memcpy (array->data + array->len, data, size); + + array->len += size; + + return array; +} + +GArray* +g_rarray_prepend (GArray *array, + gpointer data, + gint size) +{ + g_array_maybe_expand ((GRealArray*) array, size); + + memmove (array->data + size, array->data, array->len); + memcpy (array->data, data, size); + + array->len += size; + + return array; +} + +GArray* +g_rarray_truncate (GArray *array, + gint length, + gint size) +{ + if (array->data) + memset (array->data + length * size, 0, size); + array->len = length; + return array; +} + + +static gint +g_nearest_pow (gint num) +{ + gint n = 1; + + while (n < num) + n <<= 1; + + return n; +} + +static void +g_array_maybe_expand (GRealArray *array, + gint len) +{ + guint old_alloc; + + if ((array->len + len) > array->alloc) + { + old_alloc = array->alloc; + + array->alloc = g_nearest_pow (array->len + array->zero_terminated + len); + array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE); + array->data = g_realloc (array->data, array->alloc); + + memset (array->data + old_alloc, 0, array->alloc - old_alloc); + } +} diff --git a/glib/gcache.c b/glib/gcache.c new file mode 100644 index 0000000000..b121219952 --- /dev/null +++ b/glib/gcache.c @@ -0,0 +1,211 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "glib.h" + + +typedef struct _GCacheNode GCacheNode; +typedef struct _GRealCache GRealCache; + +struct _GCacheNode +{ + /* A reference counted node */ + gpointer value; + gint ref_count; +}; + +struct _GRealCache +{ + /* Called to create a value from a key */ + GCacheNewFunc value_new_func; + + /* Called to destroy a value */ + GCacheDestroyFunc value_destroy_func; + + /* Called to duplicate a key */ + GCacheDupFunc key_dup_func; + + /* Called to destroy a key */ + GCacheDestroyFunc key_destroy_func; + + /* Associates keys with nodes */ + GHashTable *key_table; + + /* Associates nodes with keys */ + GHashTable *value_table; +}; + + +static GCacheNode* g_cache_node_new (gpointer value); +static void g_cache_node_destroy (GCacheNode *node); + + +static GMemChunk *node_mem_chunk = NULL; + + +GCache* +g_cache_new (GCacheNewFunc value_new_func, + GCacheDestroyFunc value_destroy_func, + GCacheDupFunc key_dup_func, + GCacheDestroyFunc key_destroy_func, + GHashFunc hash_key_func, + GHashFunc hash_value_func, + GCompareFunc key_compare_func) +{ + GRealCache *cache; + + g_return_val_if_fail (value_new_func != NULL, NULL); + g_return_val_if_fail (value_destroy_func != NULL, NULL); + g_return_val_if_fail (key_dup_func != NULL, NULL); + g_return_val_if_fail (key_destroy_func != NULL, NULL); + g_return_val_if_fail (hash_key_func != NULL, NULL); + g_return_val_if_fail (hash_value_func != NULL, NULL); + g_return_val_if_fail (key_compare_func != NULL, NULL); + + cache = g_new (GRealCache, 1); + cache->value_new_func = value_new_func; + cache->value_destroy_func = value_destroy_func; + cache->key_dup_func = key_dup_func; + cache->key_destroy_func = key_destroy_func; + cache->key_table = g_hash_table_new (hash_key_func, key_compare_func); + cache->value_table = g_hash_table_new (hash_value_func, NULL); + + return (GCache*) cache; +} + +void +g_cache_destroy (GCache *cache) +{ + GRealCache *rcache; + + g_return_if_fail (cache != NULL); + + rcache = (GRealCache*) cache; + g_hash_table_destroy (rcache->key_table); + g_hash_table_destroy (rcache->value_table); + g_free (rcache); +} + +gpointer +g_cache_insert (GCache *cache, + gpointer key) +{ + GRealCache *rcache; + GCacheNode *node; + gpointer value; + + g_return_val_if_fail (cache != NULL, NULL); + + rcache = (GRealCache*) cache; + + node = g_hash_table_lookup (rcache->key_table, key); + if (node) + { + node->ref_count += 1; + return node->value; + } + + key = (* rcache->key_dup_func) (key); + value = (* rcache->value_new_func) (key); + node = g_cache_node_new (value); + + g_hash_table_insert (rcache->key_table, key, node); + g_hash_table_insert (rcache->value_table, value, key); + + return node->value; +} + +void +g_cache_remove (GCache *cache, + gpointer value) +{ + GRealCache *rcache; + GCacheNode *node; + gpointer key; + + g_return_if_fail (cache != NULL); + + rcache = (GRealCache*) cache; + + key = g_hash_table_lookup (rcache->value_table, value); + node = g_hash_table_lookup (rcache->key_table, key); + + node->ref_count -= 1; + if (node->ref_count == 0) + { + g_hash_table_remove (rcache->value_table, value); + g_hash_table_remove (rcache->key_table, key); + + (* rcache->key_destroy_func) (key); + (* rcache->value_destroy_func) (node->value); + g_cache_node_destroy (node); + } +} + +void +g_cache_key_foreach (GCache *cache, + GHFunc func, + gpointer user_data) +{ + GRealCache *rcache; + + g_return_if_fail (cache != NULL); + g_return_if_fail (func != NULL); + + rcache = (GRealCache*) cache; + + g_hash_table_foreach (rcache->value_table, func, user_data); +} + +void +g_cache_value_foreach (GCache *cache, + GHFunc func, + gpointer user_data) +{ + GRealCache *rcache; + + g_return_if_fail (cache != NULL); + g_return_if_fail (func != NULL); + + rcache = (GRealCache*) cache; + + g_hash_table_foreach (rcache->key_table, func, user_data); +} + + +static GCacheNode* +g_cache_node_new (gpointer value) +{ + GCacheNode *node; + + if (!node_mem_chunk) + node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode), + 1024, G_ALLOC_AND_FREE); + + node = g_chunk_new (GCacheNode, node_mem_chunk); + + node->value = value; + node->ref_count = 1; + + return node; +} + +static void +g_cache_node_destroy (GCacheNode *node) +{ + g_mem_chunk_free (node_mem_chunk, node); +} diff --git a/glib/gerror.c b/glib/gerror.c new file mode 100644 index 0000000000..96e1013e94 --- /dev/null +++ b/glib/gerror.c @@ -0,0 +1,256 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/types.h> + +#include <time.h> +#include <unistd.h> +#include "glib.h" + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif /* HAVE_SYS_SELECT_H */ + +#ifdef STDC_HEADERS +#include <string.h> /* for bzero on BSD systems */ +#endif + +#define INTERACTIVE 0 +#define STACK_TRACE 1 + + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else +# ifndef _AIX + typedef long fd_mask; +# endif +# if defined(_IBMR2) +# define SELECT_MASK void +# else +# define SELECT_MASK int +# endif +#endif + + +static int do_query (char *prompt); +static void debug (char *progname, int method); +static void stack_trace (char **); +static void stack_trace_sigchld (int); + + +static int stack_trace_done; + +void +g_debug (char *progname) +{ + char buf[32]; + + fprintf (stdout, "[n]othing, [e]xit, [s]tack trace, [a]ttach to process: "); + fflush (stdout); + + fgets (buf, 32, stdin); + if (strcmp (buf, "n\n") == 0) + return; + else if (strcmp (buf, "s\n") == 0) + debug (progname, STACK_TRACE); + else if (strcmp (buf, "a\n") == 0) + debug (progname, INTERACTIVE); + else + exit (0); +} + +void +g_attach_process (char *progname, int query) +{ + if (!query || do_query ("attach to process")) + debug (progname, INTERACTIVE); +} + +void +g_stack_trace (char *progname, int query) +{ + if (!query || do_query ("print stack trace")) + debug (progname, STACK_TRACE); +} + +static int +do_query (char *prompt) +{ + char buf[32]; + + fprintf (stdout, "%s (y/n) ", prompt); + fflush (stdout); + + fgets (buf, 32, stdin); + if ((strcmp (buf, "yes\n") == 0) || + (strcmp (buf, "y\n") == 0) || + (strcmp (buf, "YES\n") == 0) || + (strcmp (buf, "Y\n") == 0)) + return TRUE; + + return FALSE; +} + +static void +debug (char *progname, + int method) +{ + pid_t pid; + char buf[16]; + char *args[4] = { "gdb", NULL, NULL, NULL }; + volatile int x; + + sprintf (buf, "%d", (int) getpid ()); + + args[1] = progname; + args[2] = buf; + + switch (method) + { + case INTERACTIVE: + fprintf (stdout, "pid: %s\n", buf); + break; + case STACK_TRACE: + pid = fork (); + if (pid == 0) + { + stack_trace (args); + _exit (0); + } + else if (pid == (pid_t) -1) + { + perror ("could not fork"); + return; + } + break; + } + + x = 1; + while (x) + ; +} + +static void +stack_trace (char **args) +{ + pid_t pid; + int in_fd[2]; + int out_fd[2]; + SELECT_MASK fdset; + SELECT_MASK readset; + struct timeval tv; + int sel, index, state; + char buffer[256]; + char c; + + stack_trace_done = 0; + signal (SIGCHLD, stack_trace_sigchld); + + if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1)) + { + perror ("could open pipe"); + _exit (0); + } + + pid = fork (); + if (pid == 0) + { + close (0); dup (in_fd[0]); /* set the stdin to the in pipe */ + close (1); dup (out_fd[1]); /* set the stdout to the out pipe */ + close (2); dup (out_fd[1]); /* set the stderr to the out pipe */ + + execvp (args[0], args); /* exec gdb */ + perror ("exec failed"); + _exit (0); + } + else if (pid == (pid_t) -1) + { + perror ("could not fork"); + _exit (0); + } + + FD_ZERO (&fdset); + FD_SET (out_fd[0], &fdset); + + write (in_fd[1], "backtrace\n", 10); + write (in_fd[1], "p x = 0\n", 8); + write (in_fd[1], "quit\n", 5); + + index = 0; + state = 0; + + while (1) + { + readset = fdset; + tv.tv_sec = 1; + tv.tv_usec = 0; + + sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv); + if (sel == -1) + break; + + if ((sel > 0) && (FD_ISSET (out_fd[0], &readset))) + { + if (read (out_fd[0], &c, 1)) + { + switch (state) + { + case 0: + if (c == '#') + { + state = 1; + index = 0; + buffer[index++] = c; + } + break; + case 1: + buffer[index++] = c; + if ((c == '\n') || (c == '\r')) + { + buffer[index] = 0; + fprintf (stdout, "%s", buffer); + state = 0; + index = 0; + } + break; + default: + break; + } + } + } + else if (stack_trace_done) + break; + } + + close (in_fd[0]); + close (in_fd[1]); + close (out_fd[0]); + close (out_fd[1]); + _exit (0); +} + +static void +stack_trace_sigchld (int signum) +{ + stack_trace_done = 1; +} diff --git a/glib/ghash.c b/glib/ghash.c new file mode 100644 index 0000000000..ed736d4cb7 --- /dev/null +++ b/glib/ghash.c @@ -0,0 +1,418 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "glib.h" + + +#define HASH_TABLE_MIN_SIZE 11 +#define HASH_TABLE_MAX_SIZE 13845163 + + +typedef struct _GHashNode GHashNode; +typedef struct _GRealHashTable GRealHashTable; + +struct _GHashNode +{ + gpointer key; + gpointer value; + GHashNode *next; +}; + +struct _GRealHashTable +{ + gint size; + gint nnodes; + gint frozen; + GHashNode **nodes; + GHashFunc hash_func; + GCompareFunc key_compare_func; +}; + + +static void g_hash_table_resize (GHashTable *hash_table); +static gint g_hash_closest_prime (gint num); +static GHashNode* g_hash_node_new (gpointer key, + gpointer value); +static void g_hash_node_destroy (GHashNode *hash_node); +static void g_hash_nodes_destroy (GHashNode *hash_node); + + +extern gint g_primes[]; +extern gint g_nprimes; + +static GMemChunk *node_mem_chunk = NULL; +static GHashNode *node_free_list = NULL; + + +GHashTable* +g_hash_table_new (GHashFunc hash_func, + GCompareFunc key_compare_func) +{ + GRealHashTable *hash_table; + + g_return_val_if_fail (hash_func != NULL, NULL); + + hash_table = g_new (GRealHashTable, 1); + hash_table->size = 0; + hash_table->nnodes = 0; + hash_table->frozen = FALSE; + hash_table->nodes = NULL; + hash_table->hash_func = hash_func; + hash_table->key_compare_func = key_compare_func; + + return ((GHashTable*) hash_table); +} + +void +g_hash_table_destroy (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + gint i; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + for (i = 0; i < rhash_table->size; i++) + g_hash_nodes_destroy (rhash_table->nodes[i]); + + if (rhash_table->nodes) + g_free (rhash_table->nodes); + g_free (rhash_table); + } +} + +void +g_hash_table_insert (GHashTable *hash_table, + gpointer key, + gpointer value) +{ + GRealHashTable *rhash_table; + GHashNode *node; + guint hash_val; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + if (rhash_table->size == 0) + g_hash_table_resize (hash_table); + + hash_val = (* rhash_table->hash_func) (key) % rhash_table->size; + + node = rhash_table->nodes[hash_val]; + while (node) + { + if ((rhash_table->key_compare_func && + (* rhash_table->key_compare_func) (node->key, key)) || + (node->key == key)) + { + node->value = value; + return; + } + node = node->next; + } + + node = g_hash_node_new (key, value); + node->next = rhash_table->nodes[hash_val]; + rhash_table->nodes[hash_val] = node; + + rhash_table->nnodes += 1; + g_hash_table_resize (hash_table); + } +} + +void +g_hash_table_remove (GHashTable *hash_table, + gpointer key) +{ + GRealHashTable *rhash_table; + GHashNode *node; + GHashNode *prev; + guint hash_val; + + rhash_table = (GRealHashTable*) hash_table; + if (hash_table && rhash_table->size) + { + hash_val = (* rhash_table->hash_func) (key) % rhash_table->size; + + prev = NULL; + node = rhash_table->nodes[hash_val]; + + while (node) + { + if ((rhash_table->key_compare_func && + (* rhash_table->key_compare_func) (node->key, key)) || + (node->key == key)) + { + if (prev) + prev->next = node->next; + if (node == rhash_table->nodes[hash_val]) + rhash_table->nodes[hash_val] = node->next; + + g_hash_node_destroy (node); + + rhash_table->nnodes -= 1; + g_hash_table_resize (hash_table); + break; + } + + prev = node; + node = node->next; + } + } +} + +gpointer +g_hash_table_lookup (GHashTable *hash_table, + const gpointer key) +{ + GRealHashTable *rhash_table; + GHashNode *node; + guint hash_val; + + rhash_table = (GRealHashTable*) hash_table; + if (hash_table && rhash_table->size) + { + hash_val = (* rhash_table->hash_func) (key) % rhash_table->size; + + node = rhash_table->nodes[hash_val]; + + /* Hash table lookup needs to be fast. + * We therefore remove the extra conditional of testing + * whether to call the key_compare_func or not from + * the inner loop. + */ + if (rhash_table->key_compare_func) + { + while (node) + { + if ((* rhash_table->key_compare_func) (node->key, key)) + return node->value; + node = node->next; + } + } + else + { + while (node) + { + if (node->key == key) + return node->value; + node = node->next; + } + } + } + + return NULL; +} + +void +g_hash_table_freeze (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + rhash_table->frozen = TRUE; + } +} + +void +g_hash_table_thaw (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + rhash_table->frozen = FALSE; + + g_hash_table_resize (hash_table); + } +} + +void +g_hash_table_foreach (GHashTable *hash_table, + GHFunc func, + gpointer user_data) +{ + GRealHashTable *rhash_table; + GHashNode *node; + gint i; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + for (i = 0; i < rhash_table->size; i++) + { + node = rhash_table->nodes[i]; + + while (node) + { + (* func) (node->key, node->value, user_data); + node = node->next; + } + } + } +} + + +static void +g_hash_table_resize (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + GHashNode **new_nodes; + GHashNode *node; + GHashNode *next; + gfloat nodes_per_list; + guint hash_val; + gint new_size; + gint need_resize; + gint i; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + if (rhash_table->size == 0) + { + rhash_table->size = HASH_TABLE_MIN_SIZE; + rhash_table->nodes = g_new (GHashNode*, rhash_table->size); + + for (i = 0; i < rhash_table->size; i++) + rhash_table->nodes[i] = NULL; + } + else if (!rhash_table->frozen) + { + need_resize = FALSE; + nodes_per_list = (gfloat) rhash_table->nnodes / (gfloat) rhash_table->size; + + if (nodes_per_list < 0.3) + { + if (rhash_table->size > HASH_TABLE_MIN_SIZE) + need_resize = TRUE; + } + else if (nodes_per_list > 3.0) + { + if (rhash_table->size < HASH_TABLE_MAX_SIZE) + need_resize = TRUE; + } + + if (need_resize) + { + new_size = g_hash_closest_prime (rhash_table->nnodes); + if (new_size < HASH_TABLE_MIN_SIZE) + new_size = HASH_TABLE_MIN_SIZE; + else if (new_size > HASH_TABLE_MAX_SIZE) + new_size = HASH_TABLE_MAX_SIZE; + + new_nodes = g_new (GHashNode*, new_size); + + for (i = 0; i < new_size; i++) + new_nodes[i] = NULL; + + for (i = 0; i < rhash_table->size; i++) + { + node = rhash_table->nodes[i]; + + while (node) + { + next = node->next; + + hash_val = (* rhash_table->hash_func) (node->key) % new_size; + node->next = new_nodes[hash_val]; + new_nodes[hash_val] = node; + + node = next; + } + } + + g_free (rhash_table->nodes); + + rhash_table->nodes = new_nodes; + rhash_table->size = new_size; + } + } + } +} + +static gint +g_hash_closest_prime (gint num) +{ + gint i; + + for (i = 0; i < g_nprimes; i++) + if ((g_primes[i] - num) > 0) + return g_primes[i]; + + return g_primes[g_nprimes - 1]; +} + +static GHashNode* +g_hash_node_new (gpointer key, + gpointer value) +{ + GHashNode *hash_node; + + if (node_free_list) + { + hash_node = node_free_list; + node_free_list = node_free_list->next; + } + else + { + if (!node_mem_chunk) + node_mem_chunk = g_mem_chunk_new ("hash node mem chunk", + sizeof (GHashNode), + 1024, G_ALLOC_ONLY); + + hash_node = g_chunk_new (GHashNode, node_mem_chunk); + } + + hash_node->key = key; + hash_node->value = value; + hash_node->next = NULL; + + return hash_node; +} + +static void +g_hash_node_destroy (GHashNode *hash_node) +{ + if (hash_node) + { + hash_node->next = node_free_list; + node_free_list = hash_node; + } +} + +static void +g_hash_nodes_destroy (GHashNode *hash_node) +{ + GHashNode *node; + + if (hash_node) + { + node = hash_node; + while (node->next) + node = node->next; + node->next = node_free_list; + node_free_list = hash_node; + } +} diff --git a/glib/glib.h b/glib/glib.h new file mode 100644 index 0000000000..9af5fa1bbc --- /dev/null +++ b/glib/glib.h @@ -0,0 +1,674 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __G_LIB_H__ +#define __G_LIB_H__ + + +#include <glibconfig.h> + +#ifdef USE_DMALLOC +#include "dmalloc.h" +#endif + + +/* glib provides definitions for the extrema of many + * of the standard types. These are: + * G_MINFLOAT + * G_MAXFLOAT + * G_MINDOUBLE + * G_MAXDOUBLE + * G_MINSHORT + * G_MAXSHORT + * G_MININT + * G_MAXINT + * G_MINLONG + * G_MAXLONG + */ + +#ifdef HAVE_FLOAT_H + +#include <float.h> + +#define G_MINFLOAT FLT_MIN +#define G_MAXFLOAT FLT_MAX +#define G_MINDOUBLE DBL_MIN +#define G_MAXDOUBLE DBL_MAX + +#elif HAVE_VALUES_H + +#include <values.h> + +#define G_MINFLOAT MINFLOAT +#define G_MAXFLOAT MAXFLOAT +#define G_MINDOUBLE MINDOUBLE +#define G_MAXDOUBLE MAXDOUBLE + +#endif /* HAVE_VALUES_H */ + + +#ifdef HAVE_LIMITS_H + +#include <limits.h> + +#define G_MINSHORT SHRT_MIN +#define G_MAXSHORT SHRT_MAX +#define G_MININT INT_MIN +#define G_MAXINT INT_MAX +#define G_MINLONG LONG_MIN +#define G_MAXLONG LONG_MAX + +#elif HAVE_VALUES_H + +#ifdef HAVE_FLOAT_H +#include <values.h> +#endif /* HAVE_FLOAT_H */ + +#define G_MINSHORT MINSHORT +#define G_MAXSHORT MAXSHORT +#define G_MININT MININT +#define G_MAXINT MAXINT +#define G_MINLONG MINLONG +#define G_MAXLONG MAXLONG + +#endif /* HAVE_VALUES_H */ + + +/* Provide definitions for some commonly used macros. + * These are only provided if they haven't already + * been defined. It is assumed that if they are already + * defined then the current definition is correct. + */ + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ + +#ifndef NULL +#define NULL ((void*) 0) +#endif /* NULL */ + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif /* MAX */ + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ + +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif /* ABS */ + +#ifndef CLAMP +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#endif /* CLAMP */ + +#ifndef ATEXIT +#define ATEXIT(proc) (atexit (proc)) +#endif /* ATEXIT */ + + +/* Provide macros for easily allocating memory. The macros + * will cast the allocated memory to the specified type + * in order to avoid compiler warnings. (Makes the code neater). + */ + +#ifdef __DMALLOC_H__ + +#define g_new(type,count) ALLOC(type,count) +#define g_new0(type,count) CALLOC(type,count) + +#else /* __DMALLOC_H__ */ + +#define g_new(type, count) \ + ((type *) g_malloc ((unsigned) sizeof (type) * (count))) +#define g_new0(type, count) \ + ((type *) g_malloc0 ((unsigned) sizeof (type) * (count))) +#endif /* __DMALLOC_H__ */ + +#define g_chunk_new(type, chunk) \ + ((type *) g_mem_chunk_alloc (chunk)) + + +/* Provide macros for error handling. The "assert" macros will + * exit on failur. The "return" macros will exit the current + * function. Two different definitions are given for the macros + * in order to support gcc's __PRETTY_FUNCTION__ capability. + */ + +#define g_string(x) #x + +#ifdef __GNUC__ + +#define g_assert(expr) \ + if (!(expr)) \ + g_error ("file %s: line %d (%s): \"%s\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr) + +#define g_assert_not_reached() \ + g_error ("file %s: line %d (%s): \"should not be reached\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__) + +#define g_return_if_fail(expr) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d (%s): \"%s\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + return; \ + } + +#define g_return_val_if_fail(expr,val) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d (%s): \"%s\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + return val; \ + } + +#else /* __GNUC__ */ + +#define g_assert(expr) \ + if (!(expr)) \ + g_error ("file %s: line %d: \"%s\"", \ + __FILE__, \ + __LINE__, \ + #expr) + +#define g_assert_not_reached() \ + g_error ("file %s: line %d: \"should not be reached\"", \ + __FILE__, \ + __LINE__) + +#define g_return_if_fail(expr) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d: \"%s\"", \ + __FILE__, \ + __LINE__, \ + #expr); \ + return; \ + } + +#define g_return_val_if_fail(expr, val) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d: \"%s\"", \ + __FILE__, \ + __LINE__, \ + #expr); \ + return val; \ + } + +#endif /* __GNUC__ */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Provide type definitions for commonly used types. + * These are useful because a "gint8" can be adjusted + * to be 1 byte (8 bits) on all platforms. Similarly and + * more importantly, "gint32" can be adjusted to be + * 4 bytes (32 bits) on all platforms. + */ + +typedef char gchar; +typedef short gshort; +typedef long glong; +typedef int gint; +typedef char gboolean; + +typedef unsigned char guchar; +typedef unsigned short gushort; +typedef unsigned long gulong; +typedef unsigned int guint; + +typedef float gfloat; +typedef double gdouble; + +#ifdef HAVE_LONG_DOUBLE +typedef long double gldouble; +#else /* HAVE_LONG_DOUBLE */ +typedef double gldouble; +#endif /* HAVE_LONG_DOUBLE */ + +typedef void* gpointer; + +#if (SIZEOF_CHAR == 1) +typedef signed char gint8; +typedef unsigned char guint8; +#endif /* SIZEOF_CHAR */ + + +#if (SIZEOF_SHORT == 2) +typedef signed short gint16; +typedef unsigned short guint16; +#endif /* SIZEOF_SHORT */ + + +#if (SIZEOF_INT == 4) +typedef signed int gint32; +typedef unsigned int guint32; +#elif (SIZEOF_LONG == 4) +typedef signed long gint32; +typedef unsigned long guint32; +#endif /* SIZEOF_INT */ + + +typedef struct _GList GList; +typedef struct _GSList GSList; +typedef struct _GHashTable GHashTable; +typedef struct _GCache GCache; +typedef struct _GTree GTree; +typedef struct _GTimer GTimer; +typedef struct _GMemChunk GMemChunk; +typedef struct _GListAllocator GListAllocator; +typedef struct _GStringChunk GStringChunk; +typedef struct _GString GString; +typedef struct _GArray GArray; + +typedef void (*GFunc) (gpointer data, gpointer user_data); +typedef void (*GHFunc) (gpointer key, gpointer value, gpointer user_data); +typedef guint (*GHashFunc) (gpointer key); +typedef gint (*GCompareFunc) (gpointer a, gpointer b); +typedef gpointer (*GCacheNewFunc) (gpointer key); +typedef gpointer (*GCacheDupFunc) (gpointer value); +typedef void (*GCacheDestroyFunc) (gpointer value); +typedef gint (*GTraverseFunc) (gpointer key, + gpointer value, + gpointer data); +typedef gint (*GSearchFunc) (gpointer key, + gpointer data); +typedef void (*GErrorFunc) (gchar *str); +typedef void (*GWarningFunc) (gchar *str); +typedef void (*GPrintFunc) (gchar *str); + + +struct _GList +{ + gpointer data; + GList *next; + GList *prev; +}; + +struct _GSList +{ + gpointer data; + GSList *next; +}; + +struct _GString +{ + gchar *str; + gint len; +}; + +struct _GArray +{ + gchar *data; + guint len; +}; + +struct _GHashTable { gint dummy; }; +struct _GCache { gint dummy; }; +struct _GTree { gint dummy; }; +struct _GTimer { gint dummy; }; +struct _GMemChunk { gint dummy; }; +struct _GListAllocator { gint dummy; }; +struct _GStringChunk { gint dummy; }; + +typedef enum +{ + G_IN_ORDER, + G_PRE_ORDER, + G_POST_ORDER +} GTraverseType; + +/* Doubly linked lists + */ +GList* g_list_alloc (void); +void g_list_free (GList *list); +void g_list_free_1 (GList *list); +GList* g_list_append (GList *list, + gpointer data); +GList* g_list_prepend (GList *list, + gpointer data); +GList* g_list_insert (GList *list, + gpointer data, + gint position); +GList* g_list_remove (GList *list, + gpointer data); +GList* g_list_remove_link (GList *list, + GList *link); +GList* g_list_reverse (GList *list); +GList* g_list_nth (GList *list, + gint n); +GList* g_list_find (GList *list, + gpointer data); +GList* g_list_last (GList *list); +GList* g_list_first (GList *list); +gint g_list_length (GList *list); +void g_list_foreach (GList *list, + GFunc func, + gpointer user_data); + + +/* Singly linked lists + */ +GSList* g_slist_alloc (void); +void g_slist_free (GSList *list); +void g_slist_free_1 (GSList *list); +GSList* g_slist_append (GSList *list, + gpointer data); +GSList* g_slist_prepend (GSList *list, + gpointer data); +GSList* g_slist_insert (GSList *list, + gpointer data, + gint position); +GSList* g_slist_remove (GSList *list, + gpointer data); +GSList* g_slist_remove_link (GSList *list, + GSList *link); +GSList* g_slist_reverse (GSList *list); +GSList* g_slist_nth (GSList *list, + gint n); +GSList* g_slist_find (GSList *list, + gpointer data); +GSList* g_slist_last (GSList *list); +gint g_slist_length (GSList *list); +void g_slist_foreach (GSList *list, + GFunc func, + gpointer user_data); + + +/* List Allocators + */ +GListAllocator* g_list_allocator_new (void); +void g_list_allocator_free (GListAllocator* allocator); +GListAllocator* g_slist_set_allocator (GListAllocator* allocator); +GListAllocator* g_list_set_allocator (GListAllocator* allocator); + + +/* Hash tables + */ +GHashTable* g_hash_table_new (GHashFunc hash_func, + GCompareFunc key_compare_func); +void g_hash_table_destroy (GHashTable *hash_table); +void g_hash_table_insert (GHashTable *hash_table, + gpointer key, + gpointer value); +void g_hash_table_remove (GHashTable *hash_table, + gpointer key); +gpointer g_hash_table_lookup (GHashTable *hash_table, + const gpointer key); +void g_hash_table_freeze (GHashTable *hash_table); +void g_hash_table_thaw (GHashTable *hash_table); +void g_hash_table_foreach (GHashTable *hash_table, + GHFunc func, + gpointer user_data); + + +/* Caches + */ +GCache* g_cache_new (GCacheNewFunc value_new_func, + GCacheDestroyFunc value_destroy_func, + GCacheDupFunc key_dup_func, + GCacheDestroyFunc key_destroy_func, + GHashFunc hash_key_func, + GHashFunc hash_value_func, + GCompareFunc key_compare_func); +void g_cache_destroy (GCache *cache); +gpointer g_cache_insert (GCache *cache, + gpointer key); +void g_cache_remove (GCache *cache, + gpointer value); +void g_cache_key_foreach (GCache *cache, + GHFunc func, + gpointer user_data); +void g_cache_value_foreach (GCache *cache, + GHFunc func, + gpointer user_data); + + +/* Trees + */ +GTree* g_tree_new (GCompareFunc key_compare_func); +void g_tree_destroy (GTree *tree); +void g_tree_insert (GTree *tree, + gpointer key, + gpointer value); +void g_tree_remove (GTree *tree, + gpointer key); +gpointer g_tree_lookup (GTree *tree, + gpointer key); +void g_tree_traverse (GTree *tree, + GTraverseFunc traverse_func, + GTraverseType traverse_type, + gpointer data); +gpointer g_tree_search (GTree *tree, + GSearchFunc search_func, + gpointer data); +gint g_tree_height (GTree *tree); +gint g_tree_nnodes (GTree *tree); + + +/* Memory + */ + +#ifdef USE_DMALLOC + +#define g_malloc(size) (gpointer) MALLOC(size) +#define g_malloc0(size) (gpointer) CALLOC(char,size) +#define g_realloc(mem,size) (gpointer) REALLOC(mem,char,size) +#define g_free(mem) FREE(mem) + +#else /* USE_DMALLOC */ + +gpointer g_malloc (gulong size); +gpointer g_malloc0 (gulong size); +gpointer g_realloc (gpointer mem, + gulong size); +void g_free (gpointer mem); + +#endif /* USE_DMALLOC */ + +void g_mem_profile (void); +void g_mem_check (gpointer mem); + + +/* "g_mem_chunk_new" creates a new memory chunk. + * Memory chunks are used to allocate pieces of memory which are + * always the same size. Lists are a good example of such a data type. + * The memory chunk allocates and frees blocks of memory as needed. + * Just be sure to call "g_mem_chunk_free" and not "g_free" on data + * allocated in a mem chunk. ("g_free" will most likely cause a seg + * fault...somewhere). + * + * Oh yeah, GMemChunk is an opaque data type. (You don't really + * want to know what's going on inside do you?) + */ + +/* ALLOC_ONLY MemChunk's can only allocate memory. The free operation + * is interpreted as a no op. ALLOC_ONLY MemChunk's save 4 bytes per + * atom. (They are also useful for lists which use MemChunk to allocate + * memory but are also part of the MemChunk implementation). + * ALLOC_AND_FREE MemChunk's can allocate and free memory. + */ + +#define G_ALLOC_ONLY 1 +#define G_ALLOC_AND_FREE 2 + +GMemChunk* g_mem_chunk_new (gchar *name, + gint atom_size, + gulong area_size, + gint type); +void g_mem_chunk_destroy (GMemChunk *mem_chunk); +gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk); +void g_mem_chunk_free (GMemChunk *mem_chunk, + gpointer mem); +void g_mem_chunk_clean (GMemChunk *mem_chunk); +void g_mem_chunk_reset (GMemChunk *mem_chunk); +void g_mem_chunk_print (GMemChunk *mem_chunk); +void g_mem_chunk_info (void); + +/* Ah yes...we have a "g_blow_chunks" function. + * "g_blow_chunks" simply compresses all the chunks. This operation + * consists of freeing every memory area that should be freed (but + * which we haven't gotten around to doing yet). And, no, + * "g_blow_chunks" doesn't follow the naming scheme, but it is a + * much better name than "g_mem_chunk_clean_all" or something + * similar. + */ +void g_blow_chunks (void); + + +/* Timer + */ +GTimer* g_timer_new (void); +void g_timer_destroy (GTimer *timer); +void g_timer_start (GTimer *timer); +void g_timer_stop (GTimer *timer); +void g_timer_reset (GTimer *timer); +gdouble g_timer_elapsed (GTimer *timer, + gulong *microseconds); + + +/* Output + */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +void g_error (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +void g_warning (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +void g_message (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +void g_print (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +#else +void g_error (gchar *format, ...); +void g_warning (gchar *format, ...); +void g_message (gchar *format, ...); +void g_print (gchar *format, ...); +#endif + +/* Utility functions + */ +gchar* g_strdup (const gchar *str); +gchar* g_strerror (gint errnum); +gchar* g_strsignal (gint signum); + + +/* Errors + */ +GErrorFunc g_set_error_handler (GErrorFunc func); +GWarningFunc g_set_warning_handler (GWarningFunc func); +GPrintFunc g_set_message_handler (GPrintFunc func); +GPrintFunc g_set_print_handler (GPrintFunc func); + +void g_debug (char *progname); +void g_attach_process (char *progname, int query); +void g_stack_trace (char *progname, int query); + + +/* String Chunks + */ +GStringChunk* g_string_chunk_new (gint size); +void g_string_chunk_free (GStringChunk *chunk); +gchar* g_string_chunk_insert (GStringChunk *chunk, + gchar* string); +gchar* g_string_chunk_insert_const (GStringChunk *chunk, + gchar* string); + +/* Strings + */ +GString* g_string_new (gchar *init); +void g_string_free (GString *string, + gint free_segment); +GString* g_string_assign (GString *lval, + gchar *rval); +GString* g_string_truncate (GString *string, + gint len); +GString* g_string_append (GString *string, + gchar *val); +GString* g_string_append_c (GString *string, + gchar c); +GString* g_string_prepend (GString *string, + gchar *val); +GString* g_string_prepend_c (GString *string, + gchar c); +void g_string_sprintf (GString *string, + gchar *fmt, + ...); +void g_string_sprintfa (GString *string, + gchar *fmt, + ...); + +/* Resizable arrays + */ +#define g_array_append_val(array,type,val) \ + g_rarray_append (array, (gpointer) &val, sizeof (type)) +#define g_array_append_vals(array,type,vals,nvals) \ + g_rarray_append (array, (gpointer) vals, sizeof (type) * nvals) +#define g_array_prepend_val(array,type,val) \ + g_rarray_prepend (array, (gpointer) &val, sizeof (type)) +#define g_array_prepend_vals(array,type,vals,nvals) \ + g_rarray_prepend (array, (gpointer) vals, sizeof (type) * nvals) +#define g_array_truncate(array,type,length) \ + g_rarray_truncate (array, length, sizeof (type)) +#define g_array_index(array,type,index) \ + ((type*) array->data)[index] + +GArray* g_array_new (gint zero_terminated); +void g_array_free (GArray *array, + gint free_segment); +GArray* g_rarray_append (GArray *array, + gpointer data, + gint size); +GArray* g_rarray_prepend (GArray *array, + gpointer data, + gint size); +GArray* g_rarray_truncate (GArray *array, + gint length, + gint size); + + +/* Hash Functions + */ +gint g_string_equal (gpointer v, + gpointer v2); +guint g_string_hash (gpointer v); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __G_LIB_H__ */ diff --git a/glib/glibconfig.h.in b/glib/glibconfig.h.in new file mode 100644 index 0000000000..7a7655952b --- /dev/null +++ b/glib/glibconfig.h.in @@ -0,0 +1,67 @@ +/* glibconfig.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if the `long double' type works. */ +#undef HAVE_LONG_DOUBLE + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Other stuff */ +#undef HAVE_DOPRNT +#undef HAVE_FLOAT_H +#undef HAVE_LIMITS_H +#undef HAVE_LONG_DOUBLE +#undef HAVE_SYS_SELECT_H +#undef HAVE_STRERROR +#undef HAVE_STRSIGNAL +#undef HAVE_VALUES_H +#undef HAVE_VPRINTF + +#undef NO_FD_SET +#undef NO_SYS_ERRLIST +#undef NO_SYS_SIGLIST + +/* #undef PACKAGE */ +/* #undef VERSION */ + +/* The number of bytes in a char. */ +#undef SIZEOF_CHAR + +/* The number of bytes in a int. */ +#undef SIZEOF_INT + +/* The number of bytes in a long. */ +#undef SIZEOF_LONG + +/* The number of bytes in a short. */ +#undef SIZEOF_SHORT + +/* The number of bytes in a void *. */ +#undef SIZEOF_VOID_P + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strsignal function. */ +#undef HAVE_STRSIGNAL + +/* Define if you have the <float.h> header file. */ +#undef HAVE_FLOAT_H + +/* Define if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the <values.h> header file. */ +#undef HAVE_VALUES_H diff --git a/glib/glist.c b/glib/glist.c new file mode 100644 index 0000000000..f5a31d7439 --- /dev/null +++ b/glib/glist.c @@ -0,0 +1,349 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "glib.h" + + +typedef struct _GRealListAllocator GRealListAllocator; + +struct _GRealListAllocator +{ + GMemChunk *list_mem_chunk; + GList *free_list; +}; + + +static GRealListAllocator *default_allocator = NULL; +static GRealListAllocator *current_allocator = NULL; + + +GListAllocator* +g_list_allocator_new () +{ + GRealListAllocator* allocator = g_new (GRealListAllocator, 1); + + allocator->list_mem_chunk = NULL; + allocator->free_list = NULL; + + return (GListAllocator*) allocator; +} + +void +g_list_allocator_free (GListAllocator* fallocator) +{ + GRealListAllocator* allocator = (GRealListAllocator *) fallocator; + + if (allocator && allocator->list_mem_chunk) + g_mem_chunk_destroy (allocator->list_mem_chunk); + if (allocator) + g_free (allocator); +} + +GListAllocator* +g_list_set_allocator (GListAllocator* fallocator) +{ + GRealListAllocator* allocator = (GRealListAllocator *) fallocator; + GRealListAllocator* old_allocator = current_allocator; + + if (allocator) + current_allocator = allocator; + else + { + if (!default_allocator) + default_allocator = (GRealListAllocator*) g_list_allocator_new (); + current_allocator = default_allocator; + } + + if (!current_allocator->list_mem_chunk) + current_allocator->list_mem_chunk = g_mem_chunk_new ("list mem chunk", + sizeof (GList), + 1024, + G_ALLOC_ONLY); + + return (GListAllocator*) (old_allocator == default_allocator ? NULL : old_allocator); +} + + +GList* +g_list_alloc () +{ + GList *new_list; + + g_list_set_allocator (NULL); + if (current_allocator->free_list) + { + new_list = current_allocator->free_list; + current_allocator->free_list = current_allocator->free_list->next; + } + else + { + new_list = g_chunk_new (GList, current_allocator->list_mem_chunk); + } + + new_list->data = NULL; + new_list->next = NULL; + new_list->prev = NULL; + + return new_list; +} + +void +g_list_free (GList *list) +{ + GList *last; + + if (list) + { + last = g_list_last (list); + last->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +void +g_list_free_1 (GList *list) +{ + if (list) + { + list->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +GList* +g_list_append (GList *list, + gpointer data) +{ + GList *new_list; + GList *last; + + new_list = g_list_alloc (); + new_list->data = data; + + if (!list) + { + list = new_list; + } + else + { + last = g_list_last (list); + g_assert (last != NULL); + last->next = new_list; + new_list->prev = last; + } + + return list; +} + +GList* +g_list_prepend (GList *list, + gpointer data) +{ + GList *new_list; + + new_list = g_list_alloc (); + new_list->data = data; + + if (list) + { + if (list->prev) + list->prev->next = new_list; + new_list->prev = list->prev; + list->prev = new_list; + } + new_list->next = list; + + return new_list; +} + +GList* +g_list_insert (GList *list, + gpointer data, + gint position) +{ + GList *new_list; + GList *tmp_list; + + if (position < 0) + return g_list_append (list, data); + else if (position == 0) + return g_list_prepend (list, data); + + tmp_list = g_list_nth (list, position); + if (!tmp_list) + return g_list_append (list, data); + + new_list = g_list_alloc (); + new_list->data = data; + + if (tmp_list->prev) + tmp_list->prev->next = new_list; + new_list->next = tmp_list; + new_list->prev = tmp_list->prev; + tmp_list->prev = new_list; + + if (tmp_list == list) + list = new_list; + + return list; +} + +GList* +g_list_remove (GList *list, + gpointer data) +{ + GList *tmp; + + tmp = list; + while (tmp) + { + if (tmp->data == data) + { + if (tmp->prev) + tmp->prev->next = tmp->next; + if (tmp->next) + tmp->next->prev = tmp->prev; + + if (list == tmp) + list = list->next; + + tmp->next = NULL; + tmp->prev = NULL; + g_list_free (tmp); + + break; + } + + tmp = tmp->next; + } + return list; +} + +GList* +g_list_remove_link (GList *list, + GList *link) +{ + if (link) + { + if (link->prev) + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + + if (link == list) + list = list->next; + + link->next = NULL; + link->prev = NULL; + } + + return list; +} + +GList* +g_list_reverse (GList *list) +{ + GList *tmp; + GList *last; + + last = NULL; + while (list) + { + last = list; + tmp = list->next; + list->next = list->prev; + list->prev = tmp; + list = tmp; + } + + return last; +} + +GList* +g_list_nth (GList *list, + gint n) +{ + while ((n-- > 0) && list) + list = list->next; + + return list; +} + +GList* +g_list_find (GList *list, + gpointer data) +{ + while (list) + { + if (list->data == data) + break; + list = list->next; + } + + return list; +} + +GList* +g_list_last (GList *list) +{ + if (list) + { + while (list->next) + list = list->next; + } + + return list; +} + +GList* +g_list_first (GList *list) +{ + if (list) + { + while (list->prev) + list = list->prev; + } + + return list; +} + +gint +g_list_length (GList *list) +{ + gint length; + + length = 0; + while (list) + { + length++; + list = list->next; + } + + return length; +} + +void +g_list_foreach (GList *list, + GFunc func, + gpointer user_data) +{ + while (list) + { + (*func) (list->data, user_data); + list = list->next; + } +} diff --git a/glib/gmem.c b/glib/gmem.c new file mode 100644 index 0000000000..35dfdaba37 --- /dev/null +++ b/glib/gmem.c @@ -0,0 +1,824 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdlib.h> +#include <string.h> +#include "glib.h" + + +/* #define MEM_PROFILE */ +/* #define MEM_CHECK */ + + +#define MAX_MEM_AREA 65536L +#define MEM_AREA_SIZE 4L + +#if SIZEOF_VOID_P > SIZEOF_LONG +#define MEM_ALIGN SIZEOF_VOID_P +#else +#define MEM_ALIGN SIZEOF_LONG +#endif + + +typedef struct _GFreeAtom GFreeAtom; +typedef struct _GMemArea GMemArea; +typedef struct _GRealMemChunk GRealMemChunk; + +struct _GFreeAtom +{ + GFreeAtom *next; +}; + +struct _GMemArea +{ + GMemArea *next; /* the next mem area */ + GMemArea *prev; /* the previous mem area */ + gulong index; /* the current index into the "mem" array */ + gulong free; /* the number of free bytes in this mem area */ + gulong allocated; /* the number of atoms allocated from this area */ + gulong mark; /* is this mem area marked for deletion */ + gchar mem[MEM_AREA_SIZE]; /* the mem array from which atoms get allocated + * the actual size of this array is determined by + * the mem chunk "area_size". ANSI says that it + * must be declared to be the maximum size it + * can possibly be (even though the actual size + * may be less). + */ +}; + +struct _GRealMemChunk +{ + gchar *name; /* name of this MemChunk...used for debugging output */ + gint type; /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */ + gint num_mem_areas; /* the number of memory areas */ + gint num_marked_areas; /* the number of areas marked for deletion */ + guint atom_size; /* the size of an atom */ + gulong area_size; /* the size of a memory area */ + GMemArea *mem_area; /* the current memory area */ + GMemArea *mem_areas; /* a list of all the mem areas owned by this chunk */ + GMemArea *free_mem_area; /* the free area...which is about to be destroyed */ + GFreeAtom *free_atoms; /* the free atoms list */ + GTree *mem_tree; /* tree of mem areas sorted by memory address */ + GRealMemChunk *next; /* pointer to the next chunk */ + GRealMemChunk *prev; /* pointer to the previous chunk */ +}; + + +static gulong g_mem_chunk_compute_size (gulong size); +static gint g_mem_chunk_area_compare (GMemArea *a, + GMemArea *b); +static gint g_mem_chunk_area_search (GMemArea *a, + gchar *addr); + + +static GRealMemChunk *mem_chunks = NULL; + +#ifdef MEM_PROFILE +static gulong allocations[4096] = { 0 }; +static gulong allocated_mem = 0; +static gulong freed_mem = 0; +#endif /* MEM_PROFILE */ + + +#ifndef USE_DMALLOC + +gpointer +g_malloc (gulong size) +{ + gpointer p; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; +#endif /* MEM_PROFILE || MEM_CHECK */ + + + if (size == 0) + return NULL; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size += SIZEOF_LONG; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + size += SIZEOF_LONG; +#endif /* MEM_CHECK */ + + + p = (gpointer) malloc (size); + if (!p) + g_error ("could not allocate %ld bytes", size); + + +#ifdef MEM_CHECK + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = 0; +#endif /* MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = size; + +#ifdef MEM_PROFILE + if (size <= 4095) + allocations[size-1] += 1; + else + allocations[4095] += 1; + allocated_mem += size; +#endif /* MEM_PROFILE */ +#endif /* MEM_PROFILE || MEM_CHECK */ + + + return p; +} + +gpointer +g_malloc0 (gulong size) +{ + gpointer p; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; +#endif /* MEM_PROFILE || MEM_CHECK */ + + + if (size == 0) + return NULL; + + +#ifdef MEM_PROFILE + size += SIZEOF_LONG; +#endif /* MEM_PROFILE */ + +#ifdef MEM_CHECK + size += SIZEOF_LONG; +#endif /* MEM_CHECK */ + + + p = (gpointer) calloc (size, 1); + if (!p) + g_error ("could not allocate %ld bytes", size); + + +#ifdef MEM_CHECK + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = 0; +#endif /* MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = size; + +#ifdef MEM_PROFILE + if (size <= 4095) + allocations[size-1] += 1; + else + allocations[4095] += 1; + allocated_mem += size; +#endif /* MEM_PROFILE */ +#endif /* MEM_PROFILE */ + + + return p; +} + +gpointer +g_realloc (gpointer mem, + gulong size) +{ + gpointer p; + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; +#endif /* MEM_PROFILE || MEM_CHECK */ + + + if (size == 0) + return NULL; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size += SIZEOF_LONG; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + size += SIZEOF_LONG; +#endif /* MEM_CHECK */ + + + if (!mem) + p = (gpointer) malloc (size); + else + { +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); +#ifdef MEM_PROFILE + freed_mem += *t; +#endif /* MEM_PROFILE */ + mem = t; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); + if (*t >= 1) + g_warning ("trying to realloc freed memory\n"); + mem = t; +#endif /* MEM_CHECK */ + + p = (gpointer) realloc (mem, size); + } + + if (!p) + g_error ("could not reallocate %ld bytes", size); + + +#ifdef MEM_CHECK + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = 0; +#endif /* MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = size; + +#ifdef MEM_PROFILE + if (size <= 4095) + allocations[size-1] += 1; + else + allocations[4095] += 1; + allocated_mem += size; +#endif /* MEM_PROFILE */ +#endif /* MEM_PROFILE || MEM_CHECK */ + + + return p; +} + +void +g_free (gpointer mem) +{ + if (mem) + { +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; + gulong size; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); + size = *t; +#ifdef MEM_PROFILE + freed_mem += size; +#endif /* MEM_PROFILE */ + mem = t; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); + if (*t >= 1) + g_warning ("freeing previously freed memory\n"); + *t += 1; + mem = t; + + memset ((guchar*) mem + 8, 0, size); +#else /* MEM_CHECK */ + free (mem); +#endif /* MEM_CHECK */ + } +} + +#endif /* ! USE_DMALLOC */ + + +void +g_mem_profile () +{ +#ifdef MEM_PROFILE + gint i; + + for (i = 0; i < 4095; i++) + if (allocations[i] > 0) + g_print ("%lu allocations of %d bytes\n", allocations[i], i + 1); + + if (allocations[4095] > 0) + g_print ("%lu allocations of greater than 4095 bytes\n", allocations[4095]); + g_print ("%lu bytes allocated\n", allocated_mem); + g_print ("%lu bytes freed\n", freed_mem); + g_print ("%lu bytes in use\n", allocated_mem - freed_mem); +#endif /* MEM_PROFILE */ +} + +void +g_mem_check (gpointer mem) +{ +#ifdef MEM_CHECK + gulong *t; + + t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG); + + if (*t >= 1) + g_warning ("mem: 0x%08x has been freed: %lu\n", (gulong) mem, *t); +#endif /* MEM_CHECK */ +} + +GMemChunk* +g_mem_chunk_new (gchar *name, + gint atom_size, + gulong area_size, + gint type) +{ + GRealMemChunk *mem_chunk; + gulong rarea_size; + + mem_chunk = g_new (struct _GRealMemChunk, 1); + mem_chunk->name = name; + mem_chunk->type = type; + mem_chunk->num_mem_areas = 0; + mem_chunk->num_marked_areas = 0; + mem_chunk->mem_area = NULL; + mem_chunk->free_mem_area = NULL; + mem_chunk->free_atoms = NULL; + mem_chunk->mem_tree = NULL; + mem_chunk->mem_areas = NULL; + mem_chunk->atom_size = atom_size; + + if (mem_chunk->type == G_ALLOC_AND_FREE) + mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); + + if (mem_chunk->atom_size % MEM_ALIGN) + mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN); + + mem_chunk->area_size = area_size; + if (mem_chunk->area_size > MAX_MEM_AREA) + mem_chunk->area_size = MAX_MEM_AREA; + while (mem_chunk->area_size < mem_chunk->atom_size) + mem_chunk->area_size *= 2; + + rarea_size = mem_chunk->area_size + sizeof (GMemArea) - MEM_AREA_SIZE; + rarea_size = g_mem_chunk_compute_size (rarea_size); + mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE); + + /* + mem_chunk->area_size -= (sizeof (GMemArea) - MEM_AREA_SIZE); + if (mem_chunk->area_size < mem_chunk->atom_size) + { + mem_chunk->area_size = (mem_chunk->area_size + sizeof (GMemArea) - MEM_AREA_SIZE) * 2; + mem_chunk->area_size -= (sizeof (GMemArea) - MEM_AREA_SIZE); + } + + if (mem_chunk->area_size % mem_chunk->atom_size) + mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size); + */ + + mem_chunk->next = mem_chunks; + mem_chunk->prev = NULL; + if (mem_chunks) + mem_chunks->prev = mem_chunk; + mem_chunks = mem_chunk; + + return ((GMemChunk*) mem_chunk); +} + +void +g_mem_chunk_destroy (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_areas; + GMemArea *temp_area; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + mem_areas = rmem_chunk->mem_areas; + while (mem_areas) + { + temp_area = mem_areas; + mem_areas = mem_areas->next; + g_free (temp_area); + } + + if (rmem_chunk->next) + rmem_chunk->next->prev = rmem_chunk->prev; + if (rmem_chunk->prev) + rmem_chunk->prev->next = rmem_chunk->next; + + if (rmem_chunk == mem_chunks) + mem_chunks = mem_chunks->next; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_destroy (rmem_chunk->mem_tree); + + g_free (rmem_chunk); +} + +gpointer +g_mem_chunk_alloc (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *temp_area; + gpointer mem; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + while (rmem_chunk->free_atoms) + { + /* Get the first piece of memory on the "free_atoms" list. + * We can go ahead and destroy the list node we used to keep + * track of it with and to update the "free_atoms" list to + * point to its next element. + */ + mem = rmem_chunk->free_atoms; + rmem_chunk->free_atoms = rmem_chunk->free_atoms->next; + + /* Determine which area this piece of memory is allocated from */ + temp_area = g_tree_search (rmem_chunk->mem_tree, + (GSearchFunc) g_mem_chunk_area_search, + mem); + + /* If the area has been marked, then it is being destroyed. + * (ie marked to be destroyed). + * We check to see if all of the segments on the free list that + * reference this area have been removed. This occurs when + * the ammount of free memory is less than the allocatable size. + * If the chunk should be freed, then we place it in the "free_mem_area". + * This is so we make sure not to free the mem area here and then + * allocate it again a few lines down. + * If we don't allocate a chunk a few lines down then the "free_mem_area" + * will be freed. + * If there is already a "free_mem_area" then we'll just free this mem area. + */ + if (temp_area->mark) + { + /* Update the "free" memory available in that area */ + temp_area->free += rmem_chunk->atom_size; + + if (temp_area->free == rmem_chunk->area_size) + { + if (temp_area == rmem_chunk->mem_area) + rmem_chunk->mem_area = NULL; + + if (rmem_chunk->free_mem_area) + { + rmem_chunk->num_mem_areas -= 1; + rmem_chunk->num_marked_areas -= 1; + + if (temp_area->next) + temp_area->next->prev = temp_area->prev; + if (temp_area->prev) + temp_area->prev->next = temp_area->next; + if (temp_area == rmem_chunk->mem_areas) + rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; + if (temp_area == rmem_chunk->mem_area) + rmem_chunk->mem_area = NULL; + + g_free (temp_area); + } + else + rmem_chunk->free_mem_area = temp_area; + } + } + else + { + /* Update the number of allocated atoms count. + */ + temp_area->allocated += 1; + + /* The area wasn't marked...return the memory + */ + goto outa_here; + } + } + + /* If there isn't a current mem area or the current mem area is out of space + * then allocate a new mem area. We'll first check and see if we can use + * the "free_mem_area". Otherwise we'll just malloc the mem area. + */ + if ((!rmem_chunk->mem_area) || + ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size)) + { + if (rmem_chunk->free_mem_area) + { + rmem_chunk->mem_area = rmem_chunk->free_mem_area; + rmem_chunk->free_mem_area = NULL; + } + else + { + rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) - + MEM_AREA_SIZE + + rmem_chunk->area_size); + + rmem_chunk->num_mem_areas += 1; + rmem_chunk->mem_area->next = rmem_chunk->mem_areas; + rmem_chunk->mem_area->prev = NULL; + + if (rmem_chunk->mem_areas) + rmem_chunk->mem_areas->prev = rmem_chunk->mem_area; + rmem_chunk->mem_areas = rmem_chunk->mem_area; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area); + } + + rmem_chunk->mem_area->index = 0; + rmem_chunk->mem_area->free = rmem_chunk->area_size; + rmem_chunk->mem_area->allocated = 0; + rmem_chunk->mem_area->mark = 0; + } + else if (rmem_chunk->free_mem_area) + { + rmem_chunk->num_mem_areas -= 1; + + if (rmem_chunk->free_mem_area->next) + rmem_chunk->free_mem_area->next->prev = rmem_chunk->free_mem_area->prev; + if (rmem_chunk->free_mem_area->prev) + rmem_chunk->free_mem_area->prev->next = rmem_chunk->free_mem_area->next; + if (rmem_chunk->free_mem_area == rmem_chunk->mem_areas) + rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_remove (rmem_chunk->mem_tree, rmem_chunk->free_mem_area); + + g_free (rmem_chunk->free_mem_area); + rmem_chunk->free_mem_area = NULL; + } + + /* Get the memory and modify the state variables appropriately. + */ + mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index]; + rmem_chunk->mem_area->index += rmem_chunk->atom_size; + rmem_chunk->mem_area->free -= rmem_chunk->atom_size; + rmem_chunk->mem_area->allocated += 1; + +outa_here: + return mem; +} + +void +g_mem_chunk_free (GMemChunk *mem_chunk, + gpointer mem) +{ + GRealMemChunk *rmem_chunk; + GMemArea *temp_area; + GFreeAtom *free_atom; + + g_assert (mem_chunk != NULL); + g_assert (mem != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + /* Don't do anything if this is an ALLOC_ONLY chunk + */ + if (rmem_chunk->type == G_ALLOC_AND_FREE) + { + /* Place the memory on the "free_atoms" list + */ + free_atom = (GFreeAtom*) mem; + free_atom->next = rmem_chunk->free_atoms; + rmem_chunk->free_atoms = free_atom; + + temp_area = g_tree_search (rmem_chunk->mem_tree, + (GSearchFunc) g_mem_chunk_area_search, + mem); + + temp_area->allocated -= 1; + + if (temp_area->allocated == 0) + { + temp_area->mark = 1; + rmem_chunk->num_marked_areas += 1; + + g_mem_chunk_clean (mem_chunk); + } + } +} + +void +g_mem_chunk_clean (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_area; + GFreeAtom *prev_free_atom; + GFreeAtom *temp_free_atom; + gpointer mem; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + { + prev_free_atom = NULL; + temp_free_atom = rmem_chunk->free_atoms; + + while (temp_free_atom) + { + mem = (gpointer) temp_free_atom; + + mem_area = g_tree_search (rmem_chunk->mem_tree, + (GSearchFunc) g_mem_chunk_area_search, + mem); + + /* If this mem area is marked for destruction then delete the + * area and list node and decrement the free mem. + */ + if (mem_area->mark) + { + if (prev_free_atom) + prev_free_atom->next = temp_free_atom->next; + else + rmem_chunk->free_atoms = temp_free_atom->next; + temp_free_atom = temp_free_atom->next; + + mem_area->free += rmem_chunk->atom_size; + if (mem_area->free == rmem_chunk->area_size) + { + rmem_chunk->num_mem_areas -= 1; + rmem_chunk->num_marked_areas -= 1; + + if (mem_area->next) + mem_area->next->prev = mem_area->prev; + if (mem_area->prev) + mem_area->prev->next = mem_area->next; + if (mem_area == rmem_chunk->mem_areas) + rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; + if (mem_area == rmem_chunk->mem_area) + rmem_chunk->mem_area = NULL; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_remove (rmem_chunk->mem_tree, mem_area); + g_free (mem_area); + } + } + else + { + prev_free_atom = temp_free_atom; + temp_free_atom = temp_free_atom->next; + } + } + } +} + +void +g_mem_chunk_reset (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_areas; + GMemArea *temp_area; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + mem_areas = rmem_chunk->mem_areas; + rmem_chunk->num_mem_areas = 0; + rmem_chunk->mem_areas = NULL; + rmem_chunk->mem_area = NULL; + + while (mem_areas) + { + temp_area = mem_areas; + mem_areas = mem_areas->next; + g_free (temp_area); + } + + rmem_chunk->free_atoms = NULL; + + if (rmem_chunk->mem_tree) + g_tree_destroy (rmem_chunk->mem_tree); + rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); +} + +void +g_mem_chunk_print (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_areas; + gulong mem; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + mem_areas = rmem_chunk->mem_areas; + mem = 0; + + while (mem_areas) + { + mem += rmem_chunk->area_size - mem_areas->free; + mem_areas = mem_areas->next; + } + + g_print ("%s: %ld bytes using %d mem areas", rmem_chunk->name, mem, rmem_chunk->num_mem_areas); +} + +void +g_mem_chunk_info () +{ + GRealMemChunk *mem_chunk; + gint count; + + count = 0; + mem_chunk = mem_chunks; + while (mem_chunk) + { + count += 1; + mem_chunk = mem_chunk->next; + } + + g_print ("%d mem chunks", count); + + mem_chunk = mem_chunks; + while (mem_chunk) + { + g_mem_chunk_print ((GMemChunk*) mem_chunk); + mem_chunk = mem_chunk->next; + } +} + +void +g_blow_chunks () +{ + GRealMemChunk *mem_chunk; + + mem_chunk = mem_chunks; + while (mem_chunk) + { + g_mem_chunk_clean ((GMemChunk*) mem_chunk); + mem_chunk = mem_chunk->next; + } +} + + +static gulong +g_mem_chunk_compute_size (gulong size) +{ + gulong power_of_2; + gulong lower, upper; + + power_of_2 = 16; + while (power_of_2 < size) + power_of_2 <<= 1; + + lower = power_of_2 >> 1; + upper = power_of_2; + + if ((size - lower) < (upper - size)) + return lower; + return upper; +} + +static gint +g_mem_chunk_area_compare (GMemArea *a, + GMemArea *b) +{ + return (a->mem - b->mem); +} + +static gint +g_mem_chunk_area_search (GMemArea *a, + gchar *addr) +{ + if (a->mem <= addr) + { + if (addr < &a->mem[a->index]) + return 0; + return 1; + } + return -1; +} diff --git a/glib/gprimes.c b/glib/gprimes.c new file mode 100644 index 0000000000..8887c0e660 --- /dev/null +++ b/glib/gprimes.c @@ -0,0 +1,61 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "glib.h" + + +gint g_primes[] = +{ + 11, + 15, + 23, + 35, + 49, + 73, + 109, + 163, + 251, + 367, + 557, + 823, + 1237, + 1861, + 2777, + 4177, + 6247, + 9371, + 14057, + 21089, + 31627, + 47431, + 71143, + 106721, + 160073, + 240101, + 360163, + 540217, + 810343, + 1215497, + 1823231, + 2734867, + 4102283, + 6153409, + 9230113, + 13845163, +}; + +gint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]); diff --git a/glib/gslist.c b/glib/gslist.c new file mode 100644 index 0000000000..e09198522e --- /dev/null +++ b/glib/gslist.c @@ -0,0 +1,324 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "glib.h" + + +typedef struct _GRealListAllocator GRealListAllocator; + +struct _GRealListAllocator +{ + GMemChunk *list_mem_chunk; + GSList *free_list; +}; + + +static GRealListAllocator *default_allocator = NULL; +static GRealListAllocator *current_allocator = NULL; + +GListAllocator* +g_slist_set_allocator (GListAllocator* fallocator) +{ + GRealListAllocator* allocator = (GRealListAllocator *) fallocator; + GRealListAllocator* old_allocator = current_allocator; + + if (allocator) + current_allocator = allocator; + else + { + if (!default_allocator) + default_allocator = (GRealListAllocator*) g_list_allocator_new (); + current_allocator = default_allocator; + } + + if (!current_allocator->list_mem_chunk) + current_allocator->list_mem_chunk = g_mem_chunk_new ("slist mem chunk", + sizeof (GSList), + 1024, + G_ALLOC_ONLY); + + return (GListAllocator*) (old_allocator == default_allocator ? NULL : old_allocator); +} + + +GSList* +g_slist_alloc () +{ + GSList *new_list; + + g_slist_set_allocator (NULL); + if (current_allocator->free_list) + { + new_list = current_allocator->free_list; + current_allocator->free_list = current_allocator->free_list->next; + } + else + { + new_list = g_chunk_new (GSList, current_allocator->list_mem_chunk); + } + + new_list->data = NULL; + new_list->next = NULL; + + return new_list; +} + +void +g_slist_free (GSList *list) +{ + GSList *last; + + if (list) + { + last = g_slist_last (list); + last->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +void +g_slist_free_1 (GSList *list) +{ + if (list) + { + list->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +GSList* +g_slist_append (GSList *list, + gpointer data) +{ + GSList *new_list; + GSList *last; + + new_list = g_slist_alloc (); + new_list->data = data; + + if (!list) + { + list = new_list; + } + else + { + last = g_slist_last (list); + g_assert (last != NULL); + last->next = new_list; + } + + return list; +} + +GSList* +g_slist_prepend (GSList *list, + gpointer data) +{ + GSList *new_list; + + new_list = g_slist_alloc (); + new_list->data = data; + new_list->next = list; + + return new_list; +} + +GSList* +g_slist_insert (GSList *list, + gpointer data, + gint position) +{ + GSList *prev_list; + GSList *tmp_list; + GSList *new_list; + + prev_list = NULL; + tmp_list = list; + + while (tmp_list && (position-- > 0)) + { + prev_list = tmp_list; + tmp_list = tmp_list->next; + } + + if (!tmp_list && !prev_list) + return list; + + new_list = g_slist_alloc (); + + if (!prev_list) + { + new_list->next = list; + list = new_list; + } + else + { + new_list->next = prev_list->next; + prev_list->next = new_list; + } + + return list; +} + +GSList* +g_slist_remove (GSList *list, + gpointer data) +{ + GSList *tmp; + GSList *prev; + + prev = NULL; + tmp = list; + + while (tmp) + { + if (tmp->data == data) + { + if (prev) + prev->next = tmp->next; + if (list == tmp) + list = list->next; + + tmp->next = NULL; + g_slist_free (tmp); + + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + +GSList* +g_slist_remove_link (GSList *list, + GSList *link) +{ + GSList *tmp; + GSList *prev; + + prev = NULL; + tmp = list; + + while (tmp) + { + if (tmp == link) + { + if (prev) + prev->next = tmp->next; + if (list == tmp) + list = list->next; + + tmp->next = NULL; + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + +GSList* +g_slist_reverse (GSList *list) +{ + GSList *tmp; + GSList *prev; + GSList *last; + + last = NULL; + prev = NULL; + + while (list) + { + last = list; + + tmp = list->next; + list->next = prev; + + prev = list; + list = tmp; + } + + return last; +} + +GSList* +g_slist_nth (GSList *list, + gint n) +{ + while ((n-- > 0) && list) + list = list->next; + + return list; +} + +GSList* +g_slist_find (GSList *list, + gpointer data) +{ + while (list) + { + if (list->data == data) + break; + list = list->next; + } + + return list; +} + +GSList* +g_slist_last (GSList *list) +{ + if (list) + { + while (list->next) + list = list->next; + } + + return list; +} + +gint +g_slist_length (GSList *list) +{ + gint length; + + length = 0; + while (list) + { + length++; + list = list->next; + } + + return length; +} + +void +g_slist_foreach (GSList *list, + GFunc func, + gpointer user_data) +{ + while (list) + { + (*func) (list->data, user_data); + list = list->next; + } +} diff --git a/glib/gstring.c b/glib/gstring.c new file mode 100644 index 0000000000..457d47ebcb --- /dev/null +++ b/glib/gstring.c @@ -0,0 +1,487 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <glib.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + + +typedef struct _GRealStringChunk GRealStringChunk; +typedef struct _GRealString GRealString; + +struct _GRealStringChunk +{ + GHashTable *const_table; + GSList *storage_list; + gint storage_next; + gint this_size; + gint default_size; +}; + +struct _GRealString +{ + gchar *str; + gint len; + gint alloc; +}; + + +static GMemChunk *string_mem_chunk = NULL; + +/* Hash Functions. + */ + +/* Pete, you may have these elsewhere. */ +gint +g_string_equal(gpointer v, gpointer v2) +{ + return strcmp ((gchar*) v, (gchar*)v2) == 0; +} + +/* a char* hash function from ASU */ +guint +g_string_hash(gpointer v) +{ + char *s = (char*)v; + char *p; + guint h=0, g; + + for(p = s; *p != '\0'; p += 1) { + h = ( h << 4 ) + *p; + if ( ( g = h & 0xf0000000 ) ) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + + return h /* % M */; +} + + +/* String Chunks. + */ + +GStringChunk* +g_string_chunk_new (gint default_size) +{ + GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1); + gint size = 1; + + while (size < default_size) + size <<= 1; + + new_chunk->const_table = NULL; + new_chunk->storage_list = NULL; + new_chunk->storage_next = size; + new_chunk->default_size = size; + new_chunk->this_size = size; + + return (GStringChunk*) new_chunk; +} + +void +g_string_chunk_free (GStringChunk *fchunk) +{ + GRealStringChunk *chunk = (GRealStringChunk*) fchunk; + GSList *tmp_list; + + if (chunk->storage_list) + { + GListAllocator *tmp_allocator = g_slist_set_allocator (NULL); + + for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next) + g_free (tmp_list->data); + + g_slist_free (chunk->storage_list); + + g_slist_set_allocator (tmp_allocator); + } + + if (chunk->const_table) + g_hash_table_destroy (chunk->const_table); + + g_free (chunk); +} + +gchar* +g_string_chunk_insert (GStringChunk *fchunk, + gchar* string) +{ + GRealStringChunk *chunk = (GRealStringChunk*) fchunk; + gint len = strlen (string); + char* pos; + + if ((chunk->storage_next + len + 1) > chunk->this_size) + { + GListAllocator *tmp_allocator = g_slist_set_allocator (NULL); + gint new_size = chunk->default_size; + + while (new_size < len+1) + new_size <<= 1; + + chunk->storage_list = g_slist_prepend (chunk->storage_list, + g_new (char, new_size)); + + chunk->this_size = new_size; + chunk->storage_next = 0; + + g_slist_set_allocator (tmp_allocator); + } + + pos = ((char*)chunk->storage_list->data) + chunk->storage_next; + + strcpy (pos, string); + + chunk->storage_next += len + 1; + + return pos; +} + +gchar* +g_string_chunk_insert_const (GStringChunk *fchunk, + gchar* string) +{ + GRealStringChunk *chunk = (GRealStringChunk*) fchunk; + char* lookup; + + if (!chunk->const_table) + chunk->const_table = g_hash_table_new (g_string_hash, g_string_equal); + + lookup = (char*) g_hash_table_lookup (chunk->const_table, string); + + if (!lookup) + { + lookup = g_string_chunk_insert (fchunk, string); + g_hash_table_insert (chunk->const_table, lookup, lookup); + } + + return lookup; +} + +/* Strings. + */ +static gint +nearest_pow (gint num) +{ + gint n = 1; + + while (n < num) + n <<= 1; + + return n; +} + +static void +g_string_maybe_expand (GRealString* string, gint len) +{ + if (string->len + len >= string->alloc) + { + string->alloc = nearest_pow (string->len + len + 1); + string->str = g_realloc (string->str, string->alloc); + } +} + +GString* +g_string_new (gchar *init) +{ + GRealString *string; + + if (!string_mem_chunk) + string_mem_chunk = g_mem_chunk_new ("string mem chunk", + sizeof (GRealString), + 1024, G_ALLOC_AND_FREE); + + string = g_chunk_new (GRealString, string_mem_chunk); + + string->alloc = 2; + string->len = 0; + string->str = g_new0(char, 2); + + if (init) + g_string_append ((GString*)string, init); + + return (GString*) string; +} + +void +g_string_free (GString *string, gint free_segment) +{ + if (free_segment) + g_free (string->str); + + g_mem_chunk_free (string_mem_chunk, string); +} + +GString* +g_string_assign (GString *lval, + char *rval) +{ + g_string_truncate (lval, 0); + g_string_append (lval, rval); + + return lval; +} + +GString* +g_string_truncate (GString* fstring, gint len) +{ + GRealString *string = (GRealString*)fstring; + + string->len = len; + + string->str[len] = 0; + + return fstring; +} + +GString* +g_string_append (GString *fstring, gchar *val) +{ + GRealString *string = (GRealString*)fstring; + int len = strlen (val); + + g_string_maybe_expand (string, len); + + strcpy (string->str + string->len, val); + + string->len += len; + + return fstring; +} + +GString* +g_string_append_c (GString *fstring, char c) +{ + GRealString *string = (GRealString*)fstring; + + g_string_maybe_expand (string, 1); + + string->str[string->len++] = c; + string->str[string->len] = 0; + + return fstring; +} + +GString* +g_string_prepend (GString *fstring, gchar *val) +{ + GRealString *string = (GRealString*)fstring; + gint len = strlen (val); + + g_string_maybe_expand (string, len); + + memmove (string->str, string->str + len, string->len); + + strncpy (string->str, val, len); + + string->len += len; + + string->str[string->len] = 0; + + return fstring; +} + +GString* +g_string_prepend_c (GString *fstring, char c) +{ + GRealString *string = (GRealString*)fstring; + + g_string_maybe_expand (string, 1); + + memmove (string->str, string->str + 1, string->len); + + string->str[0] = c; + + string->len += 1; + + string->str[string->len] = 0; + + return fstring; +} + +static int +get_length_upper_bound (gchar* fmt, va_list *args) +{ + int len = 0; + int short_int; + int long_int; + int done; + + while (*fmt) + { + char c = *fmt++; + + short_int = FALSE; + long_int = FALSE; + + if (c == '%') + { + done = FALSE; + while (*fmt && !done) + { + switch (*fmt++) + { + case '*': + len += va_arg(*args, int); + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fmt -= 1; + len += strtol (fmt, &fmt, 10); + break; + case 'h': + short_int = TRUE; + break; + case 'l': + long_int = TRUE; + break; + + /* I ignore 'q' and 'L', they're not portable anyway. */ + + case 's': + len += strlen (va_arg (*args, char *)); + done = TRUE; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (long_int) + (void)va_arg (*args, long); + else if (short_int) + (void)va_arg (*args, int); + else + (void)va_arg (*args, int); + len += 32; + done = TRUE; + break; + case 'D': + case 'O': + case 'U': + (void)va_arg (*args, long); + len += 32; + done = TRUE; + break; + case 'e': + case 'E': + case 'f': + case 'g': + (void)va_arg (*args, double); + len += 32; + done = TRUE; + break; + case 'c': + (void)va_arg (*args, int); + len += 1; + done = TRUE; + break; + case 'p': + case 'n': + (void)va_arg (*args, void*); + len += 32; + done = TRUE; + break; + case '%': + len += 1; + done = TRUE; + break; + default: + break; + } + } + } + else + len += 1; + } + + return len; +} + +char* +g_vsprintf (gchar *fmt, + va_list *args, + va_list *args2) +{ + static gchar *buf = NULL; + static gint alloc = 0; + + gint len = get_length_upper_bound (fmt, args); + + if (len >= alloc) + { + if (buf) + g_free (buf); + + alloc = nearest_pow (MAX(len + 1, 1024)); + + buf = g_new (char, alloc); + } + + vsprintf (buf, fmt, *args2); + + return buf; +} + +static void +g_string_sprintfa_int (GString *string, + gchar *fmt, + va_list *args, + va_list *args2) +{ + g_string_append (string, g_vsprintf (fmt, args, args2)); +} + +void +g_string_sprintf (GString *string, gchar *fmt, ...) +{ + va_list args, args2; + + va_start(args, fmt); + va_start(args2, fmt); + + g_string_truncate (string, 0); + + g_string_sprintfa_int (string, fmt, &args, &args2); + + va_end(args); + va_end(args2); +} + +void +g_string_sprintfa (GString *string, gchar *fmt, ...) +{ + va_list args, args2; + + va_start(args, fmt); + va_start(args2, fmt); + + g_string_sprintfa_int (string, fmt, &args, &args2); + + va_end(args); + va_end(args2); +} diff --git a/glib/gtimer.c b/glib/gtimer.c new file mode 100644 index 0000000000..c3b720df96 --- /dev/null +++ b/glib/gtimer.c @@ -0,0 +1,119 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <sys/time.h> +#include <unistd.h> +#include "glib.h" + + +typedef struct _GRealTimer GRealTimer; + +struct _GRealTimer +{ + struct timeval start; + struct timeval end; + gint active; +}; + + +GTimer* +g_timer_new () +{ + GRealTimer *timer; + + timer = g_new (GRealTimer, 1); + timer->active = TRUE; + + gettimeofday (&timer->start, NULL); + + return ((GTimer*) timer); +} + +void +g_timer_destroy (GTimer *timer) +{ + g_assert (timer != NULL); + + g_free (timer); +} + +void +g_timer_start (GTimer *timer) +{ + GRealTimer *rtimer; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + gettimeofday (&rtimer->start, NULL); + rtimer->active = 1; +} + +void +g_timer_stop (GTimer *timer) +{ + GRealTimer *rtimer; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + gettimeofday (&rtimer->end, NULL); + rtimer->active = 0; +} + +void +g_timer_reset (GTimer *timer) +{ + GRealTimer *rtimer; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + gettimeofday (&rtimer->start, NULL); +} + +gdouble +g_timer_elapsed (GTimer *timer, + gulong *microseconds) +{ + GRealTimer *rtimer; + struct timeval elapsed; + gdouble total; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + + if (rtimer->active) + gettimeofday (&rtimer->end, NULL); + + if (rtimer->start.tv_usec > rtimer->end.tv_usec) + { + rtimer->end.tv_usec += 1000000; + rtimer->end.tv_sec--; + } + + elapsed.tv_usec = rtimer->end.tv_usec - rtimer->start.tv_usec; + elapsed.tv_sec = rtimer->end.tv_sec - rtimer->start.tv_sec; + + total = elapsed.tv_sec + ((gdouble) elapsed.tv_usec / 1e6); + + if (microseconds) + *microseconds = elapsed.tv_usec; + + return total; +} diff --git a/glib/gtree.c b/glib/gtree.c new file mode 100644 index 0000000000..61a32a409a --- /dev/null +++ b/glib/gtree.c @@ -0,0 +1,718 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "glib.h" + + +typedef struct _GRealTree GRealTree; +typedef struct _GTreeNode GTreeNode; + +struct _GRealTree +{ + GTreeNode *root; + GCompareFunc key_compare; +}; + +struct _GTreeNode +{ + gint balance; /* height (left) - height (right) */ + GTreeNode *left; /* left subtree */ + GTreeNode *right; /* right subtree */ + gpointer key; /* key for this node */ + gpointer value; /* value stored at this node */ +}; + + +static GTreeNode* g_tree_node_new (gpointer key, + gpointer value); +static void g_tree_node_destroy (GTreeNode *node); +static GTreeNode* g_tree_node_insert (GTreeNode *node, + GCompareFunc compare, + gpointer key, + gpointer value, + gint *inserted); +static GTreeNode* g_tree_node_remove (GTreeNode *node, + GCompareFunc compare, + gpointer key); +static GTreeNode* g_tree_node_balance (GTreeNode *node); +static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node, + GTreeNode **leftmost); +static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node, + gint old_balance); +static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node, + gint old_balance); +static gpointer g_tree_node_lookup (GTreeNode *node, + GCompareFunc compare, + gpointer key); +static gint g_tree_node_count (GTreeNode *node); +static gint g_tree_node_pre_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data); +static gint g_tree_node_in_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data); +static gint g_tree_node_post_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data); +static gpointer g_tree_node_search (GTreeNode *node, + GSearchFunc search_func, + gpointer data); +static gint g_tree_node_height (GTreeNode *node); +static GTreeNode* g_tree_node_rotate_left (GTreeNode *node); +static GTreeNode* g_tree_node_rotate_right (GTreeNode *node); +static void g_tree_node_check (GTreeNode *node); + + +static GMemChunk *node_mem_chunk = NULL; +static GSList *node_free_list = NULL; + + +GTree* +g_tree_new (GCompareFunc key_compare_func) +{ + GRealTree *rtree; + + rtree = g_new (GRealTree, 1); + rtree->root = NULL; + rtree->key_compare = key_compare_func; + + return (GTree*) rtree; +} + +void +g_tree_destroy (GTree *tree) +{ + GRealTree *rtree; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + g_tree_node_destroy (rtree->root); + g_free (rtree); +} + +void +g_tree_insert (GTree *tree, + gpointer key, + gpointer value) +{ + GRealTree *rtree; + gint inserted; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + inserted = FALSE; + rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare, + key, value, &inserted); +} + +void +g_tree_remove (GTree *tree, + gpointer key) +{ + GRealTree *rtree; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key); +} + +gpointer +g_tree_lookup (GTree *tree, + gpointer key) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, NULL); + + rtree = (GRealTree*) tree; + + return g_tree_node_lookup (rtree->root, rtree->key_compare, key); +} + +void +g_tree_traverse (GTree *tree, + GTraverseFunc traverse_func, + GTraverseType traverse_type, + gpointer data) +{ + GRealTree *rtree; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + g_return_if_fail (rtree->root != NULL); + + switch (traverse_type) + { + case G_PRE_ORDER: + g_tree_node_pre_order (rtree->root, traverse_func, data); + break; + + case G_IN_ORDER: + g_tree_node_in_order (rtree->root, traverse_func, data); + break; + + case G_POST_ORDER: + g_tree_node_post_order (rtree->root, traverse_func, data); + break; + } +} + +gpointer +g_tree_search (GTree *tree, + GSearchFunc search_func, + gpointer data) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, NULL); + + rtree = (GRealTree*) tree; + + if (rtree->root) + return g_tree_node_search (rtree->root, search_func, data); + return NULL; +} + +gint +g_tree_height (GTree *tree) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, 0); + + rtree = (GRealTree*) tree; + + if (rtree->root) + return g_tree_node_height (rtree->root); + return 0; +} + +gint +g_tree_nnodes (GTree *tree) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, 0); + + rtree = (GRealTree*) tree; + + if (rtree->root) + return g_tree_node_count (rtree->root); + return 0; +} + + +static GTreeNode* +g_tree_node_new (gpointer key, + gpointer value) +{ + GTreeNode *node; + GSList *tmp_list; + + if (node_free_list) + { + tmp_list = node_free_list; + node_free_list = node_free_list->next; + + node = tmp_list->data; + + { + GListAllocator *tmp_allocator = g_list_set_allocator (NULL); + g_slist_free_1 (tmp_list); + g_list_set_allocator (tmp_allocator); + } + } + else + { + if (!node_mem_chunk) + node_mem_chunk = g_mem_chunk_new ("tree node mem chunk", sizeof (GTreeNode), 1024, G_ALLOC_ONLY); + + node = g_chunk_new (GTreeNode, node_mem_chunk); + } + + node->balance = 0; + node->left = NULL; + node->right = NULL; + node->key = key; + node->value = value; + + return node; +} + +static void +g_tree_node_destroy (GTreeNode *node) +{ + if (node) + { + node_free_list = g_slist_prepend (node_free_list, node); + g_tree_node_destroy (node->right); + g_tree_node_destroy (node->left); + } +} + +static GTreeNode* +g_tree_node_insert (GTreeNode *node, + GCompareFunc compare, + gpointer key, + gpointer value, + gint *inserted) +{ + gint old_balance; + gint cmp; + + if (!node) + { + *inserted = TRUE; + return g_tree_node_new (key, value); + } + + cmp = (* compare) (key, node->key); + if (cmp == 0) + { + *inserted = FALSE; + node->value = value; + return node; + } + + if (cmp < 0) + { + if (node->left) + { + old_balance = node->left->balance; + node->left = g_tree_node_insert (node->left, compare, key, value, inserted); + + if ((old_balance != node->left->balance) && node->left->balance) + node->balance -= 1; + } + else + { + *inserted = TRUE; + node->left = g_tree_node_new (key, value); + node->balance -= 1; + } + } + else if (cmp > 0) + { + if (node->right) + { + old_balance = node->right->balance; + node->right = g_tree_node_insert (node->right, compare, key, value, inserted); + + if ((old_balance != node->right->balance) && node->right->balance) + node->balance += 1; + } + else + { + *inserted = TRUE; + node->right = g_tree_node_new (key, value); + node->balance += 1; + } + } + + if (*inserted) + { + if ((node->balance < -1) || (node->balance > 1)) + node = g_tree_node_balance (node); + } + + return node; +} + +static GTreeNode* +g_tree_node_remove (GTreeNode *node, + GCompareFunc compare, + gpointer key) +{ + GTreeNode *garbage; + GTreeNode *new_root; + gint old_balance; + gint cmp; + + if (!node) + return NULL; + + cmp = (* compare) (key, node->key); + if (cmp == 0) + { + garbage = node; + + if (!node->right) + { + node = node->left; + } + else + { + old_balance = node->right->balance; + node->right = g_tree_node_remove_leftmost (node->right, &new_root); + new_root->left = node->left; + new_root->right = node->right; + new_root->balance = node->balance; + node = g_tree_node_restore_right_balance (new_root, old_balance); + } + + node_free_list = g_slist_prepend (node_free_list, garbage); + } + else if (cmp < 0) + { + if (node->left) + { + old_balance = node->left->balance; + node->left = g_tree_node_remove (node->left, compare, key); + node = g_tree_node_restore_left_balance (node, old_balance); + } + } + else if (cmp > 0) + { + if (node->right) + { + old_balance = node->right->balance; + node->right = g_tree_node_remove (node->right, compare, key); + node = g_tree_node_restore_right_balance (node, old_balance); + } + } + + return node; +} + +static GTreeNode* +g_tree_node_balance (GTreeNode *node) +{ + if (node->balance < -1) + { + if (node->left->balance > 0) + node->left = g_tree_node_rotate_left (node->left); + node = g_tree_node_rotate_right (node); + } + else if (node->balance > 1) + { + if (node->right->balance < 0) + node->right = g_tree_node_rotate_right (node->right); + node = g_tree_node_rotate_left (node); + } + + return node; +} + +static GTreeNode* +g_tree_node_remove_leftmost (GTreeNode *node, + GTreeNode **leftmost) +{ + gint old_balance; + + if (!node->left) + { + *leftmost = node; + return node->right; + } + + old_balance = node->left->balance; + node->left = g_tree_node_remove_leftmost (node->left, leftmost); + return g_tree_node_restore_left_balance (node, old_balance); +} + +static GTreeNode* +g_tree_node_restore_left_balance (GTreeNode *node, + gint old_balance) +{ + if (!node->left) + node->balance += 1; + else if ((node->left->balance != old_balance) && + (node->left->balance == 0)) + node->balance += 1; + + if (node->balance > 1) + return g_tree_node_balance (node); + return node; +} + +static GTreeNode* +g_tree_node_restore_right_balance (GTreeNode *node, + gint old_balance) +{ + if (!node->right) + node->balance -= 1; + else if ((node->right->balance != old_balance) && + (node->right->balance == 0)) + node->balance -= 1; + + if (node->balance < -1) + return g_tree_node_balance (node); + return node; +} + +static gpointer +g_tree_node_lookup (GTreeNode *node, + GCompareFunc compare, + gpointer key) +{ + gint cmp; + + if (!node) + return NULL; + + cmp = (* compare) (key, node->key); + if (cmp == 0) + return node->value; + + if (cmp < 0) + { + if (node->left) + return g_tree_node_lookup (node->left, compare, key); + } + else if (cmp > 0) + { + if (node->right) + return g_tree_node_lookup (node->right, compare, key); + } + + return NULL; +} + +static gint +g_tree_node_count (GTreeNode *node) +{ + gint count; + + count = 1; + if (node->left) + count += g_tree_node_count (node->left); + if (node->right) + count += g_tree_node_count (node->right); + + return count; +} + +static gint +g_tree_node_pre_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data) +{ + if ((*traverse_func) (node->key, node->value, data)) + return TRUE; + if (node->left) + { + if (g_tree_node_pre_order (node->left, traverse_func, data)) + return TRUE; + } + if (node->right) + { + if (g_tree_node_pre_order (node->right, traverse_func, data)) + return TRUE; + } + + return FALSE; +} + +static gint +g_tree_node_in_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data) +{ + if (node->left) + { + if (g_tree_node_in_order (node->left, traverse_func, data)) + return TRUE; + } + if ((*traverse_func) (node->key, node->value, data)) + return TRUE; + if (node->right) + { + if (g_tree_node_in_order (node->right, traverse_func, data)) + return TRUE; + } + + return FALSE; +} + +static gint +g_tree_node_post_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data) +{ + if (node->left) + { + if (g_tree_node_post_order (node->left, traverse_func, data)) + return TRUE; + } + if (node->right) + { + if (g_tree_node_post_order (node->right, traverse_func, data)) + return TRUE; + } + if ((*traverse_func) (node->key, node->value, data)) + return TRUE; + + return FALSE; +} + +static gpointer +g_tree_node_search (GTreeNode *node, + GSearchFunc search_func, + gpointer data) +{ + gint dir; + + if (!node) + return NULL; + + do { + dir = (* search_func) (node->key, data); + if (dir == 0) + return node->value; + + if (dir < 0) + node = node->left; + else if (dir > 0) + node = node->right; + } while (node && (dir != 0)); + + return NULL; +} + +static gint +g_tree_node_height (GTreeNode *node) +{ + gint left_height; + gint right_height; + + if (node) + { + left_height = 0; + right_height = 0; + + if (node->left) + left_height = g_tree_node_height (node->left); + + if (node->right) + right_height = g_tree_node_height (node->right); + + return MAX (left_height, right_height) + 1; + } + + return 0; +} + +static GTreeNode* +g_tree_node_rotate_left (GTreeNode *node) +{ + GTreeNode *left; + GTreeNode *right; + gint a_bal; + gint b_bal; + + left = node->left; + right = node->right; + + node->right = right->left; + right->left = node; + + a_bal = node->balance; + b_bal = right->balance; + + if (b_bal <= 0) + { + if (a_bal >= 1) + right->balance = b_bal - 1; + else + right->balance = a_bal + b_bal - 2; + node->balance = a_bal - 1; + } + else + { + if (a_bal <= b_bal) + right->balance = a_bal - 2; + else + right->balance = b_bal - 1; + node->balance = a_bal - b_bal - 1; + } + + return right; +} + +static GTreeNode* +g_tree_node_rotate_right (GTreeNode *node) +{ + GTreeNode *left; + GTreeNode *right; + gint a_bal; + gint b_bal; + + left = node->left; + right = node->right; + + node->left = left->right; + left->right = node; + + a_bal = node->balance; + b_bal = left->balance; + + if (b_bal <= 0) + { + if (b_bal > a_bal) + left->balance = b_bal + 1; + else + left->balance = a_bal + 2; + node->balance = a_bal - b_bal + 1; + } + else + { + if (a_bal <= -1) + left->balance = b_bal + 1; + else + left->balance = a_bal + b_bal + 2; + node->balance = a_bal + 1; + } + + return left; +} + +static void +g_tree_node_check (GTreeNode *node) +{ + gint left_height; + gint right_height; + gint balance; + + if (node) + { + left_height = 0; + right_height = 0; + + if (node->left) + left_height = g_tree_node_height (node->left); + if (node->right) + right_height = g_tree_node_height (node->right); + + balance = right_height - left_height; + if (balance != node->balance) + g_print ("g_tree_node_check: failed: %d ( %d )\n", + balance, node->balance); + + if (node->left) + g_tree_node_check (node->left); + if (node->right) + g_tree_node_check (node->right); + } +} diff --git a/glib/gutils.c b/glib/gutils.c new file mode 100644 index 0000000000..c153328176 --- /dev/null +++ b/glib/gutils.c @@ -0,0 +1,732 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdarg.h> +#include <stdio.h> +#include <string.h> +#include "glib.h" + + +static GErrorFunc error_func = NULL; +static GWarningFunc warning_func = NULL; +static GPrintFunc message_func = NULL; +static GPrintFunc print_func = NULL; + +extern char* g_vsprintf (gchar *fmt, va_list *args, va_list *args2); + +gchar* +g_strdup (const gchar *str) +{ + gchar *new_str; + + new_str = NULL; + if (str) + { + new_str = g_new (char, strlen (str) + 1); + strcpy (new_str, str); + } + + return new_str; +} + +gchar* +g_strerror (gint errnum) +{ + static char msg[64]; + +#ifdef HAVE_STRERROR + return strerror (errnum); +#elif NO_SYS_ERRLIST + switch (errnum) + { +#ifdef E2BIG + case E2BIG: return "argument list too long"; +#endif +#ifdef EACCES + case EACCES: return "permission denied"; +#endif +#ifdef EADDRINUSE + case EADDRINUSE: return "address already in use"; +#endif +#ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return "can't assign requested address"; +#endif +#ifdef EADV + case EADV: return "advertise error"; +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return "address family not supported by protocol family"; +#endif +#ifdef EAGAIN + case EAGAIN: return "no more processes"; +#endif +#ifdef EALIGN + case EALIGN: return "EALIGN"; +#endif +#ifdef EALREADY + case EALREADY: return "operation already in progress"; +#endif +#ifdef EBADE + case EBADE: return "bad exchange descriptor"; +#endif +#ifdef EBADF + case EBADF: return "bad file number"; +#endif +#ifdef EBADFD + case EBADFD: return "file descriptor in bad state"; +#endif +#ifdef EBADMSG + case EBADMSG: return "not a data message"; +#endif +#ifdef EBADR + case EBADR: return "bad request descriptor"; +#endif +#ifdef EBADRPC + case EBADRPC: return "RPC structure is bad"; +#endif +#ifdef EBADRQC + case EBADRQC: return "bad request code"; +#endif +#ifdef EBADSLT + case EBADSLT: return "invalid slot"; +#endif +#ifdef EBFONT + case EBFONT: return "bad font file format"; +#endif +#ifdef EBUSY + case EBUSY: return "mount device busy"; +#endif +#ifdef ECHILD + case ECHILD: return "no children"; +#endif +#ifdef ECHRNG + case ECHRNG: return "channel number out of range"; +#endif +#ifdef ECOMM + case ECOMM: return "communication error on send"; +#endif +#ifdef ECONNABORTED + case ECONNABORTED: return "software caused connection abort"; +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: return "connection refused"; +#endif +#ifdef ECONNRESET + case ECONNRESET: return "connection reset by peer"; +#endif +#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) + case EDEADLK: return "resource deadlock avoided"; +#endif +#ifdef EDEADLOCK + case EDEADLOCK: return "resource deadlock avoided"; +#endif +#ifdef EDESTADDRREQ + case EDESTADDRREQ: return "destination address required"; +#endif +#ifdef EDIRTY + case EDIRTY: return "mounting a dirty fs w/o force"; +#endif +#ifdef EDOM + case EDOM: return "math argument out of range"; +#endif +#ifdef EDOTDOT + case EDOTDOT: return "cross mount point"; +#endif +#ifdef EDQUOT + case EDQUOT: return "disk quota exceeded"; +#endif +#ifdef EDUPPKG + case EDUPPKG: return "duplicate package name"; +#endif +#ifdef EEXIST + case EEXIST: return "file already exists"; +#endif +#ifdef EFAULT + case EFAULT: return "bad address in system call argument"; +#endif +#ifdef EFBIG + case EFBIG: return "file too large"; +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: return "host is down"; +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: return "host is unreachable"; +#endif +#ifdef EIDRM + case EIDRM: return "identifier removed"; +#endif +#ifdef EINIT + case EINIT: return "initialization error"; +#endif +#ifdef EINPROGRESS + case EINPROGRESS: return "operation now in progress"; +#endif +#ifdef EINTR + case EINTR: return "interrupted system call"; +#endif +#ifdef EINVAL + case EINVAL: return "invalid argument"; +#endif +#ifdef EIO + case EIO: return "I/O error"; +#endif +#ifdef EISCONN + case EISCONN: return "socket is already connected"; +#endif +#ifdef EISDIR + case EISDIR: return "illegal operation on a directory"; +#endif +#ifdef EISNAME + case EISNAM: return "is a name file"; +#endif +#ifdef ELBIN + case ELBIN: return "ELBIN"; +#endif +#ifdef EL2HLT + case EL2HLT: return "level 2 halted"; +#endif +#ifdef EL2NSYNC + case EL2NSYNC: return "level 2 not synchronized"; +#endif +#ifdef EL3HLT + case EL3HLT: return "level 3 halted"; +#endif +#ifdef EL3RST + case EL3RST: return "level 3 reset"; +#endif +#ifdef ELIBACC + case ELIBACC: return "can not access a needed shared library"; +#endif +#ifdef ELIBBAD + case ELIBBAD: return "accessing a corrupted shared library"; +#endif +#ifdef ELIBEXEC + case ELIBEXEC: return "can not exec a shared library directly"; +#endif +#ifdef ELIBMAX + case ELIBMAX: return "attempting to link in more shared libraries than system limit"; +#endif +#ifdef ELIBSCN + case ELIBSCN: return ".lib section in a.out corrupted"; +#endif +#ifdef ELNRNG + case ELNRNG: return "link number out of range"; +#endif +#ifdef ELOOP + case ELOOP: return "too many levels of symbolic links"; +#endif +#ifdef EMFILE + case EMFILE: return "too many open files"; +#endif +#ifdef EMLINK + case EMLINK: return "too many links"; +#endif +#ifdef EMSGSIZE + case EMSGSIZE: return "message too long"; +#endif +#ifdef EMULTIHOP + case EMULTIHOP: return "multihop attempted"; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: return "file name too long"; +#endif +#ifdef ENAVAIL + case ENAVAIL: return "not available"; +#endif +#ifdef ENET + case ENET: return "ENET"; +#endif +#ifdef ENETDOWN + case ENETDOWN: return "network is down"; +#endif +#ifdef ENETRESET + case ENETRESET: return "network dropped connection on reset"; +#endif +#ifdef ENETUNREACH + case ENETUNREACH: return "network is unreachable"; +#endif +#ifdef ENFILE + case ENFILE: return "file table overflow"; +#endif +#ifdef ENOANO + case ENOANO: return "anode table overflow"; +#endif +#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR)) + case ENOBUFS: return "no buffer space available"; +#endif +#ifdef ENOCSI + case ENOCSI: return "no CSI structure available"; +#endif +#ifdef ENODATA + case ENODATA: return "no data available"; +#endif +#ifdef ENODEV + case ENODEV: return "no such device"; +#endif +#ifdef ENOENT + case ENOENT: return "no such file or directory"; +#endif +#ifdef ENOEXEC + case ENOEXEC: return "exec format error"; +#endif +#ifdef ENOLCK + case ENOLCK: return "no locks available"; +#endif +#ifdef ENOLINK + case ENOLINK: return "link has be severed"; +#endif +#ifdef ENOMEM + case ENOMEM: return "not enough memory"; +#endif +#ifdef ENOMSG + case ENOMSG: return "no message of desired type"; +#endif +#ifdef ENONET + case ENONET: return "machine is not on the network"; +#endif +#ifdef ENOPKG + case ENOPKG: return "package not installed"; +#endif +#ifdef ENOPROTOOPT + case ENOPROTOOPT: return "bad proocol option"; +#endif +#ifdef ENOSPC + case ENOSPC: return "no space left on device"; +#endif +#ifdef ENOSR + case ENOSR: return "out of stream resources"; +#endif +#ifdef ENOSTR + case ENOSTR: return "not a stream device"; +#endif +#ifdef ENOSYM + case ENOSYM: return "unresolved symbol name"; +#endif +#ifdef ENOSYS + case ENOSYS: return "function not implemented"; +#endif +#ifdef ENOTBLK + case ENOTBLK: return "block device required"; +#endif +#ifdef ENOTCONN + case ENOTCONN: return "socket is not connected"; +#endif +#ifdef ENOTDIR + case ENOTDIR: return "not a directory"; +#endif +#ifdef ENOTEMPTY + case ENOTEMPTY: return "directory not empty"; +#endif +#ifdef ENOTNAM + case ENOTNAM: return "not a name file"; +#endif +#ifdef ENOTSOCK + case ENOTSOCK: return "socket operation on non-socket"; +#endif +#ifdef ENOTTY + case ENOTTY: return "inappropriate device for ioctl"; +#endif +#ifdef ENOTUNIQ + case ENOTUNIQ: return "name not unique on network"; +#endif +#ifdef ENXIO + case ENXIO: return "no such device or address"; +#endif +#ifdef EOPNOTSUPP + case EOPNOTSUPP: return "operation not supported on socket"; +#endif +#ifdef EPERM + case EPERM: return "not owner"; +#endif +#ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return "protocol family not supported"; +#endif +#ifdef EPIPE + case EPIPE: return "broken pipe"; +#endif +#ifdef EPROCLIM + case EPROCLIM: return "too many processes"; +#endif +#ifdef EPROCUNAVAIL + case EPROCUNAVAIL: return "bad procedure for program"; +#endif +#ifdef EPROGMISMATCH + case EPROGMISMATCH: return "program version wrong"; +#endif +#ifdef EPROGUNAVAIL + case EPROGUNAVAIL: return "RPC program not available"; +#endif +#ifdef EPROTO + case EPROTO: return "protocol error"; +#endif +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return "protocol not suppored"; +#endif +#ifdef EPROTOTYPE + case EPROTOTYPE: return "protocol wrong type for socket"; +#endif +#ifdef ERANGE + case ERANGE: return "math result unrepresentable"; +#endif +#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED)) + case EREFUSED: return "EREFUSED"; +#endif +#ifdef EREMCHG + case EREMCHG: return "remote address changed"; +#endif +#ifdef EREMDEV + case EREMDEV: return "remote device"; +#endif +#ifdef EREMOTE + case EREMOTE: return "pathname hit remote file system"; +#endif +#ifdef EREMOTEIO + case EREMOTEIO: return "remote i/o error"; +#endif +#ifdef EREMOTERELEASE + case EREMOTERELEASE: return "EREMOTERELEASE"; +#endif +#ifdef EROFS + case EROFS: return "read-only file system"; +#endif +#ifdef ERPCMISMATCH + case ERPCMISMATCH: return "RPC version is wrong"; +#endif +#ifdef ERREMOTE + case ERREMOTE: return "object is remote"; +#endif +#ifdef ESHUTDOWN + case ESHUTDOWN: return "can't send afer socket shutdown"; +#endif +#ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return "socket type not supported"; +#endif +#ifdef ESPIPE + case ESPIPE: return "invalid seek"; +#endif +#ifdef ESRCH + case ESRCH: return "no such process"; +#endif +#ifdef ESRMNT + case ESRMNT: return "srmount error"; +#endif +#ifdef ESTALE + case ESTALE: return "stale remote file handle"; +#endif +#ifdef ESUCCESS + case ESUCCESS: return "Error 0"; +#endif +#ifdef ETIME + case ETIME: return "timer expired"; +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: return "connection timed out"; +#endif +#ifdef ETOOMANYREFS + case ETOOMANYREFS: return "too many references: can't splice"; +#endif +#ifdef ETXTBSY + case ETXTBSY: return "text file or pseudo-device busy"; +#endif +#ifdef EUCLEAN + case EUCLEAN: return "structure needs cleaning"; +#endif +#ifdef EUNATCH + case EUNATCH: return "protocol driver not attached"; +#endif +#ifdef EUSERS + case EUSERS: return "too many users"; +#endif +#ifdef EVERSION + case EVERSION: return "version mismatch"; +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: return "operation would block"; +#endif +#ifdef EXDEV + case EXDEV: return "cross-domain link"; +#endif +#ifdef EXFULL + case EXFULL: return "message tables full"; +#endif + } +#else /* NO_SYS_ERRLIST */ + extern int sys_nerr; + extern char *sys_errlist[]; + + if ((errnum > 0) && (errnum <= sys_nerr)) + return sys_errlist [errnum]; +#endif /* NO_SYS_ERRLIST */ + + sprintf (msg, "unknown error (%d)", errnum); + return msg; +} + +gchar* +g_strsignal (gint signum) +{ + static char msg[64]; + +#ifdef HAVE_STRSIGNAL + extern char *strsignal (int sig); + return strsignal (signum); +#elif NO_SYS_SIGLIST + switch (signum) + { +#ifdef SIGHUP + case SIGHUP: return "Hangup"; +#endif +#ifdef SIGINT + case SIGINT: return "Interrupt"; +#endif +#ifdef SIGQUIT + case SIGQUIT: return "Quit"; +#endif +#ifdef SIGILL + case SIGILL: "Illegal instruction"; +#endif +#ifdef SIGTRAP + case SIGTRAP: "Trace/breakpoint trap"; +#endif +#ifdef SIGABRT + case SIGABRT: "IOT trap/Abort"; +#endif +#ifdef SIGBUS + case SIGBUS: "Bus error"; +#endif +#ifdef SIGFPE + case SIGFPE: "Floating point exception"; +#endif +#ifdef SIGKILL + case SIGKILL: "Killed"; +#endif +#ifdef SIGUSR1 + case SIGUSR1: "User defined signal 1"; +#endif +#ifdef SIGSEGV + case SIGSEGV: "Segmentation fault"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: "User defined signal 2"; +#endif +#ifdef SIGPIPE + case SIGPIPE: "Broken pipe"; +#endif +#ifdef SIGALRM + case SIGALRM: "Alarm clock"; +#endif +#ifdef SIGTERM + case SIGTERM: "Terminated"; +#endif +#ifdef SIGSTKFLT + case SIGSTKFLT: "Stack fault"; +#endif +#ifdef SIGCHLD + case SIGCHLD: "Child exited"; +#endif +#ifdef SIGCONT + case SIGCONT: "Continued"; +#endif +#ifdef SIGSTOP + case SIGSTOP: "Stopped (signal)"; +#endif +#ifdef SIGTSTP + case SIGTSTP: "Stopped"; +#endif +#ifdef SIGTTIN + case SIGTTIN: "Stopped (tty input)"; +#endif +#ifdef SIGTTOU + case SIGTTOU: "Stopped (tty output)"; +#endif +#ifdef SIGURG + case SIGURG: "Urgent condition"; +#endif +#ifdef SIGXCPU + case SIGXCPU: "CPU time limit exceeded"; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: "File size limit exceeded"; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: "Virtual time alarm"; +#endif +#ifdef SIGPROF + case SIGPROF: "Profile signal"; +#endif +#ifdef SIGWINCH + case SIGWINCH: "Window size changed"; +#endif +#ifdef SIGIO + case SIGIO: "Possible I/O"; +#endif +#ifdef SIGPWR + case SIGPWR: "Power failure"; +#endif +#ifdef SIGUNUSED + case SIGUNUSED: return "Unused signal"; +#endif + } +#else /* NO_SYS_SIGLIST */ + extern char *sys_siglist[]; + return sys_siglist [signum]; +#endif /* NO_SYS_SIGLIST */ + + sprintf (msg, "unknown signal (%d)", signum); + return msg; +} + +void +g_error (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (error_func) + { + (* error_func) (buf); + } + else + { + fputs ("\n** ERROR **: ", stderr); + fputs (buf, stderr); + fputc ('\n', stderr); + } + + abort (); +} + +void +g_warning (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (warning_func) + { + (* warning_func) (buf); + } + else + { + fputs ("\n** WARNING **: ", stderr); + fputs (buf, stderr); + fputc ('\n', stderr); + } +} + +void +g_message (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (message_func) + { + (* message_func) (buf); + } + else + { + fputs ("message: ", stdout); + fputs (buf, stdout); + fputc ('\n', stdout); + } +} + +void +g_print (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (print_func) + { + (* print_func) (buf); + } + else + { + fputs (buf, stdout); + } +} + +GErrorFunc +g_set_error_handler (GErrorFunc func) +{ + GErrorFunc old_error_func; + + old_error_func = error_func; + error_func = func; + + return old_error_func; +} + +GWarningFunc +g_set_warning_handler (GWarningFunc func) +{ + GWarningFunc old_warning_func; + + old_warning_func = warning_func; + warning_func = func; + + return old_warning_func; +} + +GPrintFunc +g_set_message_handler (GPrintFunc func) +{ + GPrintFunc old_message_func; + + old_message_func = message_func; + message_func = func; + + return old_message_func; +} + +GPrintFunc +g_set_print_handler (GPrintFunc func) +{ + GPrintFunc old_print_func; + + old_print_func = print_func; + print_func = func; + + return old_print_func; +} diff --git a/glib/install-sh b/glib/install-sh new file mode 100755 index 0000000000..89fc9b098b --- /dev/null +++ b/glib/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# 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}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + 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;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + 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` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/glib/ltconfig b/glib/ltconfig new file mode 100755 index 0000000000..e9d3a83795 --- /dev/null +++ b/glib/ltconfig @@ -0,0 +1,1415 @@ +#! /bin/sh + +# ltconfig - Create a system-specific libtool. +# Generated automatically from ltconfig.in by configure. +# Copyright (C) 1996, 1997, Free Software Foundation, Inc. +# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This file 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. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A lot of this script is taken from autoconf-2.10. + +# The name of this program. +progname=`echo "$0" | sed 's%^.*/%%'` + +# Constants: +PROGRAM=ltconfig +PACKAGE=libtool +VERSION=1.0f +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5' +rm="rm -f" + +help="Try \`$progname --help' for more information." + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$\\\\]\)/\\\1/g' + +# Same as above, but don't quote variable references. +double_quote_subst='s/\([\\"\\\\]\)/\\\1/g' + +# Global variables: +can_build_shared=yes +enable_shared=yes +# All known linkers require a `.a' archive for static linking. +enable_static=yes +ltmain= +silent= +srcdir= +ac_config_guess= +ac_config_sub= +host= +nonopt= +verify_host=yes +with_gcc=no +with_gnu_ld=no + +old_AR="$AR" +old_CC="$CC" +old_CFLAGS="$CFLAGS" +old_CPPFLAGS="$CPPFLAGS" +old_LD="$LD" +old_LN_S="$LN_S" +old_NM="$NM" +old_RANLIB="$RANLIB" + +# Parse the command line options. +args= +prev= +for option +do + case "$option" in + -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval "$prev=\$option" + prev= + continue + fi + + case "$option" in + --help) cat <<EOM +Usage: $progname [OPTION]... LTMAIN [HOST] + +Generate a system-specific libtool script. + + --disable-shared do not build shared libraries + --disable-static do not build static libraries + --help display this help and exit + --no-verify do not verify that HOST is a valid host type + --quiet same as \`--silent' + --silent don't print informational messages + --srcdir=DIR find \`config.guess' in DIR + --version output version information and exit + --with-gcc assume that the GNU C compiler will be used + --with-gnu-ld assume that the C compiler uses the GNU linker + +LTMAIN is the \`ltmain.sh' shell script fragment that provides basic libtool +functionality. + +HOST is the canonical host system name [default=guessed]. +EOM + exit 0 + ;; + + --disable-shared) enable_shared=no ;; + + --disable-static) enable_static=no ;; + + --quiet | --silent) silent=yes ;; + + --srcdir) prev=srcdir ;; + --srcdir=*) srcdir="$optarg" ;; + + --no-verify) verify_host=no ;; + + --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION"; exit 0 ;; + + --with-gcc) with_gcc=yes ;; + --with-gnu-ld) with_gnu_ld=yes ;; + + -*) + echo "$progname: unrecognized option \`$option'" 1>&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + if test -z "$ltmain"; then + ltmain="$option" + elif test -z "$host"; then +# FIXME This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 +# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then +# echo "$progname: warning \`$option' is not a valid host type" 1>&2 +# fi + host="$option" + else + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac +done + +if test -z "$ltmain"; then + echo "$progname: you must specify a LTMAIN file" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +if test -f "$ltmain"; then : +else + echo "$progname: warning: \`$ltmain' does not exist" 1>&2 +fi + +# Quote any args containing shell metacharacters. +ltconfig_args= +for arg +do + case "$arg" in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ltconfig_args="$ltconfig_args '$arg'" ;; + *) ltconfig_args="$ltconfig_args $arg" ;; + esac +done + +# A relevant subset of AC_INIT. + +# 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 +# 5 compiler messages saved in config.log +# 6 checking for... messages and results +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>>./config.log + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +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 "$srcdir"; then + # Assume the source directory is the same one as the path to ltmain.sh. + srcdir=`echo "$ltmain" | sed 's%/[^/]*$%%'` + test "$srcdir" = "$ltmain" && srcdir=. +fi + +trap "$rm conftest*; exit 1" 1 2 15 +if test "$verify_host" = yes; then + # Check for config.guess and config.sub. + ac_aux_dir= + for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/config.guess; then + ac_aux_dir=$ac_dir + break + fi + done + if test -z "$ac_aux_dir"; then + echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 + echo "$help" 1>&2 + exit 1 + fi + ac_config_guess=$ac_aux_dir/config.guess + ac_config_sub=$ac_aux_dir/config.sub + + # Make sure we can run config.sub. + if $ac_config_sub sun4 >/dev/null 2>&1; then : + else + echo "$progname: cannot run $ac_config_sub" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + echo $ac_n "checking host system type""... $ac_c" 1>&6 + + host_alias=$host + case "$host_alias" in + "") + if host_alias=`$ac_config_guess`; then : + else + echo "$progname: cannot guess host type; you must specify one" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac + host=`$ac_config_sub $host_alias` + echo "$ac_t$host" 1>&6 + + # Make sure the host verified. + test -z "$host" && exit 1 + +elif test -z "$host"; then + echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 + echo "$help" 1>&2 + exit 1 +else + host_alias=$host +fi + +# Transform *-*-linux* to *-*-linux-gnu*, to support old configure scripts. +case "$host" in +*-*-linux-gnu*) ;; +*-*-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +case "$host_os" in +aix*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR cru $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' + +# Set a sane default for `AR'. +test -z "$AR" && AR=ar + +# If RANLIB is not set, then run the test. +if test "${RANLIB+set}" != "set"; then + result=no + + echo $ac_n "checking for ranlib... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/ranlib; then + RANLIB="ranlib" + result="ranlib" + break + fi + done + IFS="$save_ifs" + + echo "$ac_t$result" 1>&6 +fi + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds;\$RANLIB \$oldlib" + old_postinstall_cmds="$old_postinstall_cmds;\$RANLIB \$oldlib" +fi + +# Check to see if we are using GCC. +if test "$with_gcc" != yes || test -z "$CC"; then + # If CC is not set, then try to find GCC or a usable CC. + if test -z "$CC"; then + echo $ac_n "checking for gcc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + IFS="$save_ifs" + test -z "$dir" && dir=. + if test -f $dir/gcc; then + CC="gcc" + break + fi + done + IFS="$save_ifs" + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + fi + + # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". + if test -z "$CC"; then + echo $ac_n "checking for cc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + cc_rejected=no + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/cc; then + if test "$dir/cc" = "/usr/ucb/cc"; then + cc_rejected=yes + continue + fi + CC="cc" + break + fi + done + IFS="$save_ifs" + if test $cc_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same name, so the bogon will be chosen + # first if we set CC to just the name; use the full file name. + shift + set dummy "$dir/cc" "$@" + shift + CC="$@" + fi + fi + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$CC"; then + echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 + exit 1 + fi + fi + + # Now see if the compiler is really GCC. + with_gcc=no + echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 + echo "$progname:394: checking whether we are using GNU C" >&5 + + $rm conftest.c + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF + if { ac_try='${CC-cc} -E conftest.c'; { (eval echo $progname:402: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + with_gcc=yes + fi + $rm conftest.c + echo "$ac_t$with_gcc" 1>&6 +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 +pic_flag= +profile_flag_pattern= +special_shlib_compile_flags= +wl= +link_static_flag= +no_builtin_flag= + +if test "$with_gcc" = yes; then + profile_flag_pattern='-pg?' + wl='-Wl,' + link_static_flag='-static' + no_builtin_flag=' -fno-builtin' + + case "$host_os" in + aix3* | aix4* | irix5* | irix6* | osf3* | osf4*) + # PIC is the default for these OSes. + ;; + os2*) + # We can build DLLs from non-PIC. + ;; + *) + pic_flag='-fPIC' + ;; + esac +else + # PORTME Check for PIC flags for the system compiler. + case "$host_os" in + aix3* | aix4*) + # All AIX code is PIC. + link_static_flag='-bnso -bI:/lib/syscalls.exp' + ;; + + hpux9* | hpux10*) + # Is there a better link_static_flag that works with the bundled CC? + wl='-Wl,' + link_static_flag='${wl}-a ${wl}archive' + pic_flag='+Z' + ;; + + irix5* | irix6*) + wl='-Wl,' + link_static_flag='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + os2*) + # We can build DLLs from non-PIC. + ;; + + osf3* | osf4*) + # All OSF/1 code is PIC. + wl='-Wl,' + link_static_flag='-non_shared' + ;; + + sco3.2v5*) + pic_flag='-Kpic' + link_static_flag='-dn' + special_shlib_compile_flags='-belf' + ;; + + solaris2*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + sunos4*) + pic_flag='-PIC' + link_static_flag='-Bstatic' + wl='-Qoption ld ' + ;; + + uts4*) + pic_flag='-pic' + link_static_flag='-Bstatic' + ;; + + *) + can_build_shared=no + ;; + esac +fi + +if test -n "$pic_flag"; then + echo "$ac_t$pic_flag" 1>&6 + + # Check to make sure the pic_flag actually works. + echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 + $rm conftest* + echo > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $pic_flag -DPIC" + echo "$progname:507: checking if $compiler PIC flag $pic_flag works" >&5 + if { (eval echo $progname:508: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + + # On HP-UX, the stripped-down bundled CC doesn't accept +Z, but also + # reports no error. So, we need to grep stderr for (Bundled). + if grep '(Bundled)' conftest.err >/dev/null; then + echo "$ac_t"no 1>&6 + can_build_shared=no + pic_flag= + else + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + can_build_shared=no + pic_flag= + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + echo "$ac_t"none 1>&6 +fi + +# Check for any special shared library compilation flags. +if test -n "$special_shlib_compile_flags"; then + echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : + else + echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 + can_build_shared=no + fi +fi + +echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 +$rm conftest* +echo 'main(){return(0);}' > conftest.c +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $link_static_flag" +echo "$progname:550: checking if $compiler static flag $link_static_flag works" >&5 +if { (eval echo $progname:551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + echo "$ac_t$link_static_flag" 1>&6 +else + echo "$ac_t"none 1>&6 + link_static_flag= +fi +LDFLAGS="$save_LDFLAGS" +$rm conftest* + +if test -z "$LN_S"; then + # Check to see if we can use ln -s, or we need hard links. + echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 + $rm conftestdata + if ln -s X conftestdata 2>/dev/null; then + $rm conftestdata + LN_S="ln -s" + else + LN_S=ln + fi + if test "$LN_S" = "ln -s"; then + echo "$ac_t"yes 1>&6 + else + echo "$ac_t"no 1>&6 + fi +fi + +# Make sure LD is an absolute path. +if test -z "$LD"; then + ac_prog=ld + if test "$with_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 + echo "$progname:583: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac + elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld... $ac_c" 1>&6 + echo "$progname:601: checking for GNU ld" >&5 + else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 + echo "$progname:604: checking for non-GNU ld" >&5 + fi + + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" + fi + + if test -n "$LD"; then + echo "$ac_t$LD" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$LD"; then + echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 + exit 1 + fi +fi + +# Check to see if it really is or isn't GNU ld. +echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 +# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + with_gnu_ld=yes +else + with_gnu_ld=no +fi +echo "$ac_t$with_gnu_ld" 1>&6 + +# See if the linker supports building shared libraries. +echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 + +allow_undefined_flag= +archive_cmds= +old_archive_from_new_cmds= +export_dynamic_flag_spec= +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_runpath_var=no +hardcode_shlibpath_var=unsupported +runpath_var= + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # See if GNU ld supports shared libraries. + + case "$host_os" in + sunos4*) + ld_shlibs=yes + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + archive_cmds='$CC -shared ${wl}-soname $wl$soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath $wl$libdir' + export_dynamic_flag_spec='${wl}-export-dynamic' + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case "$host_os" in + aix3*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$LD -o $objdir/$soname$libobjs -bE:$lib.exp -T512 -H512 -bM:SRE$deplibs;$AR cru $lib $objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$with_gcc" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$CC -o $objdir/$soname$libobjs ${wl}-bE:$lib.exp ${wl}-bM:SRE ${wl}-bnoentry$deplibs;$AR cru $lib $objdir/$soname' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # doesn't break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs /usr/lib/c++rt0.o' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 don't have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3, at last, uses gcc -shared to do shared libraries. + freebsd3*) + archive_cmds='$CC -shared -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + archive_cmds='$rm $objdir/$soname;$LD -b +s +b $install_libdir -o $objdir/$soname$libobjs$deplibs;mv $objdir/$soname $lib' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + hpux10*) + archive_cmds='$LD -b +h $soname +s +b $install_libdir -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + irix5* | irix6*) + archive_cmds='$LD -shared -o $lib -soname $soname -set_version $verstring$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + ;; + + netbsd*) + # Tested with NetBSD 1.2 ld + archive_cmds='$LD -Bshareable -o $lib$libobjs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def;echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def;echo DATA >> $objdir/$libname.def;echo " SINGLE NONSHARED" >> $objdir/$libname.def;echo EXPORTS >> $objdir/$libname.def;emxexp$libobjs >> $objdir/$libname.def;$CC -Zdll -Zcrtdll -o $lib$libobjs $objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' + ;; + + osf3* | osf4*) + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} -o $lib -soname $soname -set_version $verstring$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -o $lib$libobjs$deplibs' + hardcode_direct=yes + ;; + + solaris2*) + archive_cmds='$LD -G -z text -h $soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bstatic -o $lib$libobjs' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + can_build_shared=no + ;; + esac +fi +echo "$ac_t$ld_shlibs" 1>&6 + +if test -z "$NM"; then + echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 + case "$NM" in + /*) ;; # Let the user override the test with a path. + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + NM="$ac_dir/nm -p" + else + NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$NM" && NM=nm + ;; + esac + echo "$ac_t$NM" 1>&6 +fi + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRSTU]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \1' + +# Define system-specific variables. +case "$host_os" in +aix*) + symcode='[BCDTU]' + ;; +solaris2*) + symcode='[BDTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTUW]' +fi + +# Write the raw and C identifiers. +global_symbol_pipe="sed -n -e 's/^.* $symcode $sympat$/$symxfrm/p'" + +# Check to see that the pipe works correctly. +pipe_works=no +$rm conftest* +cat > conftest.c <<EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(){} +#ifdef __cplusplus +} +#endif +main(){nm_test_var='a';nm_test_func();return(0);} +EOF + +echo "$progname:900: checking if global_symbol_pipe works" >&5 +if { (eval echo $progname:901: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.o; then + # Now try to grab the symbols. + nlist=conftest.nm + if { echo "$progname:904: eval \"$NM conftest.o | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.o | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`echo "$wcout" | sed 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + rm -f "$nlist"T + count=-1 + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat <<EOF > conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + sed 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> conftest.c + + cat <<EOF >> conftest.c +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{ +EOF + sed 's/^\(.*\) \(.*\)$/ {"\1", \&\2},/' < "$nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0}, +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.o conftestm.o + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS='conftestm.o' + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo $progname:962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + pipe_works=yes + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$save_LIBS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $global_symbol_pipe" >&5 + fi +else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 +fi +$rm conftest* + +# Don't use the global_symbol_pipe unless it works. +echo "$ac_t$pipe_works" 1>&6 +test "$pipe_works" = yes || global_symbol_pipe= + +# Check hardcoding attributes. +echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test "$hardcode_runpath_var" = yes; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && \ + test "$hardcode_minus_L" != no && \ + test "$hardcode_shlibpath_var" != no; then + + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +elif test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" != yes; then + # We can't hardcode anything. + hardcode_action=unsupported +else + # We can only hardcode existing directories. + hardcode_action=relink +fi +echo "$ac_t$hardcode_action" 1>&6 +test "$hardcode_action" = unsupported && can_build_shared=no + + +reload_flag= +reload_cmds='$LD$reload_flag -o $output$reload_objs' +echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 +# PORTME Some linker may need a different reload flag. +reload_flag='-r' +echo "$ac_t$reload_flag" +test -n "$reload_flag" && reload_flag=" $reload_flag" + +# PORTME Fill in your ld.so characteristics +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +finish_cmds= +shlibpath_var= +version_type=none +dynamic_linker="$host_os ld.so" + +echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 +case "$host_os" in +aix3* | aix4*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='$libname.so.$major' + ;; + +freebsd2* | freebsd3*) + version_type=sunos + library_names_spec='$libname.so.$versuffix $libname.so' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +gnu*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + shlibpath_var=LD_LIBRARY_PATH + ;; + +hpux9* | hpux10*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + shlibpath_var=SHLIB_PATH + library_names_spec='$libname.sl.$versuffix $libname.sl.$major $libname.sl' + soname_spec='$libname.sl.$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=osf + soname_spec='$libname.so' + library_names_spec='$libname.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + + if test -f /lib/ld.so.1; then + dynamic_linker='GNU ld.so' + else + # Only the GNU ld.so supports shared libraries on MkLinux. + case "$host_cpu" in + powerpc*) dynamic_linker=no ;; + *) dynamic_linker='Linux ld.so' ;; + esac + fi + ;; + +netbsd* | openbsd*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + version_type=none + libname_spec='$name' + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4*) + version_type=osf + soname_spec='$libname.so' + library_names_spec='$libname.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sco3.2v5*) + version_type=osf + soname_spec='$libname.so.$major' + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris2*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +uts4*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$ac_t$dynamic_linker" +test "$dynamic_linker" = no && can_build_shared=no + +# FIXME add checks for striplib and old_striplib here. +# strip -x works for most platforms, though not for static libraries on NetBSD +# HP-UX requires "-r" for library stripping +striplib= +old_striplib= + +# Report the final consequences. +echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 + +echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds;\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +esac + +echo "$ac_t$enable_shared" 1>&6 + +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes + +echo "checking whether to build static libraries... $enable_static" 1>&6 + +echo $ac_n "checking for objdir... $ac_c" 1>&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$ac_t$objdir" 1>&6 + +# Now quote all the things that may contain metacharacters. +for var in old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \ + old_LN_S AR CC LD LN_S NM reload_flag reload_cmds wl pic_flag \ + link_static_flag no_builtin_flag export_dynamic_flag_spec \ + profile_flag_pattern libname_spec library_names_spec soname_spec RANLIB \ + old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + archive_cmds postinstall_cmds \ + allow_undefined_flag finish_cmds global_symbol_pipe \ + striplib old_striplib \ + hardcode_libdir_flag_spec hardcode_libdir_separator; do + + case "$var" in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | archive_cmds | postinstall_cmds | finish_cmds) + # Double-quote double-evaled strings. + eval "$var=\`echo \"\$$var\" | sed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\"\`" + ;; + *) + eval "$var=\`echo \"\$$var\" | sed \"\$sed_quote_subst\"\`" + ;; + esac +done + +ofile=libtool +trap "$rm $ofile; exit 1" 1 2 15 +echo creating $ofile +$rm $ofile +cat <<EOF > $ofile +#! /bin/sh + +# libtool - Provide generalized library-building support services. +# +# Generated automatically by $PROGRAM - GNU $PACKAGE $VERSION +# This program was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# CC="$old_CC" CFLAGS="$old_CFLAGS" CPPFLAGS="$old_CPPFLAGS" \\ +# LD="$old_LD" NM="$old_NM" RANLIB="$old_RANLIB" LN_S="$old_LN_S" \\ +# $0$ltconfig_args +# +# Compiler and other test output produced by $progname, useful for +# debugging $progname, is in ./config.log if it exists. + +# The version of $progname that generated this script. +LTCONFIG_VERSION="$VERSION" + +# Shell to use when invoking shell scripts. +SHELL=${CONFIG_SHELL-/bin/sh} + +# Whether or not to build libtool libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build old-style libraries. +build_old_libs=$enable_static + +# The host system. +host_alias="$host_alias" +host="$host" + +# The archiver. +AR="$AR" + +# The default C compiler. +CC="$CC" + +# The linker used to build libraries. +LD="$LD" + +# Whether we need hard or soft links. +LN_S="$LN_S" + +# A BSD-compatible nm program. +NM="$NM" + +# The name of the directory that contains temporary libtool files. +objdir="$objdir" + +# How to create reloadable object files. +reload_flag="$reload_flag" +reload_cmds="$reload_cmds" + +# How to pass a linker flag through the compiler. +wl="$wl" + +# Additional compiler flags for building library objects. +pic_flag="$pic_flag" + +# Compiler flag to prevent dynamic linking. +link_static_flag="$link_static_flag" + +# Compiler flag to turn off builtin functions. +no_builtin_flag="$no_builtin_flag" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="$export_dynamic_flag_spec" + +# Pattern to match compiler flags for creating libNAME_p libraries: +profile_flag_pattern="$profile_flag_pattern" + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec="$libname_spec" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="$library_names_spec" + +# The coded name of the library, if different from the real name. +soname_spec="$soname_spec" + +# Commands used to build and install an old-style archive. +RANLIB="$RANLIB" +old_archive_cmds="$old_archive_cmds" +old_postinstall_cmds="$old_postinstall_cmds" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="$old_archive_from_new_cmds" + +# Commands used to build and install a shared archive. +archive_cmds="$archive_cmds" +postinstall_cmds="$postinstall_cmds" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="$allow_undefined_flag" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="$finish_cmds" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="$global_symbol_pipe" + +# How to strip a library file. +striplib="$striplib" +old_striplib="$old_striplib" + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using RUNPATH_VAR=DIR during linking hardcodes DIR into the +# resulting binary. +hardcode_runpath_var=$hardcode_runpath_var + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +EOF + +case "$host_os" in +aix*) + cat <<\EOF >> $ofile +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES +fi + +EOF + ;; +esac + +# Detect if we are using a relative or absolute path to ltmain.sh. +case "$ltmain" in +/*) cat <<EOF >> $ofile +# Execute the libtool backend. +. $ltmain +EOF + ;; +*) cat <<EOF >> $ofile +# Find the path to this script. +thisdir=\`echo "\$0" | sed -e 's%/[^/]*\$%%'\` +test "X\$0" = "X\$thisdir" && thisdir=. + +# Execute the libtool backend. +. \$thisdir/$ltmain +EOF + ;; +esac + +echo 'exit 1' >> $ofile + +chmod +x $ofile +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/glib/ltmain.sh b/glib/ltmain.sh new file mode 100644 index 0000000000..cb46c84987 --- /dev/null +++ b/glib/ltmain.sh @@ -0,0 +1,2372 @@ +# ltmain.sh - Provide generalized library-building support services. +# Generated automatically from ltmain.in by configure. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program 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. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +#FIXME: echo=echo +echo='printf %s\n' +if test "X`$echo '\t'`" = 'X\t'; then : +else + # The Solaris and AIX default echo program unquotes backslashes. + # This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # So, we emulate echo with printf '%s\n' + echo='printf %s\n' + if test "X`$echo '\t'`" = 'X\t'; then : + else + # Oops. We have no working printf. Try to find a not-so-buggy echo. + echo=echo + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + save_PATH="$PATH" + PATH="$PATH":/usr/ucb + for dir in $PATH; do + if test -f $dir/echo && test "X`$dir/echo '\t'`" = 'X\t'; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + PATH="$save_PATH" + fi +fi + +# The name of this program. +progname=`$echo "$0" | sed 's%^.*/%%'` + +# Constants. +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.0f + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$\\\\]\)/\\\1/g' + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +if test "$LTCONFIG_VERSION" != "$VERSION"; then + $echo "$progname: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + $echo "$progname: not configured to build any kind of library" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case "$arg" in + -*=*) optarg=`$echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + execute_dlfiles) + eval "$prev=\"\$$prev \$arg\"" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case "$arg" in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION" + exit 0 + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$progname: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$progname: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case "$nonopt" in + *cc | *++) + mode=link + for arg + do + case "$arg" in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx) + mode=execute + ;; + *install*|cp) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$progname: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$progname: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$progname: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case "$mode" in + # libtool compile mode + compile) + progname="$progname: compile" + # Get the compilation command and the source file. + base_compile= + lastarg= + srcfile="$nonopt" + suppress_output= + + for arg + do + # The only flag that cannot be specified is the output filename. + if test "X$arg" = "X-o"; then + $echo "$progname: you cannot specify the output filename with \`-o'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "$lastarg" | sed "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly in scan + # sets, so we specify it separately. + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + # Get the name of the library object. + libobj=`$echo "$srcfile" | sed -e 's%^.*/%%'` + + # Recognize several different file suffixes. + xform='[cCFSfm]' + case "$libobj" in + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "$libobj" | sed -e "s/\.$xform$/.lo/"` + + case "$libobj" in + *.lo) obj=`$echo "$libobj" | sed -e 's/\.lo$/.o/'` ;; + *) + $echo "$progname: cannot determine name of library object from \`$srcfile'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$progname: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + $run $rm $obj $libobj + trap "$run $rm $obj $libobj; exit 1" 1 2 15 + else + $run $rm $libobj + trap "$run $rm $libobj; exit 1" 1 2 15 + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + # All platforms use -DPIC, to notify preprocessed assembler code. + $show "$base_compile$pic_flag -DPIC $srcfile" + if $run eval "$base_compile\$pic_flag -DPIC \$srcfile"; then : + else + test -n "$obj" && $run $rm $obj + exit 1 + fi + + # If we have no pic_flag, then copy the object into place and finish. + if test -z "$pic_flag"; then + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj + exit $? + fi + + # Just move the object, then go on to compile the next one + $show "$mv $obj $libobj" + $run $mv $obj $libobj || exit 1 + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + # Suppress compiler output if we already did a PIC compilation. + $show "$base_compile $srcfile$suppress_output" + if $run eval "$base_compile \$srcfile$suppress_output"; then : + else + $run $rm $obj $libobj + exit 1 + fi + fi + + # Create an invalid libtool object if no PIC, so that we don't accidentally + # link it into a program. + if test "$build_libtool_libs" != yes; then + $show "$echo timestamp > $libobj" + $run eval "\$echo timestamp > \$libobj" || exit $? + fi + + exit 0 + ;; + + # libtool link mode + link) + progname="$progname: link" + CC="$nonopt" + allow_undefined=no + compile_command="$CC" + finalize_command="$CC" + + compile_shlibpath= + finalize_shlibpath= + deplibs= + dlfiles= + dlprefiles= + export_dynamic=no + hardcode_libdirs= + libobjs= + link_against_libtool_libs= + ltlibs= + objs= + prev= + prevarg= + rpath= + perm_rpath= + temp_rpath= + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case "$arg" in + -all-static | -static) + if test "X$arg" = "X-all-static" && test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$progname: warning: complete static linking is impossible in this configuration" 1>&2 + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + for arg + do + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case "$prev" in + dlfiles|dlprefiles) + case "$arg" in + *.la | *.lo) ;; # We handle these cases below. + *) + dlprefiles="$dlprefiles $arg" + test "$prev" = dlfiles && dlfiles="$dlfiles $arg" + prev= + ;; + esac + ;; + rpath) + rpath="$rpath $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi + + prevarg="$arg" + + case "$arg" in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + allow_undefined=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + if test "$export_dynamic" != yes; then + export_dynamic=yes + if test -n "$export_dynamic_flag_spec"; then + arg=`eval \\$echo "$export_dynamic_flag_spec"` + else + arg= + fi + + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + fi + ;; + + -L*) + dir=`$echo "$arg" | sed 's%^-L\(.*\)$%\1%'` + case "$dir" in + /*) + # Add the corresponding hardcode_libdir_flag, if it is not identical. + ;; + *) + $echo "$progname: \`-L$dir' cannot specify a relative directory" 1>&2 + exit 1 + ;; + esac + deplibs="$deplibs $arg" + ;; + + -l*) deplibs="$deplibs $arg" ;; + + -o) prev=output ;; + + -rpath) + prev=rpath + continue + ;; + + -static) + # If we have no pic_flag, then this is the same as -all-static. + if test -z "$pic_flag" && test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + + *.o | *.a) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A library object. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test "$build_libtool_libs" = yes; then + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "$arg" | sed 's/\.lo$/\.o/'` + prev= + fi + libobjs="$libobjs $arg" + ;; + + *.la) + # A libtool-controlled library. + + dlname= + libdir= + library_names= + old_library= + + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $arg >/dev/null 2>&1; then : + else + $echo "$progname: \`$arg' is not a valid libtool archive" 1>&2 + exit 1 + fi + + # If there is no directory component, then add one. + case "$arg" in + */*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$libdir"; then + $echo "$progname: \`$arg' contains no -rpath information" 1>&2 + exit 1 + fi + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + + if test -z "$linklib"; then + $echo "$progname: cannot find name of link library for \`$arg'" 1>&2 + exit 1 + fi + + # Find the relevant object directory and library name. + name=`$echo "$arg" | sed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` + dir=`$echo "$arg" | sed 's%/[^/]*$%%'` + if test "X$dir" = "X$arg"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + + # This library was specified with -dlopen. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test -z "$dlname"; then + # If there is no dlname, we need to preload. + prev=dlprefiles + else + # We should not create a dependency on this library. + prev= + continue + fi + fi + + # The library was specified with -dlpreopen. + if test "$prev" = dlprefiles; then + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + dlprefiles="$dlprefiles $dir/$old_library" + else + dlprefiles="$dlprefiles $dir/$linklib" + fi + prev= + fi + + if test "$build_libtool_libs" = yes && test -n "$library_names"; then + link_against_libtool_libs="$link_against_libtool_libs $arg" + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # This is the magic to use -rpath. + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + flag=`eval \\$echo \"$hardcode_libdir_flag_spec\"` + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test "$hardcode_runpath_var" = yes; then + # Do the same for the permanent run path. + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + + + case "$hardcode_action" in + immediate) + if test "$hardcode_direct" = no; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = no; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = no; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + relink) + # We need an absolute path. + case "$dir" in + /*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$progname: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + + if test "$hardcode_direct" = yes; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + *) + $echo "$progname: \`$hardcode_action' is an unknown hardcode action" 1>&2 + exit 1 + ;; + esac + + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + finalize_command="$finalize_command $libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + finalize_command="$finalize_command -L$libdir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + finalize_shlibpath="$finalize_shlibpath$libdir:" + finalize_command="$finalize_command -l$name" + else + # We can't seem to hardcode it, guess we'll fake it. + finalize_command="$finalize_command -L$libdir -l$name" + fi + else + # Transform directly to old archives if we don't build new libraries. + if test -n "$pic_flag" && test -z "$old_library"; then + $echo "$progname: cannot find static library for \`$arg'" 1>&2 + exit 1 + fi + + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_command="$compile_command $dir/$linklib" + finalize_command="$finalize_command $dir/$linklib" + else + compile_command="$compile_command -L$dir -l$name" + finalize_command="$finalize_command -L$dir -l$name" + fi + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + esac + + # Now actually substitute the argument into the commands. + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + done + + if test -n "$prev"; then + $echo "$progname: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + oldlib= + oldobjs= + case "$output" in + "") + $echo "$progname: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + */*) + $echo "$progname: output file \`$output' must have no directory components" 1>&2 + exit 1 + ;; + + *.la) + # Make sure we only generate libraries of the form `libNAME.la'. + case "$output" in + lib*) ;; + *) + $echo "$progname: libtool library \`$arg' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + name=`$echo "$output" | sed -e 's/\.la$//' -e 's/^lib//'` + libname=`eval \\$echo \"$libname_spec\"` + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + current=0 + revision=0 + age=0 + + if test -n "$objs"; then + $echo "$progname: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 + exit 1 + fi + + # How the heck are we supposed to write a wrapper for a shared library? + if test -n "$link_against_libtool_libs"; then + $echo "$progname: libtool library \`$output' may not depend on uninstalled libraries:$link_against_libtool_libs" 1>&2 + exit 1 + fi + + # Add libc to deplibs on all systems. + deplibs="$deplibs -lc" + + if test -n "$dlfiles$dlprefiles"; then + $echo "$progname: warning: \`-dlopen' is ignored while creating libtool libraries" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -z "$rpath"; then + $echo "$progname: you must specify an installation directory with \`-rpath'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$progname: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo + IFS="$save_ifs" + + if test -n "$5"; then + $echo "$progname: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + test -n "$2" && current="$2" + test -n "$3" && revision="$3" + test -n "$4" && age="$4" + + # Check that each of the things are valid numbers. + case "$current" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$revision" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$age" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$progname: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + version_vars="version_type current age revision" + case "$version_type" in + none) ;; + + linux) + version_vars="$version_vars major versuffix" + major=`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + version_vars="$version_vars versuffix verstring" + major=`expr $current - $age` + versuffix="$current.$age.$revision" + verstring="$versuffix" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + version_vars="$version_vars major versuffix" + major="$current" + versuffix="$current.$revision" + ;; + + *) + $echo "$progname: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Create the output directory, or remove our outputs if we need to. + if test -d $objdir; then + $show "$rm $objdir/$output $objdir/$libname.*" + $run $rm $objdir/$output $objdir/$libname.* + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$progname: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Clear the flag. + allow_undefined_flag= + fi + + if test "$build_libtool_libs" = yes; then + # Get the real and link names of the library. + library_names=`eval \\$echo \"$library_names_spec\"` + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + soname=`eval \\$echo \"$soname_spec\"` + else + soname="$realname" + fi + + lib="$objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are PIC. + test -z "$pic_flag" && libobjs=`$echo "$libobjs " | sed -e 's/\.lo /.o /g' -e 's/ $//g'` + + # Do each of the archive commands. + cmds=`eval \\$echo \"$archive_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Create links to the real library. + for link in $linknames; do + $show "(cd $objdir && $LN_S $realname $link)" + $run eval '(cd $objdir && $LN_S $realname $link)' || exit $? + done + + # If -export-dynamic was specified, set the dlname. + if test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + *.lo | *.o) + if test -n "$link_against_libtool_libs"; then + $echo "$progname: error: cannot link libtool libraries into reloadable objects" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$progname: warning: \`-l' and \`-L' are ignored while creating objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles"; then + $echo "$progname: warning: \`-dlopen' is ignored while creating objects" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -n "$rpath"; then + $echo "$progname: warning: \`-rpath' is ignored while creating objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$progname: warning: \`-version-info' is ignored while creating objects" 1>&2 + fi + + case "$output" in + *.lo) + if test -n "$objs"; then + $echo "$progname: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "$output" | sed 's/\.lo$/.o/'` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Create the old-style object. + reload_objs="$objs"`$echo "$libobjs " | sed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + output="$obj" + cmds=`eval \\$echo \"$reload_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + test -z "$libobj" && exit 0 + + if test "$build_libtool_libs" != yes; then + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "$echo timestamp > $libobj" + $run eval "\$echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs" + output="$libobj" + cmds=`eval \\$echo \"$reload_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj || exit 1 + fi + + exit 0 + ;; + + *) + if test -n "$vinfo"; then + $echo "$progname: warning: \`-version-info' is ignored while linking programs" 1>&2 + fi + + if test -n "$rpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + flag=`eval \\$echo \"$hardcode_libdir_flag_spec\"` + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test "$hardcode_runpath_var" = yes; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + fi + + # Substitute the hardcoded libdirs into the compile commands. + if test -n "$hardcode_libdir_separator"; then + compile_command=`$echo "$compile_command" | sed "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + finalize_command=`$echo "$finalize_command" | sed "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + fi + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "$compile_command " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + finalize_command=`$echo "$finalize_command " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + fi + + if test "$export_dynamic" = yes && test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${output}S.c" + else + dlsyms= + fi + + if test -n "$dlsyms"; then + # Add our own program objects to the preloaded list. + dlprefiles=`$echo "$objs$dlprefiles " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + + # Discover the nlist of each of the dlfiles. + nlist="$objdir/${output}.nm" + + if test -d $objdir; then + $show "$rm $nlist ${nlist}T" + $run $rm "$nlist" "${nlist}T" + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + # Parse the name list into a source file. + $show "creating $objdir/$dlsyms" + if test -z "$run"; then + # Make sure we at least have an empty file. + test -f "$nlist" || : > "$nlist" + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`$echo "$wcout" | sed 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + $rm "$nlist"T + count=-1 + fi + + case "$dlsyms" in + "") ;; + *.c) + cat <<EOF > "$objdir/$dlsyms" +/* $dlsyms - symbol resolution table for \`$output' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define dld_preloaded_symbol_count some_other_symbol +#define dld_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */ +EOF + if test -f "$nlist"; then + sed -e 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> "$objdir/$dlsyms" + else + $echo '/* NONE */' >> "$objdir/$dlsyms" +EOF + fi + + cat <<EOF >> "$objdir/$dlsyms" + +#undef dld_preloaded_symbol_count +#undef dld_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{ +EOF + + if test -f "$nlist"; then + sed 's/^\(.*\) \(.*\)$/ {"\1", \&\2},/' < "$nlist" >> "$objdir/$dlsyms" + fi + + cat <<\EOF >> "$objdir/$dlsyms" + {0}, +}; + +#ifdef __cplusplus +} +#endif +EOF + ;; + + *) + echo "$progname: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + fi + + # Now compile the dynamic symbol file. + $show "(cd $objdir && $CC -c$no_builtin_flag \"$dlsyms\")" + $run eval '(cd $objdir && $CC -c$no_builtin_flag "$dlsyms")' || exit $? + + # Transform the symbol file into the correct name. + compile_command=`$echo "$compile_command" | sed "s%@SYMFILE@%$objdir/${output}S.o%"` + finalize_command=`$echo "$finalize_command" | sed "s%@SYMFILE@%$objdir/${output}S.o%"` + elif test "$export_dynamic" != yes; then + test -n "$dlfiles$dlprefiles" && $echo "$progname: warning: \`-dlopen' and \`-dlpreopen' are ignored without \`-export-dynamic'" 1>&2 + else + # We keep going just in case the user didn't refer to + # dld_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + $echo "$progname: not configured to extract global symbols from dlpreopened files" 1>&2 + + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "$compile_command" | sed 's%@OUTPUT@%'"$output"'%g'` + finalize_command=`$echo "$finalize_command" | sed 's%@OUTPUT@%'"$output"'%g'` + + # We have no uninstalled library dependencies, so finalize right now. + $show "$compile_command" + $run eval "$compile_command" + exit $? + fi + + # Replace the output file specification. + compile_command=`$echo "$compile_command" | sed 's%@OUTPUT@%'"$objdir/$output"'%g'` + finalize_command=`$echo "$finalize_command" | sed 's%@OUTPUT@%'"$objdir/$output"'T%g'` + + # Create the binary in the object directory, then wrap it. + if test -d $objdir; then : + else + $show "$mkdir $objdir" + $run $mkdir $objdir || exit $? + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case "$dir" in + /*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + # Delete the old output file. + $run $rm $output + + if test -n "$compile_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_command="$runpath_var=\"$rpath\$$runpath_var\" $compile_command" + finalize_command="$runpath_var=\"$rpath\$$runpath_var\" $finalize_command" + fi + + case "$hardcode_action" in + relink) + # AGH! Flame the AIX and HP-UX people for me, will ya? + $echo "$progname: warning: using a buggy system linker" 1>&2 + $echo "$progname: relinking will be required before \`$output' can be installed" 1>&2 + ;; + esac + + $show "$compile_command" + $run eval "$compile_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the finalize command for shipping. + finalize_command=`$echo "$finalize_command" | sed "$sed_quote_subst"` + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + cat > $output <<EOF +#! /bin/sh + +# $output - temporary wrapper script for $objdir/$output +# Generated by ltmain.sh - GNU $PACKAGE $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of \``pwd`'. +# If it is, it will not operate correctly. + +# This environment variable determines our operation mode. +if test "\$libtool_install_magic" = "$magic"; then + # install mode needs the following variables: + link_against_libtool_libs='$link_against_libtool_libs' + finalize_command="$finalize_command" +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test "\$libtool_execute_magic" = "$magic"; then : + else + echo='$echo' + file="\$0" + fi + + # Find the directory that this script lives in. + thisdir=\`\$echo "\$file" | sed 's%/[^/]*$%%'\` + test "x\$thisdir" = "x\$file" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld "\$file" | sed -n 's/.*-> //p'\` + while test -n "\$file"; do + destdir=\`\$echo "\$file" | sed 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test "x\$destdir" != "x\$file"; then + case "\$destdir" in + /*) thisdir="\$destdir" ;; + *) thisdir="\$thisdir/\$destdir" ;; + esac + fi + + file=\`\$echo "\$file" | sed 's%^.*/%%'\` + file=\`ls -ld "\$thisdir/\$file" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd "\$thisdir" && pwd\` + test -n "\$absdir" && thisdir="\$absdir" + + progdir="\$thisdir/$objdir" + program='$output' + + if test -f "\$progdir/\$program"; then +EOF + + # Export our shlibpath_var if we have one. + if test -n "$shlibpath_var" && test -n "$temp_rpath"; then + cat >> $output <<EOF + # Add our own library path to $shlibpath_var + $shlibpath_var="$temp_rpath\$$shlibpath_var" + + # Some systems cannot cope with colon-terminated $shlibpath_var + $shlibpath_var=\`\$echo \$$shlibpath_var | sed -e 's/:*\$//'\` + + export $shlibpath_var + +EOF + fi + + cat >> $output <<EOF + if test "\$libtool_execute_magic" != "$magic"; then + # Run the actual program with our arguments. + args= + for arg + do + # Quote arguments (to preserve shell metacharacters). + sed_quote_subst='$sed_quote_subst' + arg=\`\$echo "\$arg" | sed "\$sed_quote_subst"\` + args="\$args \\"\$arg\\"" + done + + # Export the path to the program. + PATH="\$progdir:\$PATH" + export PATH + + eval "exec \$program \$args" + + \$echo "\$0: cannot exec \$program \$args" + exit 1 + fi + else + # The program doesn't exist. + \$echo "\$0: error: \$progdir/\$program does not exist" 1>&2 + \$echo "This script is just a wrapper for \$program." 1>&2 + \$echo "See the $PACKAGE documentation for more information." 1>&2 + exit 1 + fi +fi +EOF + chmod +x $output + fi + exit 0 + ;; + esac + + + # See if we need to build an old-fashioned archive. + if test "$build_old_libs" = "yes"; then + # Now set the variables for building old libraries. + oldlib="$objdir/$libname.a" + + # Transform .lo files to .o files. + oldobjs="$objs"`$echo "$libobjs " | sed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + if test -d "$objdir"; then + $show "$rm $oldlib" + $run $rm $oldlib + else + $show "$mkdir $objdir" + $run $mkdir $objdir + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=`eval \\$echo \"$old_archive_from_new_cmds\"` + else + cmds=`eval \\$echo \"$old_archive_cmds\"` + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Now create the libtool archive. + case "$output" in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.a" + + $show "creating $output" + + # Only create the output if not a dry run. + if test -z "$run"; then + cat > $output <<EOF +# $output - a libtool library file +# Generated by ltmain.sh - GNU $PACKAGE $VERSION + +# The name that we can dlopen(3). +dlname='$dlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Directory that this library needs to be installed in: +libdir='$install_libdir' +EOF + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $objdir && $LN_S ../$output $output)" + $run eval "(cd $objdir && $LN_S ../$output $output)" || exit 1 + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + progname="$progname: install" + + # There may be an optional /bin/sh argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL"; then + # Aesthetically quote it. + arg=`$echo "$nonopt" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir= + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case "$arg" in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$progname: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$progname: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$progname: no file or destination specified" 1>&2 + else + $echo "$progname: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "$dest" | sed 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test -n "$isdir"; then + destdir="$dest" + destname= + else + destdir=`$echo "$dest" | sed 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "$dest" | sed 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$progname: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case "$destdir" in + /*) ;; + *) + for file in $files; do + case "$file" in + *.lo) ;; + *) + $echo "$progname: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case "$file" in + *.a) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then : + else + $echo "$progname: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir="`$echo "$file" | sed 's%/[^/]*$%%'`/" + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$realname $destdir/$realname" + $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? + test "X$dlname" = "X$realname" && dlname= + + # Support stripping libraries. + if test -n "$stripme"; then + if test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run $striplib $destdir/$realname || exit $? + else + $echo "$progname: warning: no library stripping program" 1>&2 + fi + fi + + if test $# -gt 0; then + # Delete the old symlinks. + rmcmd="$rm" + for linkname + do + rmcmd="$rmcmd $destdir/$linkname" + done + $show "$rmcmd" + $run $rmcmd + + # ... and create new ones. + for linkname + do + test "X$dlname" = "X$linkname" && dlname= + $show "(cd $destdir && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $LN_S $realname $linkname)" + done + fi + + if test -n "$dlname"; then + # Install the dynamically-loadable library. + $show "$install_prog $dir/$dlname $destdir/$dlname" + $run eval "$install_prog $dir/$dlname $destdir/$dlname" || exit $? + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=`eval \\$echo \"$postinstall_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "$file" | sed 's%^.*/%%'` + $show "$install_prog $file $destdir/$name" + $run eval "$install_prog $file $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "$file" | sed 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case "$destfile" in + *.lo) + staticdest=`$echo "$destfile" | sed 's/\.lo$/\.o/'` + ;; + *.o) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$progname: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "$file" | sed 's/\.lo$/\.o/'` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Do a test to see if this is really a libtool program. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + link_against_libtool_libs= + finalize_command= + + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$link_against_libtool_libs" || test -z "$finalize_command"; then + $echo "$progname: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $link_against_libtool_libs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case "$lib" in + */*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/`$echo "$lib" | sed 's%^.*/%%g'`" + if test -z "$libdir"; then + $echo "$progname: warning: \`$lib' contains no -rpath information" 1>&2 + elif test -f "$libfile"; then : + else + $echo "$progname: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + if test "$hardcode_action" = relink; then + if test "$finalize" = yes; then + $echo "$progname: warning: relinking \`$file' on behalf of your buggy system linker" 1>&2 + $show "$finalize_command" + if $run eval "$finalize_command"; then : + else + $echo "$progname: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + file="$objdir/$file"T + else + $echo "$progname: warning: cannot relink \`$file' on behalf of your buggy system linker" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "$file" | sed "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + $show "$install_prog$stripme $file $dest" + $run eval "$install_prog\$stripme \$file \$dest" || exit $? + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "$file" | sed 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + # Support stripping libraries. + if test -n "$stripme"; then + if test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run $old_striplib $oldlib || exit $? + else + $echo "$progname: warning: no static library stripping program" 1>&2 + fi + fi + + # Do each command in the postinstall commands. + cmds=`eval \\$echo \"$old_postinstall_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$progname: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + progname="$progname: finish" + libdirs="$nonopt" + + if test -n "$finish_cmds" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + # Do each command in the postinstall commands. + cmds=`eval \\$echo \"$finish_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + done + fi + + $echo "To link against installed libraries in LIBDIR, users may have to:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to their \`$shlibpath_var' environment variable" + fi + $echo " - use the \`-LLIBDIR' linker flag" + exit 0 + ;; + + # libtool execute mode + execute) + progname="$progname: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$progname: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test -f "$file"; then : + else + $echo "$progname: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case "$file" in + *.la) + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then : + else + $echo "$progname: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$progname: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "$file" | sed 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$progname: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "$file" | sed 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$progname: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case "$file" in + -*) ;; + *) + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "$file" | sed "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$progname: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool uninstall mode + uninstall) + progname="$progname: uninstall" + rm="$nonopt" + files= + + for arg + do + case "$arg" in + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$progname: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + for file in $files; do + dir=`$echo "$file" | sed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + name=`$echo "$file" | sed -e 's%^.*/%%'` + + rmfiles="$file" + + case "$name" in + *.la) + # Possibly a libtool archive, so verify it. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $dir/$n" + test "X$n" = "X$dlname" && dlname= + done + test -n "$dlname" && rmfiles="$rmfiles $dir/$dlname" + test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" + + # FIXME: should reinstall the best remaining shared library. + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "$name" | sed 's/\.lo$/\.o/'` + rmfiles="$rmfiles $dir/$oldobj" + fi + ;; + esac + + $show "$rm $rmfiles" + $run $rm $rmfiles + done + exit 0 + ;; + + "") + $echo "$progname: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$progname: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case "$mode" in +"") cat <<EOF +Usage: $progname [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + +-n, --dry-run display commands without modifying any files + --features display configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$progname --help --mode=MODE' for +a more detailed description of MODE. +EOF + ;; + +compile) + cat <<EOF +Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'. +EOF + ;; + +execute) + cat <<EOF +Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments. +EOF + ;; + +finish) + cat <<EOF +Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed. +EOF + ;; + +install) + cat <<EOF +Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized). +EOF + ;; + +link) + cat <<EOF +Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -allow-undefined allow a libtool library to reference undefined symbols + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to dld_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only +library objects (\`.lo' files) may be specified, and \`-rpath' is required. + +If OUTPUT-FILE ends in \`.a', then a standard library is created using \`ar' +and \`ranlib'. + +If OUTPUT-FILE ends in \`.lo' or \`.o', then a reloadable object file is +created, otherwise an executable program is created. +EOF + ;; + +uninstall) + cat <<EOF +Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM. +EOF + ;; + +*) + $echo "$progname: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +$echo +$echo "Try \`$progname --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/glib/missing b/glib/missing new file mode 100755 index 0000000000..e4b838ca92 --- /dev/null +++ b/glib/missing @@ -0,0 +1,134 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996. + +# This program 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, or (at your option) +# any later version. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison touch file \`y.tab.c' + makeinfo touch the output file + yacc touch file \`y.tab.c'" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + touch config.h.in + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print \ + | sed 's/^\(.*\).am$/touch \1.in/' \ + | sh + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + your modified any \`.y' file. For being effective, your + modifications might require the \`Bison' package. Grab it from + any GNU archive site." + touch y.tab.c + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/glib/mkinstalldirs b/glib/mkinstalldirs new file mode 100755 index 0000000000..fef1eb9418 --- /dev/null +++ b/glib/mkinstalldirs @@ -0,0 +1,36 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? + fi + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/glib/stamp-h.in b/glib/stamp-h.in new file mode 100644 index 0000000000..9788f70238 --- /dev/null +++ b/glib/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/glib/testglib.c b/glib/testglib.c new file mode 100644 index 0000000000..4357b2364d --- /dev/null +++ b/glib/testglib.c @@ -0,0 +1,296 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include <string.h> +#include "glib.h" + +int array[10000]; + +void +my_hash_callback (gpointer key, + gpointer value, + gpointer user_data) +{ + int *d = value; + *d = 1; +} + +guint +my_hash (gpointer key) +{ + return (guint) *((gint*) key); +} + +gint +my_hash_compare (gpointer a, + gpointer b) +{ + return *((gint*) a) == *((gint*) b); +} + +gint +my_compare (gpointer a, + gpointer b) +{ + char *cha = a; + char *chb = b; + + return *cha - *chb; +} + +gint +my_traverse (gpointer key, + gpointer value, + gpointer data) +{ + char *ch = key; + g_print ("%c ", *ch); + return FALSE; +} + +int +main (int argc, + char *argv[]) +{ + GList *list, *t; + GSList *slist, *st; + GHashTable *hash_table; + GMemChunk *mem_chunk; + GStringChunk *string_chunk; + GTimer *timer; + gint nums[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + gchar *mem[10000], *tmp_string, *tmp_string_2; + gint i, j; + GArray *garray; + GString *string1, *string2; + GTree *tree; + char chars[62]; + + g_print ("checking size of gint8...%d (should be 1)\n", sizeof (gint8)); + g_print ("checking size of gint16...%d (should be 2)\n", sizeof (gint16)); + g_print ("checking size of gint32...%d (should be 4)\n", sizeof (gint32)); + + g_print ("checking doubly linked lists..."); + + list = NULL; + for (i = 0; i < 10; i++) + list = g_list_append (list, &nums[i]); + list = g_list_reverse (list); + + for (i = 0; i < 10; i++) + { + t = g_list_nth (list, i); + if (*((gint*) t->data) != (9 - i)) + g_error ("failed"); + } + + g_list_free (list); + + g_print ("ok\n"); + + + g_print ("checking singly linked lists..."); + + slist = NULL; + for (i = 0; i < 10; i++) + slist = g_slist_append (slist, &nums[i]); + slist = g_slist_reverse (slist); + + for (i = 0; i < 10; i++) + { + st = g_slist_nth (slist, i); + if (*((gint*) st->data) != (9 - i)) + g_error ("failed"); + } + + g_slist_free (slist); + + g_print ("ok\n"); + + + g_print ("checking trees...\n"); + + tree = g_tree_new (my_compare); + i = 0; + for (j = 0; j < 10; j++, i++) + { + chars[i] = '0' + j; + g_tree_insert (tree, &chars[i], &chars[i]); + } + for (j = 0; j < 26; j++, i++) + { + chars[i] = 'A' + j; + g_tree_insert (tree, &chars[i], &chars[i]); + } + for (j = 0; j < 26; j++, i++) + { + chars[i] = 'a' + j; + g_tree_insert (tree, &chars[i], &chars[i]); + } + + g_print ("tree height: %d\n", g_tree_height (tree)); + g_print ("tree nnodes: %d\n", g_tree_nnodes (tree)); + + g_print ("tree: "); + g_tree_traverse (tree, my_traverse, G_IN_ORDER, NULL); + g_print ("\n"); + + for (i = 0; i < 10; i++) + g_tree_remove (tree, &chars[i]); + + g_print ("tree height: %d\n", g_tree_height (tree)); + g_print ("tree nnodes: %d\n", g_tree_nnodes (tree)); + + g_print ("tree: "); + g_tree_traverse (tree, my_traverse, G_IN_ORDER, NULL); + g_print ("\n"); + + g_print ("ok\n"); + + + g_print ("checking mem chunks..."); + + mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE); + + for (i = 0; i < 10000; i++) + { + mem[i] = g_chunk_new (gchar, mem_chunk); + + for (j = 0; j < 50; j++) + mem[i][j] = i * j; + } + + for (i = 0; i < 10000; i++) + { + g_mem_chunk_free (mem_chunk, mem[i]); + } + + g_print ("ok\n"); + + + g_print ("checking hash tables..."); + + hash_table = g_hash_table_new (my_hash, my_hash_compare); + for (i = 0; i < 10000; i++) + { + array[i] = i; + g_hash_table_insert (hash_table, &array[i], &array[i]); + } + g_hash_table_foreach (hash_table, my_hash_callback, NULL); + + for (i = 0; i < 10000; i++) + if (array[i] == 0) + g_print ("%d\n", i); + + for (i = 0; i < 10000; i++) + g_hash_table_remove (hash_table, &array[i]); + + g_hash_table_destroy (hash_table); + + g_print ("ok\n"); + + + g_print ("checking string chunks..."); + + string_chunk = g_string_chunk_new (1024); + + for (i = 0; i < 100000; i ++) + { + tmp_string = g_string_chunk_insert (string_chunk, "hi pete"); + + if (strcmp ("hi pete", tmp_string) != 0) + g_error ("string chunks are broken.\n"); + } + + tmp_string_2 = g_string_chunk_insert_const (string_chunk, tmp_string); + + g_assert (tmp_string_2 != tmp_string && + strcmp(tmp_string_2, tmp_string) == 0); + + tmp_string = g_string_chunk_insert_const (string_chunk, tmp_string); + + g_assert (tmp_string_2 == tmp_string); + + g_string_chunk_free (string_chunk); + + g_print ("ok\n"); + + + g_print ("checking arrays..."); + + garray = g_array_new (FALSE); + for (i = 0; i < 10000; i++) + g_array_append_val (garray, gint, i); + + for (i = 0; i < 10000; i++) + if (g_array_index (garray, gint, i) != i) + g_print ("uh oh: %d ( %d )\n", g_array_index (garray, gint, i), i); + + g_array_free (garray, TRUE); + + garray = g_array_new (FALSE); + for (i = 0; i < 10000; i++) + g_array_prepend_val (garray, gint, i); + + for (i = 0; i < 10000; i++) + if (g_array_index (garray, gint, i) != (10000 - i - 1)) + g_print ("uh oh: %d ( %d )\n", g_array_index (garray, gint, i), 10000 - i - 1); + + g_array_free (garray, TRUE); + + g_print ("ok\n"); + + + g_print ("checking strings..."); + + string1 = g_string_new ("hi pete!"); + string2 = g_string_new (""); + + g_assert (strcmp ("hi pete!", string1->str) == 0); + + for (i = 0; i < 10000; i++) + g_string_append_c (string1, 'a'+(i%26)); + + g_string_sprintf (string2, "%s|%0100d|%s|%s|%0*d|%*.*f|%10000.10000f", + "this pete guy sure is a wuss, like he's the number ", + 1, + " wuss. everyone agrees.\n", + string1->str, + 10, 666, 15, 15, 666.666666666, 666.666666666); + + g_print ("ok\n"); + + g_print ("checking timers...\n"); + + timer = g_timer_new (); + g_print (" spinning for 3 seconds...\n"); + + g_timer_start (timer); + while (g_timer_elapsed (timer, NULL) < 3) + ; + + g_timer_stop (timer); + g_timer_destroy (timer); + + g_print ("ok\n"); + + /* g_debug (argv[0]); */ + + + return 0; +} diff --git a/gtk+.prj b/gtk+.prj new file mode 100644 index 0000000000..2c16fecaf7 --- /dev/null +++ b/gtk+.prj @@ -0,0 +1,334 @@ +;; -*- Lisp -*- +(Created-By-Prcs-Version 1 1 0) +(Project-Description "") +(Project-Version gtk+ 0 16) +(Parent-Version gtk+ 0 15) +(Descends-From -*- -*- -*-) +(Version-Log "") +(New-Version-Log "") +(Checkin-Time "Wed, 19 Feb 1997 15:49:10 -0800") +(Checkin-Login pmattis) +(Populate-Ignore ("\\.o$" "\\.a$" "^core$" "^.*/core$" + ".*.deps/.*" "\\.dvi$" "\\.aux$" "\\.log" + "Makefile$" "config.cache$" "config.log$" + "configure$" "gconfig.h$" "stamp-h$")) +(Files +;; This is a comment. Fill in files here. +;; For example: (prcs/checkout.cc ()) + +; Files added by populate at Thu, 21 Nov 1996 16:48:40 -0800: + + (docs/texinfo.tex (gtk+/1_texinfo.te 1.1 644)) + (docs/gtk.texi (gtk+/2_gtk.texi 1.5 644)) + (docs/gdk.texi (gtk+/3_gdk.texi 1.2 644)) + (docs/Makefile.in (gtk+/4_Makefile.i 1.5 644)) + (docs/Makefile.am (gtk+/5_Makefile.a 1.2 644)) + (gtk/testgtk.c (gtk+/6_testgtk.c 1.14 644)) + (gtk/gtkwindow.h (gtk+/7_gtkwindow. 1.6 644)) + (gtk/gtkwindow.c (gtk+/8_gtkwindow. 1.10 644)) + (gtk/gtkwidget.h (gtk+/9_gtkwidget. 1.8 644)) + (gtk/gtkwidget.c (gtk+/10_gtkwidget. 1.14 644)) + (gtk/gtkvseparator.h (gtk+/11_gtkvsepara 1.3 644)) + (gtk/gtkvseparator.c (gtk+/12_gtkvsepara 1.5 644)) + (gtk/gtkvscrollbar.h (gtk+/13_gtkvscroll 1.3 644)) + (gtk/gtkvscrollbar.c (gtk+/14_gtkvscroll 1.5 644)) + (gtk/gtkvscale.h (gtk+/15_gtkvscale. 1.2 644)) + (gtk/gtkvscale.c (gtk+/16_gtkvscale. 1.7 644)) + (gtk/gtkvruler.h (gtk+/17_gtkvruler. 1.4 644)) + (gtk/gtkvruler.c (gtk+/18_gtkvruler. 1.7 644)) + (gtk/gtkviewport.h (gtk+/19_gtkviewpor 1.3 644)) + (gtk/gtkviewport.c (gtk+/20_gtkviewpor 1.6 644)) + (gtk/gtkvbox.h (gtk+/21_gtkvbox.h 1.2 644)) + (gtk/gtkvbox.c (gtk+/22_gtkvbox.c 1.5 644)) + (gtk/gtktypeutils.h (gtk+/23_gtktypeuti 1.4 644)) + (gtk/gtktypeutils.c (gtk+/24_gtktypeuti 1.6 644)) + (gtk/gtktreeitem.h (gtk+/25_gtktreeite 1.3 644)) + (gtk/gtktreeitem.c (gtk+/26_gtktreeite 1.4 644)) + (gtk/gtktree.h (gtk+/27_gtktree.h 1.3 644)) + (gtk/gtktree.c (gtk+/28_gtktree.c 1.4 644)) + (gtk/gtktogglebutton.h (gtk+/29_gtktoggleb 1.5 644)) + (gtk/gtktogglebutton.c (gtk+/30_gtktoggleb 1.8 644)) + (gtk/gtktable.h (gtk+/31_gtktable.h 1.2 644)) + (gtk/gtktable.c (gtk+/32_gtktable.c 1.8 644)) + (gtk/gtkstyle.h (gtk+/33_gtkstyle.h 1.3 644)) + (gtk/gtkstyle.c (gtk+/34_gtkstyle.c 1.7 644)) + (gtk/gtksignal.h (gtk+/35_gtksignal. 1.7 644)) + (gtk/gtksignal.c (gtk+/36_gtksignal. 1.9 644)) + (gtk/gtkseparator.h (gtk+/37_gtkseparat 1.2 644)) + (gtk/gtkseparator.c (gtk+/38_gtkseparat 1.4 644)) + (gtk/gtkscrolledwindow.h (gtk+/39_gtkscrolle 1.2 644)) + (gtk/gtkscrolledwindow.c (gtk+/40_gtkscrolle 1.8 644)) + (gtk/gtkscrollbar.h (gtk+/41_gtkscrollb 1.2 644)) + (gtk/gtkscrollbar.c (gtk+/42_gtkscrollb 1.4 644)) + (gtk/gtkscale.h (gtk+/43_gtkscale.h 1.4 644)) + (gtk/gtkscale.c (gtk+/44_gtkscale.c 1.7 644)) + (gtk/gtkruler.h (gtk+/45_gtkruler.h 1.5 644)) + (gtk/gtkruler.c (gtk+/46_gtkruler.c 1.8 644)) + (gtk/gtkrc.h (gtk+/47_gtkrc.h 1.3 644)) + (gtk/gtkrc.c (gtk+/48_gtkrc.c 1.4 644)) + (gtk/gtkrange.h (gtk+/49_gtkrange.h 1.4 644)) + (gtk/gtkrange.c (gtk+/50_gtkrange.c 1.6 644)) + (gtk/gtkradiobutton.h (gtk+/51_gtkradiobu 1.3 644)) + (gtk/gtkradiobutton.c (gtk+/b/0_gtkradiobutton.c 1.7 644)) + (gtk/gtkpixmap.h (gtk+/b/1_gtkpixmap. 1.3 644)) + (gtk/gtkpixmap.c (gtk+/b/2_gtkpixmap. 1.5 644)) + (gtk/gtkoptionmenu.h (gtk+/b/3_gtkoptionm 1.5 644)) + (gtk/gtkoptionmenu.c (gtk+/b/4_gtkoptionm 1.7 644)) + (gtk/gtkobject.h (gtk+/b/5_gtkobject. 1.6 644)) + (gtk/gtkobject.c (gtk+/b/6_gtkobject. 1.9 644)) + (gtk/gtkmisc.h (gtk+/b/7_gtkmisc.h 1.2 644)) + (gtk/gtkmisc.c (gtk+/b/8_gtkmisc.c 1.4 644)) + (gtk/gtkmenushell.h (gtk+/b/9_gtkmenushe 1.5 644)) + (gtk/gtkmenushell.c (gtk+/b/10_gtkmenushe 1.8 644)) + (gtk/gtkmenuitem.h (gtk+/b/11_gtkmenuite 1.6 644)) + (gtk/gtkmenuitem.c (gtk+/b/12_gtkmenuite 1.8 644)) + (gtk/gtkmenubar.h (gtk+/b/13_gtkmenubar 1.4 644)) + (gtk/gtkmenubar.c (gtk+/b/14_gtkmenubar 1.7 644)) + (gtk/gtkmenu.h (gtk+/b/15_gtkmenu.h 1.5 644)) + (gtk/gtkmenu.c (gtk+/b/16_gtkmenu.c 1.8 644)) + (gtk/gtkmain.h (gtk+/b/17_gtkmain.h 1.4 644)) + (gtk/gtkmain.c (gtk+/b/18_gtkmain.c 1.11 644)) + (gtk/gtklistitem.h (gtk+/b/19_gtklistite 1.3 644)) + (gtk/gtklistitem.c (gtk+/b/20_gtklistite 1.9 644)) + (gtk/gtklist.h (gtk+/b/21_gtklist.h 1.5 644)) + (gtk/gtklist.c (gtk+/b/22_gtklist.c 1.10 644)) + (gtk/gtklabel.h (gtk+/b/23_gtklabel.h 1.2 644)) + (gtk/gtklabel.c (gtk+/b/24_gtklabel.c 1.7 644)) + (gtk/gtkitem.h (gtk+/b/25_gtkitem.h 1.3 644)) + (gtk/gtkitem.c (gtk+/b/26_gtkitem.c 1.7 644)) + (gtk/gtkimage.h (gtk+/b/27_gtkimage.h 1.2 644)) + (gtk/gtkimage.c (gtk+/b/28_gtkimage.c 1.4 644)) + (gtk/gtkhseparator.h (gtk+/b/29_gtkhsepara 1.2 644)) + (gtk/gtkhseparator.c (gtk+/b/30_gtkhsepara 1.4 644)) + (gtk/gtkhscrollbar.h (gtk+/b/31_gtkhscroll 1.2 644)) + (gtk/gtkhscrollbar.c (gtk+/b/32_gtkhscroll 1.4 644)) + (gtk/gtkhscale.h (gtk+/b/33_gtkhscale. 1.2 644)) + (gtk/gtkhscale.c (gtk+/b/34_gtkhscale. 1.7 644)) + (gtk/gtkhruler.h (gtk+/b/35_gtkhruler. 1.4 644)) + (gtk/gtkhruler.c (gtk+/b/36_gtkhruler. 1.7 644)) + (gtk/gtkhbox.h (gtk+/b/37_gtkhbox.h 1.2 644)) + (gtk/gtkhbox.c (gtk+/b/38_gtkhbox.c 1.5 644)) + (gtk/gtkgc.h (gtk+/b/39_gtkgc.h 1.3 644)) + (gtk/gtkgc.c (gtk+/b/40_gtkgc.c 1.5 644)) + (gtk/gtkframe.h (gtk+/b/41_gtkframe.h 1.2 644)) + (gtk/gtkframe.c (gtk+/b/42_gtkframe.c 1.5 644)) + (gtk/gtkenums.h (gtk+/b/45_gtkenums.h 1.6 644)) + (gtk/gtkentry.h (gtk+/b/46_gtkentry.h 1.5 644)) + (gtk/gtkentry.c (gtk+/b/47_gtkentry.c 1.9 644)) + (gtk/gtkdrawingarea.h (gtk+/b/48_gtkdrawing 1.4 644)) + (gtk/gtkdrawingarea.c (gtk+/b/49_gtkdrawing 1.6 644)) + (gtk/gtkdata.h (gtk+/b/50_gtkdata.h 1.2 644)) + (gtk/gtkdata.c (gtk+/b/51_gtkdata.c 1.7 644)) + (gtk/gtkcontainer.h (gtk+/c/0_gtkcontainer.h 1.6 644)) + (gtk/gtkcontainer.c (gtk+/c/1_gtkcontain 1.10 644)) + (gtk/gtkcheckbutton.h (gtk+/c/2_gtkcheckbu 1.3 644)) + (gtk/gtkcheckbutton.c (gtk+/c/3_gtkcheckbu 1.6 644)) + (gtk/gtkbutton.h (gtk+/c/4_gtkbutton. 1.4 644)) + (gtk/gtkbutton.c (gtk+/c/5_gtkbutton. 1.9 644)) + (gtk/gtkbox.h (gtk+/c/6_gtkbox.h 1.2 644)) + (gtk/gtkbox.c (gtk+/c/7_gtkbox.c 1.5 644)) + (gtk/gtkbin.h (gtk+/c/8_gtkbin.h 1.2 644)) + (gtk/gtkbin.c (gtk+/c/9_gtkbin.c 1.6 644)) + (gtk/gtkarrow.h (gtk+/c/10_gtkarrow.h 1.2 644)) + (gtk/gtkarrow.c (gtk+/c/11_gtkarrow.c 1.4 644)) + (gtk/gtkalignment.h (gtk+/c/12_gtkalignme 1.2 644)) + (gtk/gtkalignment.c (gtk+/c/13_gtkalignme 1.5 644)) + (gtk/gtkadjustment.h (gtk+/c/14_gtkadjustm 1.3 644)) + (gtk/gtkadjustment.c (gtk+/c/15_gtkadjustm 1.7 644)) + (gtk/gtkaccelerator.h (gtk+/c/16_gtkacceler 1.4 644)) + (gtk/gtkaccelerator.c (gtk+/c/17_gtkacceler 1.4 644)) + (gtk/gtk.h (gtk+/c/18_gtk.h 1.7 644)) + (gtk/fnmatch.h (gtk+/c/19_fnmatch.h 1.1 644)) + (gtk/fnmatch.c (gtk+/c/20_fnmatch.c 1.1 644)) + (TODO (gtk+/c/21_TODO 1.13 644)) + (gtk/Makefile.in (gtk+/c/22_Makefile.i 1.10 644)) + (gtk/Makefile.am (gtk+/c/23_Makefile.a 1.10 644)) + (gdk/makekeysyms.sed (gtk+/c/24_makekeysym 1.1 644)) + (gdk/makekeysyms (gtk+/c/25_makekeysym 1.1 755)) + (gdk/makecursors.sed (gtk+/c/26_makecursor 1.1 644)) + (gdk/makecursors (gtk+/c/27_makecursor 1.1 755)) + (gdk/gdkx.h (gtk+/c/28_gdkx.h 1.2 644)) + (gdk/gdkwindow.c (gtk+/c/29_gdkwindow. 1.8 644)) + (gdk/gdkvisual.c (gtk+/c/30_gdkvisual. 1.2 644)) + (gdk/gdktypes.h (gtk+/c/31_gdktypes.h 1.6 644)) + (gdk/gdkrectangle.c (gtk+/c/32_gdkrectang 1.3 644)) + (gdk/gdkprivate.h (gtk+/c/33_gdkprivate 1.4 644)) + (gdk/gdkpixmap.c (gtk+/c/34_gdkpixmap. 1.6 644)) + (gdk/gdkkeysyms.h (gtk+/c/35_gdkkeysyms 1.2 644)) + (gdk/gdkimage.c (gtk+/c/36_gdkimage.c 1.4 644)) + (gdk/gdkglobals.c (gtk+/c/37_gdkglobals 1.3 644)) + (gdk/gdkgc.c (gtk+/c/38_gdkgc.c 1.6 644)) + (gdk/gdkfont.c (gtk+/c/39_gdkfont.c 1.4 644)) + (gdk/gdkdraw.c (gtk+/c/40_gdkdraw.c 1.4 644)) + (gdk/gdkcursors.h (gtk+/c/41_gdkcursors 1.3 644)) + (gdk/gdkcursor.c (gtk+/c/42_gdkcursor. 1.3 644)) + (gdk/gdkcolor.c (gtk+/c/43_gdkcolor.c 1.4 644)) + (gdk/gdk.h (gtk+/c/44_gdk.h 1.6 644)) + (gdk/gdk.c (gtk+/c/45_gdk.c 1.8 644)) + (gdk/Makefile.in (gtk+/c/46_Makefile.i 1.7 644)) + (gdk/Makefile.am (gtk+/c/47_Makefile.a 1.7 644)) + (glib/testglib.c (gtk+/c/48_testglib.c 1.8 644)) + (glib/stamp-h.in (gtk+/c/49_stamp-h.in 1.1 644)) + (glib/mkinstalldirs (gtk+/c/50_mkinstalld 1.1 755)) + (glib/install-sh (gtk+/c/51_install-sh 1.1 755)) + (glib/gutils.c (gtk+/d/0_gutils.c 1.3 644)) + (glib/gtimer.c (gtk+/d/1_gtimer.c 1.2 644)) + (glib/gslist.c (gtk+/d/2_gslist.c 1.6 644)) + (glib/gprimes.c (gtk+/d/3_gprimes.c 1.2 644)) + (glib/gmem.c (gtk+/d/4_gmem.c 1.9 644)) + (glib/glist.c (gtk+/d/5_glist.c 1.4 644)) + (glib/glib.h (gtk+/d/6_glib.h 1.8 644)) + (glib/ghash.c (gtk+/d/7_ghash.c 1.5 644)) + (glib/gerror.c (gtk+/d/8_gerror.c 1.4 644)) + (glib/gconfig.h.in (gtk+/d/9_gconfig.h. 1.3 644)) + (glib/gconfig.h (gtk+/d/10_gconfig.h 1.6 644)) + (glib/gcache.c (gtk+/d/11_gcache.c 1.6 644)) + (glib/configure.in (gtk+/d/12_configure. 1.4 644)) + (glib/configure (gtk+/d/13_configure 1.4 755)) + (glib/config.sub (gtk+/d/14_config.sub 1.2 755)) + (glib/config.guess (gtk+/d/15_config.gue 1.2 755)) + (glib/aclocal.m4 (gtk+/d/16_aclocal.m4 1.4 644)) + (glib/acconfig.h (gtk+/d/17_acconfig.h 1.3 644)) + (glib/README (gtk+/d/18_README 1.1 644)) + (glib/NEWS (gtk+/d/19_NEWS 1.1 644)) + (glib/Makefile.in (gtk+/d/20_Makefile.i 1.7 644)) + (glib/Makefile.am (gtk+/d/21_Makefile.a 1.7 644)) + (glib/INSTALL (gtk+/d/22_INSTALL 1.1 644)) + (glib/ChangeLog (gtk+/d/23_ChangeLog 1.2 644)) + (glib/COPYING (gtk+/d/24_COPYING 1.1 644)) + (glib/AUTHORS (gtk+/d/25_AUTHORS 1.2 644)) + (stamp-h.in (gtk+/d/26_stamp-h.in 1.1 644)) + (mkinstalldirs (gtk+/d/27_mkinstalld 1.1 755)) + (install-sh (gtk+/d/28_install-sh 1.1 755)) + (configure.in (gtk+/d/30_configure. 1.8 644)) + (configure (gtk+/d/31_configure 1.8 755)) + (config.sub (gtk+/d/32_config.sub 1.2 755)) + (config.h.in (gtk+/d/33_config.h.i 1.4 644)) + (config.guess (gtk+/d/34_config.gue 1.2 755)) + (aclocal.m4 (gtk+/d/35_aclocal.m4 1.4 644)) + (acconfig.h (gtk+/d/36_acconfig.h 1.3 644)) + (README (gtk+/d/37_README 1.1 644)) + (NEWS (gtk+/d/38_NEWS 1.1 644)) + (Makefile.in (gtk+/d/39_Makefile.i 1.9 644)) + (Makefile.am (gtk+/d/40_Makefile.a 1.7 644)) + (INSTALL (gtk+/d/41_INSTALL 1.1 644)) + (ChangeLog (gtk+/d/42_ChangeLog 1.14 644)) + (COPYING (gtk+/d/43_COPYING 1.2 644)) + (AUTHORS (gtk+/d/44_AUTHORS 1.2 644)) + +; Files added by populate at Mon, 30 Dec 1996 13:14:24 -0800: + + (gtk/gtkmenufactory.h (gtk+/0_gtkmenufac 1.4 644)) + (gtk/gtkmenufactory.c (gtk+/1_gtkmenufac 1.4 644)) + +; Files added by populate at Thu, 02 Jan 1997 15:31:44 -0800: + + (gtk/testgtkrc (gtk+/0_testgtkrc 1.2 644)) + + +; Files added by populate at Fri, 10 Jan 1997 14:19:47 -0800: + + (gtk/gtkfilesel.h (gtk+/b/0_gtkfilesel.h 1.3 644)) + (gtk/gtkfilesel.c (gtk+/c/0_gtkfilesel.c 1.7 644)) + (glib/gstring.c (gtk+/d/0_gstring.c 1.4 644)) + +; Files added by populate at Fri, 10 Jan 1997 18:01:19 -0800: + + (gdk/gdkselection.c (gtk+/b/0_gdkselection.c 1.5 644)) + +; Files added by populate at Sun, 19 Jan 1997 18:29:12 -0800: + + (gtk/gtktext.h (gtk+/b/0_gtktext.h 1.4 644)) + (gtk/gtktext.c (gtk+/c/0_gtktext.c 1.7 644)) + (gtk/gtkdialog.h (gtk+/d/0_gtkdialog.h 1.2 644)) + (gtk/gtkdialog.c (gtk+/d/47_gtkdialog. 1.4 644)) + (gdk/gdkxid.c (gtk+/d/48_gdkxid.c 1.2 644)) + +; Files added by populate at Thu, 23 Jan 1997 01:29:17 -0800: + + (gtk/gtknotebook.h (gtk+/b/0_gtknotebook.h 1.3 644)) + (gtk/gtknotebook.c (gtk+/c/0_gtknotebook.c 1.6 644)) + +; Files added by populate at Thu, 23 Jan 1997 02:06:11 -0800: + + (gtk/line-wrap.xbm (gtk+/b/0_line-wrap.xbm 1.1 644)) + (gtk/line-arrow.xbm (gtk+/c/0_line-arrow.xbm 1.1 644)) + +; Files added by populate at Fri, 24 Jan 1997 13:02:44 -0800: + + + + + + +; Files deleted by populate at Fri, 24 Jan 1997 13:02:44 -0800: + + ; `docs/texinfo3.7.patch' + +; Files added by populate at Tue, 28 Jan 1997 16:54:35 -0800: + + (gtk/simple.c (gtk+/e/0_simple.c 1.1 644)) + (glib/ltmain.sh (gtk+/e/1_ltmain.sh 1.3 644)) + (glib/ltconfig (gtk+/e/2_ltconfig 1.3 755)) + (ltmain.sh (gtk+/e/3_ltmain.sh 1.3 644)) + (ltconfig (gtk+/e/4_ltconfig 1.3 755)) + +; Files added by populate at Thu, 30 Jan 1997 01:30:38 -0800: + + (glib/gtree.c (gtk+/b/0_gtree.c 1.3 644)) + +; Files added by populate at Mon, 03 Feb 1997 19:46:14 -0800: + + (makecopyright (gtk+/b/0_makecopyright 1.1 755)) + +; Files added by populate at Sat, 08 Feb 1997 14:41:52 -0800: + + (gtk/gtkprogressbar.h (gtk+/b/0_gtkprogressbar.h 1.1 644)) + (gtk/gtkprogressbar.c (gtk+/c/0_gtkprogressbar.c 1.1 644)) + (glib/garray.c (gtk+/d/0_garray.c 1.1 644)) + +; Files deleted by populate at Sat, 08 Feb 1997 14:41:52 -0800: + + ; `interp/Makefile.am' + ; `interp/Makefile.in' + ; `interp/interp.c' + +;; Files added by populate at Wed, 19 Feb 1997 15:48:04 -0800: + + (gtk+.xconfig.in (gtk+/b/0_gtk+.xconfig.in 1.1 644)) + +;; Files deleted by populate at Wed, 19 Feb 1997 15:48:04 -0800: + + ; docs/proposal.tex + +;; Files added by populate at Thu, 17 Apr 1997 17:39:47 -0700: + + (docs/macros.texi ()) + (gdk/gdkproperty.c ()) + (glib/missing () :symlink) + (missing () :symlink) + +;; Files deleted by populate at Thu, 17 Apr 1997 17:39:47 -0700: + + ; gtk/gtkcanvas.c + ; gtk/gtkcanvas.h + ; gtk/gtkfill.c + ; gtk/gtkfill.h + +;; Files added by populate at Thu, 17 Apr 1997 17:41:14 -0700: + + (gtk/gtktooltips.h ()) + (gtk/gtktooltips.c ()) + (gtk/gtkradiomenuitem.h ()) + (gtk/gtkradiomenuitem.c ()) + (gtk/gtkpreview.h ()) + (gtk/gtkpreview.c ()) + (gtk/gtkcolorsel.h ()) + (gtk/gtkcolorsel.c ()) + (gtk/gtkcheckmenuitem.h ()) + (gtk/gtkcheckmenuitem.c ()) + (gtk/gtkaspectframe.h ()) + (gtk/gtkaspectframe.c ()) +) +(Merge-Parents) +(New-Merge-Parents) diff --git a/gtk+.xconfig.in b/gtk+.xconfig.in new file mode 100644 index 0000000000..8843df6ce4 --- /dev/null +++ b/gtk+.xconfig.in @@ -0,0 +1,3 @@ +X_CFLAGS = @x_cflags@ +X_LDFLAGS = @x_ldflags@ +X_LIBS = @x_libs@ diff --git a/gtk/.cvsignore b/gtk/.cvsignore new file mode 100644 index 0000000000..e5ac5d91d3 --- /dev/null +++ b/gtk/.cvsignore @@ -0,0 +1,9 @@ +*.lo +Makefile +.deps +_libs +libgtk.la +testgtk +testinput +testselection +simple diff --git a/gtk/3DRings.xpm b/gtk/3DRings.xpm new file mode 100644 index 0000000000..1ca75da752 --- /dev/null +++ b/gtk/3DRings.xpm @@ -0,0 +1,116 @@ +/* XPM */ +static char * DRings_xpm[] = { +"48 48 65 1", +" c None", +". c #104010404103", +"X c #1040208130C2", +"o c #104014515144", +"O c #000010402081", +"+ c #1040104030C2", +"@ c #208120815144", +"# c #28A241035965", +"$ c #30C230C26185", +"% c #208130C24103", +"& c #104010402081", +"* c #104000002081", +"= c #000010401040", +"- c #492441036185", +"; c #596559659E79", +": c #30C220815144", +"> c #0820186128A2", +", c #000000001040", +"< c #2081104030C2", +"1 c #514459659658", +"2 c #514455556185", +"3 c #104000001040", +"4 c #000008200000", +"5 c #618569A6AEBA", +"6 c #618569A69658", +"7 c #410345148E38", +"8 c #104020814103", +"9 c #79E782079658", +"0 c #208120814103", +"q c #596571C69E79", +"w c #4103514471C6", +"e c #2081208130C2", +"r c #6185618571C6", +"t c #28A228A25965", +"y c #596561858617", +"u c #96589E79BEFB", +"i c #28A230C271C6", +"p c #38E345145144", +"a c #79E78207A699", +"s c #30C2492469A6", +"d c #410330C25965", +"f c #410351446185", +"g c #AEBAAAAAD75C", +"h c #38E338E34103", +"j c #EFBEEBADEFBE", +"k c #208130C25144", +"l c #9658A289DF7D", +"z c #208110404103", +"x c #28A228A26185", +"c c #8E388A28BEFB", +"v c #208118612081", +"b c #38E3451479E7", +"n c #4924618579E7", +"m c #86178617B6DA", +"M c #30C220814103", +"N c #104030C25144", +"B c #4103410371C6", +"V c #86178A28D75C", +"C c #DF7DDB6CE79D", +"Z c #BEFBC30BD75C", +"A c #410330C271C6", +"S c #30C228A230C2", +"D c #082008201861", +"F c #186130C238E3", +"G c #0000208130C2", +" .Xo ", +" O+O@#$% ", +" &*=+X-;: ", +" >&=,=<11#2 ", +" +O34,X567& ", +" 8X+=,90q9w. ", +" +e<>3r tyu-& ", +" Xi%.= paus+ ", +" Od-@= fga$h ", +" @y7X, Xrjak ", +" 2:eaw+ $ag;@ ", +" .X@8@k@o@X+ +pl9tO ", +" +zX@x$$isikt8o02crv ", +" 8@%ip7757ywbs$Ohn6#. ", +" &0%$p7r215ybw1pzp2-0= ", +" 8tk$#yw21665n;1+%-p$O ", +" O<e7pbryq5am9ay6XMpM>3& ", +" 9.NtpBw16amclVcm1t%kX*88 ", +" +&etd7r6y9ulgglm6>e>3s@83 ", +" +0k$y-y69cgCCCZVam%+#ik8X ", +" O&oi$d725amgCjCZu962ybtx8+p ", +" &X0x$sBym9VZCCCZca;yBbi%08& ", +" =++@sApMy5muZZgum6y2wds:>+& ", +" #tp;1;yB#i25cVucma5;w-pti@8& ", +" .#2alumnBp:@1r59y9y6ywBS$%0X+= ", +" %$wmZVu;#tX8X07r1656y2wbp$k@%@OD ", +" 0Byc9a;h%0>&D&hBrr2r1bwB-AF:0<&*= ", +" kBf;yr#@X+&<%MkhsBwBwpsB#Bktkt8+Oh ", +" xt7B-t8*,3O.X00:$i#dBd#bptFek0X.+* ", +" Xt#b#@=, =&O+X0Ft%ibsp$p$ki%l5sX&= ", +" &<kvX&4 +O*&<X0e:%$pAti%:edugn0= ", +" +X@&+, V,O&>+Xt>tktktv0%@k;Cls+ ", +" =+O*4*X:p;9cy3&&8ve0FMtt$ee0>z7cZ6k ", +" D=D4,=.k$sBs$ee=+X0Fk%-#t%0X&O0nu9bG ", +" ,,434*&ze@F<eeeeee><tdhdSMe<&&XAaawx ", +" 4,4,=+><peeeeee&=<%M%$hSF0X&O&kw5r%Z ", +" D&vSFMF<>&D =0S-2i& ", +" +>puB> >0h7s. ", +" SM5VqM &0t#$8 ", +" XpVV70 &0kMk. ", +" XdyB%z *X<%@+ ", +" &k$b0X+=8X08o ", +" &e:e+=*X.X+& ", +" +X.O+X0O.=, ", +" +>&+0>3&* ", +" &X0k+O, ", +" >v,3 ", +" "}; diff --git a/gtk/FilesQueue.xpm b/gtk/FilesQueue.xpm new file mode 100644 index 0000000000..586d27ec43 --- /dev/null +++ b/gtk/FilesQueue.xpm @@ -0,0 +1,98 @@ +/* XPM */ +static char * FilesQueue_xpm[] = { +"44 31 64 1", +" c None", +". c #E79DE38DDF7D", +"X c #CF3CC71BCF3C", +"o c #71C675D671C6", +"O c #B6DAB2CAB6DA", +"+ c #CF3CD34CCF3C", +"@ c #DF7DE38DE79D", +"# c #FFFFFBEEFFFF", +"$ c #EFBEEFBEEFBE", +"% c #DF7DDB6CDF7D", +"& c #BEFBBAEAC71B", +"* c #BEFBBAEABEFB", +"= c #BEFBC30BC71B", +"- c #71C66DB671C6", +"; c #D75CD34CD75C", +": c #9E799A699E79", +"> c #E79DE38DE79D", +", c #CF3CCB2BC71B", +"< c #B6DAB2CABEFB", +"1 c #BEFBBAEAB6DA", +"2 c #B6DAB6DAB6DA", +"3 c #618561856185", +"4 c #C71BBAEABEFB", +"5 c #AEBAAAAAAEBA", +"6 c #965892488E38", +"7 c #A699A699A699", +"8 c #38E338E338E3", +"9 c #F7DEF7DEF7DE", +"0 c #E79DEFBEEFBE", +"q c #DF7DE38DDF7D", +"w c #C71BC71BC71B", +"e c #C71BC30BBEFB", +"r c #BEFBC30BBEFB", +"t c #B6DAAAAAAEBA", +"y c #410345144103", +"u c #D75CDB6CD75C", +"i c #C71BCB2BC71B", +"p c #BEFBCB2BBEFB", +"a c #9E79A289A699", +"s c #86178E388E38", +"d c #CF3CCF3CD75C", +"f c #CF3CD75CCF3C", +"g c #C71BC30BCF3C", +"h c #28A22CB228A2", +"j c #000000000000", +"k c #D75CD34CDF7D", +"l c #10400C300820", +"z c #E79DEBADEFBE", +"x c #DF7DDB6CD75C", +"c c #514459655965", +"v c #8617861779E7", +"b c #DF7DD34CD75C", +"n c #CF3CCB2BCF3C", +"m c #618555555965", +"M c #861786178617", +"N c #30C234D330C2", +"B c #EFBEEBADE79D", +"V c #DF7DDB6CE79D", +"C c #D75CE38DD75C", +"Z c #514449245144", +"A c #186120812081", +"S c #79E77DF779E7", +"D c #6185659569A6", +"F c #9E7992489E79", +" .XoOX+ ", +" @#$%&*=-o;: ", +" @>,=O<12*&:-<3X ", +" >%&1*4*2*OO**56758790 ", +" 9qX+we=r*&e<<<251t5555yu9 ", +" $qu++;ipi=p*=p**2tOOO27a5s<- ", +" #9udfXi;,gi&**4**4r*Ot5t55tehj ", +" 0qku+u;+d,gg=*=r*&**&<255t<*yl1 ", +" $$zq@%xk%uf;,w,i=i=e**r=12tO1=8cvj ", +" $@%>.%.%%%xbkx,w+ni,wwrwe*4*1=;8mMNj ", +" zz@Bz>>>V%%%C+u;;dfnnfwggi&=&X+yZsNll ", +" af#9@B0>q>qqq>xk.;;;kfX+XnXw=g,fycMhhN5 ", +" al5#9$$>qzBV.%x%%b;x+fnf+,X,iiqym6NAo-j ", +" #roS%#$zz>>V%%xkk%f;;+df,XnwnVZD:8AS-j* ", +" D-9Oy*9$Bz>q%qx%%u;x;;dknX+d>Zm:hhSDjr ", +" a3o+>S3z#90@@z.%>qCC%uu;ff%@Zm:NhMoj= ", +" wlvvo#:3599$>B>q>%%%%+f;fk$ymaalMvjr ", +" 0.a--S49mct9$z@.qkkqC;xu%@Zm5AlvSj* ", +" ohu%3:Z:9@y609q@@>..>Cx>$Zm5NhMvjr ", +" -j797Zv5705y=#$0>>V.%>#Z378AMMj* ", +" Zj9Xo-McBXDv%90.%%#9cc78AsMj* ", +" 8hM#M-DSF96cvz0>z#c35Nhs6j1 ", +" jl9#o63vx#-D###mmt8N66j* ", +" 5jc@fZF3o%+ZFDm<8A6FjO ", +" :j50sSay<$ss2Nh:FjO ", +" 6880&SDMF.rNNFFj1 ", +" 8jr#:SFScA6ajO ", +" Alr$DSysajO ", +" >jy#51:jO ", +" %Dy*gjO ", +" alla "}; diff --git a/gtk/Makefile.am b/gtk/Makefile.am new file mode 100644 index 0000000000..60d43b1d25 --- /dev/null +++ b/gtk/Makefile.am @@ -0,0 +1,248 @@ +## Process this file with automake to produce Makefile.in + +gtkincludedir = $(includedir)/gtk + +lib_LTLIBRARIES = libgtk.la + +libgtk_la_SOURCES = \ + gtkaccelerator.c \ + gtkadjustment.c \ + gtkaspectframe.c \ + gtkalignment.c \ + gtkarrow.c \ + gtkbin.c \ + gtkbbox.c \ + gtkbox.c \ + gtkbutton.c \ + gtkcheckbutton.c \ + gtkcheckmenuitem.c \ + gtkcolorsel.c \ + gtkcontainer.c \ + gtkcurve.c \ + gtkdata.c \ + gtkdialog.c \ + gtkdrawingarea.c \ + gtkentry.c \ + gtkeventbox.c \ + gtkfilesel.c \ + gtkfixed.c \ + gtkframe.c \ + gtkgamma.c \ + gtkgc.c \ + gtkhbbox.c \ + gtkhbox.c \ + gtkhpaned.c \ + gtkhruler.c \ + gtkhscale.c \ + gtkhscrollbar.c \ + gtkhseparator.c \ + gtkimage.c \ + gtkinputdialog.c \ + gtkitem.c \ + gtklabel.c \ + gtklist.c \ + gtklistitem.c \ + gtkmain.c \ + gtkmenu.c \ + gtkmenubar.c \ + gtkmenufactory.c \ + gtkmenuitem.c \ + gtkmenushell.c \ + gtkmisc.c \ + gtknotebook.c \ + gtkobject.c \ + gtkoptionmenu.c \ + gtkpaned.c \ + gtkpixmap.c \ + gtkpreview.c \ + gtkprogressbar.c \ + gtkradiobutton.c \ + gtkradiomenuitem.c \ + gtkrange.c \ + gtkrc.c \ + gtkruler.c \ + gtkscale.c \ + gtkscrollbar.c \ + gtkscrolledwindow.c \ + gtkselection.c \ + gtkseparator.c \ + gtksignal.c \ + gtkstyle.c \ + gtktable.c \ + gtktext.c \ + gtktogglebutton.c \ + gtktooltips.c \ + gtktree.c \ + gtktreeitem.c \ + gtktypeutils.c \ + gtkvbbox.c \ + gtkvbox.c \ + gtkviewport.c \ + gtkvpaned.c \ + gtkvruler.c \ + gtkvscale.c \ + gtkvscrollbar.c \ + gtkvseparator.c \ + gtkwidget.c \ + gtkwindow.c \ + fnmatch.c \ + fnmatch.h + +gtkinclude_HEADERS = \ + gtk.h \ + gtkaccelerator.h \ + gtkadjustment.h \ + gtkaspectframe.h \ + gtkalignment.h \ + gtkarrow.h \ + gtkbin.h \ + gtkbbox.h \ + gtkbox.h \ + gtkbutton.h \ + gtkcheckbutton.h \ + gtkcheckmenuitem.h \ + gtkcolorsel.h \ + gtkcontainer.h \ + gtkcurve.h \ + gtkdata.h \ + gtkdialog.h \ + gtkdrawingarea.h \ + gtkentry.h \ + gtkenums.h \ + gtkeventbox.h \ + gtkfilesel.h \ + gtkfixed.h \ + gtkframe.h \ + gtkgamma.h \ + gtkgc.h \ + gtkhbbox.h \ + gtkhbox.h \ + gtkhpaned.h \ + gtkhruler.h \ + gtkhscale.h \ + gtkhscrollbar.h \ + gtkhseparator.h \ + gtkimage.h \ + gtkinputdialog.h \ + gtkitem.h \ + gtklabel.h \ + gtklist.h \ + gtklistitem.h \ + gtkmain.h \ + gtkmenu.h \ + gtkmenubar.h \ + gtkmenufactory.h \ + gtkmenuitem.h \ + gtkmenushell.h \ + gtkmisc.h \ + gtknotebook.h \ + gtkobject.h \ + gtkoptionmenu.h \ + gtkpaned.h \ + gtkpixmap.h \ + gtkpreview.h \ + gtkprogressbar.h \ + gtkradiobutton.h \ + gtkradiomenuitem.h \ + gtkrange.h \ + gtkrc.h \ + gtkruler.h \ + gtkscale.h \ + gtkscrollbar.h \ + gtkscrolledwindow.h \ + gtkselection.h \ + gtkseparator.h \ + gtksignal.h \ + gtkstyle.h \ + gtktable.h \ + gtktext.h \ + gtktogglebutton.h \ + gtktooltips.h \ + gtktree.h \ + gtktreeitem.h \ + gtktypeutils.h \ + gtkvbbox.h \ + gtkvbox.h \ + gtkviewport.h \ + gtkvpaned.h \ + gtkvruler.h \ + gtkvscale.h \ + gtkvscrollbar.h \ + gtkvseparator.h \ + gtkwidget.h \ + gtkwindow.h \ + gtktypebuiltins.h + +../gtk/gtktypebuiltins.h: gtk.defs gentypeinfo.el + $(srcdir)/runelisp $(srcdir)/gentypeinfo.el idmac $< $@ + +gtktypebuiltins.c: gtk.defs gentypeinfo.el + $(srcdir)/runelisp $(srcdir)/gentypeinfo.el id $< $@ + +libgtk_la_LDFLAGS = -version-info 1:0: + +EXTRA_DIST = \ + line-arrow.xbm \ + line-wrap.xbm \ + testgtkrc \ + gtk.defs \ + runelisp \ + gentypeinfo.el \ + gtktypebuiltins.c \ + test.xpm \ + marble.xpm \ + 3DRings.xpm \ + FilesQueue.xpm \ + Modeller.xpm + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ + +noinst_PROGRAMS = testgtk testinput testselection simple +testgtk_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +testinput_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +testselection_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +simple_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +DEPS = \ + $(top_builddir)/gtk/libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + $(top_builddir)/glib/libglib.la + +testgtk_DEPENDENCIES = $(DEPS) +testinput_DEPENDENCIES = $(DEPS) +testselection_DEPENDENCIES = $(DEPS) +simple_DEPENDENCIES = $(DEPS) + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done diff --git a/gtk/Modeller.xpm b/gtk/Modeller.xpm new file mode 100644 index 0000000000..62e27f9853 --- /dev/null +++ b/gtk/Modeller.xpm @@ -0,0 +1,117 @@ +/* XPM */ +static char * InterfaceModeller_app_2_Tile_xpm[] = { +"48 48 66 1", +" c None", +". c #86174D344103", +"X c #69A651445144", +"o c #8617410330C2", +"O c #69A6410338E3", +"+ c #30C218611861", +"@ c #AEBA6DB66185", +"# c #71C638E328A2", +"$ c #69A634D328A2", +"% c #30C228A228A2", +"& c #79E73CF330C2", +"* c #BEFB9E799E79", +"= c #8E3869A66185", +"- c #514424921861", +"; c #A699A289B6DA", +": c #A6999E79A699", +"> c #71C65D756185", +", c #9E799A69A699", +"< c #8E3882078E38", +"1 c #861779E78617", +"2 c #A6999A69AEBA", +"3 c #8E388A289658", +"4 c #71C675D679E7", +"5 c #96588A289E79", +"6 c #30C230C238E3", +"7 c #C71BC71BC71B", +"8 c #9E79A289AEBA", +"9 c #AEBAAAAABEFB", +"0 c #96589248A699", +"q c #A699AAAAB6DA", +"w c #AEBAAAAAB6DA", +"e c #D75CD34CD75C", +"r c #EFBEE79DEFBE", +"t c #BEFBB6DABEFB", +"y c #B6DABAEAC71B", +"u c #AEBAAEBAB6DA", +"i c #E79DDB6CDF7D", +"p c #96588E389658", +"a c #596559656185", +"s c #AEBA8E388E38", +"d c #CF3CCB2BCF3C", +"f c #9E799A699E79", +"g c #86177DF78E38", +"h c #69A6659571C6", +"j c #AEBAAEBABEFB", +"k c #96589E799E79", +"l c #B6DAA699A699", +"z c #E79DC71BC71B", +"x c #B6DAB6DAB6DA", +"c c #861786179658", +"v c #B6DAB2CABEFB", +"b c #BEFBAAAAAEBA", +"n c #C71BBEFBC71B", +"m c #514441034103", +"M c #41033CF34103", +"N c #492428A228A2", +"B c #AEBAA289B6DA", +"V c #618530C22081", +"C c #69A630C228A2", +"Z c #69A630C22081", +"A c #596528A22081", +"S c #492428A22081", +"D c #618528A22081", +"F c #596520811861", +"G c #69A628A22081", +"H c #FFFF14514103", +" .X ", +" .oO+ ", +" @.o#++ ", +" @.o$%+ ", +" @.&#++ ", +" @.o#++ ", +" @.o$++ ", +" @.&#++ ", +" .O#++ ", +" *=-$++ ", +" ;:>+++ ", +" ;,<1% ", +" 2,34 ", +" 2;,51 ", +" 2,,,,6 ", +" 7777 28888,6 ", +" 77777777 2829,,,06 ", +" 9qwwe7rrrrr77rr 828,9tyt,6 ", +" uuwriirrieiiieii77pa< 82,8,,,8,06 ", +" s=1ttiieeeeded77eufgh>j,8,8,k,0,6 ", +" =@lzieeeeee77eeex:fpcg4>9,,,,qjv6 ", +" =O=blt7eeee7deenw:ffp<gha:t979;06 ", +" =OO@=@zieeee7ex:::fffff0,v72444h6 ", +" =OOo&Osst7iee7wkf:f:ff;t721444ham ", +" =#&&&&OO@di7eu:ff:fferiv114444hmMX ", +" =O&&&..o.sdp33fff:errrii7cc1hhh6mmNX= ", +" =O&&&@.o.@sberrrrrriiuxuxnB;44aMmVCO#OX ", +" =O&&o@..o.zrrrie777nnxtuxx:x;n:>mV##&&O$mX ", +" =O&&o....zrrieieuxunx7txx:nnfwpMmVZ#$ZZZVVN ", +" =O&oooo.*rrde77ewxnxxtnw:f4M%M%+NA#$Z$ZZVmN> ", +" =Oo&ooo@iree7inxn7nnuuff4h%M>m%S-AZ$CCZDZmSX ", +" =O&o.o.@rrn7eulun7xxuwp4mm6ahM%--AZCCZDDDANX ", +" =Ooooo.*rixenuwwn7nxupph%M>>h6mAADVVZVVDDANX ", +" =O&o.o.zrexwwnwuxxnughX%mahhmMN-AZCCVVDDAAN> ", +" *XOoo.*iin7n777xxxtphaM+ama>MSNFVCZZVVDAAAS> ", +" 1O..izewxux7nuuux4%++%hha>%N-DDCZZVDAAAASX ", +" 1.=ituu:uButnxxuX%>hh>M%++NADZZZVDADAA--X ", +" :e7f::lnn7*ppnx6ahm6++mNN-ADCZVDDAAAA-SX ", +" 7nupp:wxxg%MMau6%++NmmmADADVVVVVDAA---NX ", +" 7uBgh1wwxg6h>m%:MmmVNAVDZVZCVZZDAAAAF-S+X ", +" nfgaM%pnwhX6%mXb6$DVVZC$C#C$ZZDVAAA---+NX ", +" 27a%MaM47:mN.OoolmODGZ####$$ZZVDDA-----SSX ", +" 2gmg<m6p7wmmOo...O$GZ####$$CZVVDAAA----++X ", +" qBcaM <gxgmXmo.@.o&$$##$$$CZZZDADA-A-++-NX ", +" M6> paMa HX.@@@oZ$###$$CZVDDAAAA---SS+X ", +" 43 p=&@@&&$##$CCCVVVAAA--+S+S+%X ", +" k =o@.##$VVmmmNNNSSSSSS%XXXX ", +" s>OSSNmN>>aaa177777 "}; diff --git a/gtk/fnmatch.c b/gtk/fnmatch.c new file mode 100644 index 0000000000..0a45770a40 --- /dev/null +++ b/gtk/fnmatch.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +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., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include "fnmatch.h" +#include <ctype.h> + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/gtk/fnmatch.h b/gtk/fnmatch.h new file mode 100644 index 0000000000..d9d73b3d86 --- /dev/null +++ b/gtk/fnmatch.h @@ -0,0 +1,67 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +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., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(protos) protos +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in <unistd.h>. */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/gtk/gentypeinfo.el b/gtk/gentypeinfo.el new file mode 100644 index 0000000000..2de6a92d2b --- /dev/null +++ b/gtk/gentypeinfo.el @@ -0,0 +1,137 @@ +(require 'cl) + +;;; file access + +(defun read-file (name) + (let ((buf (generate-new-buffer "infile")) + (res nil)) + (save-excursion + (set-buffer buf) + (insert-file-contents name) + (condition-case nil + (while t + (setq res (cons (read buf) res))) + (end-of-file (reverse res)))))) + +(defun setup-outfile () + (setq standard-output (generate-new-buffer "outfile"))) + +(defun write-outfile (name) + (save-excursion + (set-buffer standard-output) + (write-region (point-min) (point-max) name))) + +;;; string stunts + +(defun char-upper-case-p (ch) + (eql (upcase ch) ch)) + +(defun char-lower-case-p (ch) + (eql (downcase ch) ch)) + +(defun canonicalize (str) + (if (symbolp str) + (setq str (symbol-name str))) + (let ((res nil) + (start 0) + (pos 0) + (end (length str)) + (prevlower nil)) + (while (< pos end) + (let ((ch (elt str pos))) + (cond ((memq ch '(?- ?_)) + (setq res (cons (substring str start pos) res) + prevlower nil + pos (1+ pos) + start pos)) + ((and (char-upper-case-p ch) + prevlower) + (setq res (cons (substring str start pos) res) + start pos + pos (1+ pos) + prevlower nil)) + (t + (setq pos (1+ pos) + prevlower (char-lower-case-p ch)))))) + (reverse (mapcar 'downcase (cons (substring str start end) res))))) + +(defun syllables-to-string (syls del) + (let ((res "")) + (while syls + (setq res (format "%s%s%s" res (car syls) + (if (cdr syls) del "")) + syls (cdr syls))) + res)) + +(defun macroname (canon) + (syllables-to-string (mapcar 'upcase canon) "_")) + +(defun funcname (canon) + (syllables-to-string canon "_")) + +(defun typename (canon) + (syllables-to-string (mapcar 'capitalize canon) "")) + +(defun scmname (canon) + (syllables-to-string canon "-")) + +(defun short-name (canon) + (if (equal (car canon) "gtk") (cdr canon) canon)) + +;;; Code generation + +(defun printf (&rest args) + (princ (apply 'format args))) + +(defun interestingp (form) + (and (listp form) + (memq (car form) '(define-enum define-flags define-boxed)))) + +(defun map-interesting (func defs) + (mapcar #'(lambda (form) + (if (interestingp form) + (funcall func form))) + defs)) + +(defun emit-idmacs (defs) + (let ((i 0)) + (map-interesting + #'(lambda (form) + (let ((name (canonicalize (cadr form)))) + (printf "#define GTK_TYPE_%s (gtk_type_builtins[%d])\n" + (macroname (short-name name)) i)) + (setq i (1+ i))) + defs) + (printf "#define GTK_TYPE_NUM_BUILTINS %d\n" i))) + +(defun emit-ids (defs) + (map-interesting + #'(lambda (form) + (printf " { %S, %s },\n" + (symbol-name (cadr form)) + (case (car form) + ((define-enum) "GTK_TYPE_ENUM") + ((define-flags) "GTK_TYPE_FLAGS") + ((define-boxed) "GTK_TYPE_BOXED")))) + defs)) + + + +(if (< (length command-line-args-left) 3) + (error "args: op def-file output-file")) + +(setq op (intern (car command-line-args-left))) +(setq defs (read-file (cadr command-line-args-left))) +(setq outfile (caddr command-line-args-left)) +(setq command-line-args-left nil) + +(setup-outfile) +(printf "/* generated by gentypeinfo from \"gtk.defs\" */\n\n") +(case op + ((idmac) + (emit-idmacs defs)) + ((id) + (emit-ids defs)) + (else + (error "supported ops are: idmac id"))) +(write-outfile outfile) diff --git a/gtk/gtk.defs b/gtk/gtk.defs new file mode 100644 index 0000000000..0228e7a8bf --- /dev/null +++ b/gtk/gtk.defs @@ -0,0 +1,810 @@ +; -*- scheme -*- + +;;; Gtk enums + +(define-enum GtkWindowType + (toplevel GTK_WINDOW_TOPLEVEL) + (dialog GTK_WINDOW_DIALOG) + (popup GTK_WINDOW_POPUP)) + +(define-enum GtkStateType + (normal GTK_STATE_NORMAL) + (active GTK_STATE_ACTIVE) + (prelight GTK_STATE_PRELIGHT) + (selected GTK_STATE_SELECTED) + (insensitive GTK_STATE_INSENSITIVE)) + +(define-enum GtkDirectionType + (tab-forward GTK_DIR_TAB_FORWARD) + (tab-backward GTK_DIR_TAB_BACKWARD) + (up GTK_DIR_UP) + (down GTK_DIR_DOWN) + (left GTK_DIR_LEFT) + (right GTK_DIR_RIGHT)) + +(define-enum GtkShadowType + (none GTK_SHADOW_NONE) + (in GTK_SHADOW_IN) + (out GTK_SHADOW_OUT) + (etched-in GTK_SHADOW_ETCHED_IN) + (etched-out GTK_SHADOW_ETCHED_OUT)) + +(define-enum GtkArrowType + (up GTK_ARROW_UP) + (down GTK_ARROW_DOWN) + (left GTK_ARROW_LEFT) + (right GTK_ARROW_RIGHT)) + +(define-enum GtkPackType + (start GTK_PACK_START) + (end GTK_PACK_END)) + +(define-enum GtkPolicyType + (always GTK_POLICY_ALWAYS) + (automatic GTK_POLICY_AUTOMATIC)) + +(define-enum GtkUpdateType + (continous GTK_UPDATE_CONTINUOUS) + (discontinous GTK_UPDATE_DISCONTINUOUS) + (delayed GTK_UPDATE_DELAYED)) + +(define-flags GtkAttachOptions + (expand GTK_EXPAND) + (shrink GTK_SHRINK) + (fill GTK_FILL)) + +(define-flags GtkSignalRunType + (first GTK_RUN_FIRST) + (last GTK_RUN_LAST) + (both GTK_RUN_BOTH) + (mask GTK_RUN_MASK) + (no-recurse GTK_RUN_NO_RECURSE)) + +(define-enum GtkWindowPosition + (none GTK_WIN_POS_NONE) + (center GTK_WIN_POS_CENTER) + (mouse GTK_WIN_POS_MOUSE)) + +(define-enum GtkSubmenuDirection + (left GTK_DIRECTION_LEFT) + (right GTK_DIRECTION_RIGHT)) + +(define-enum GtkSubmenuPlacement + (top-bottom GTK_TOP_BOTTOM) + (left-right GTK_LEFT_RIGHT)) + +(define-enum GtkMenuFactoryType + (menu GTK_MENU_FACTORY_MENU) + (menu-bar GTK_MENU_FACTORY_MENU_BAR) + (option-menu GTK_MENU_FACTORY_OPTION_MENU)) + +(define-enum GtkMetricType + (pixels GTK_PIXELS) + (inches GTK_INCHES) + (centimeters GTK_CENTIMETERS)) + +(define-enum GtkScrollType + (none GTK_SCROLL_NONE) + (step-backward GTK_SCROLL_STEP_BACKWARD) + (step-forward GTK_SCROLL_STEP_FORWARD) + (page-backward GTK_SCROLL_PAGE_BACKWARD) + (page-forward GTK_SCROLL_PAGE_FORWARD)) + +(define-enum GtkTroughType + (none GTK_TROUGH_NONE) + (start GTK_TROUGH_START) + (end GTK_TROUGH_END)) + +(define-enum GtkPositionType + (left GTK_POS_LEFT) + (right GTK_POS_RIGHT) + (top GTK_POS_TOP) + (bottom GTK_POS_BOTTOM)) + +(define-enum GtkPreviewType + (color GTK_PREVIEW_COLOR) + (grayscale GTK_PREVIEW_GRAYSCALE)) + +(define-flags GtkWidgetFlags + (visible GTK_VISIBLE) + (mapped GTK_MAPPED) + (unmapped GTK_UNMAPPED) + (realized GTK_REALIZED) + (sensitive GTK_SENSITIVE) + (parent-sensitive GTK_PARENT_SENSITIVE) + (no-window GTK_NO_WINDOW) + (has-focus GTK_HAS_FOCUS) + (can-focus GTK_CAN_FOCUS) + (has-default GTK_HAS_DEFAULT) + (can-default GTK_CAN_DEFAULT) + (propagate-state GTK_PROPAGATE_STATE) + (anchored GTK_ANCHORED) + (basic GTK_BASIC) + (user-style GTK_USER_STYLE)) + +;;; Gdk enums + +(define-enum GdkWindowType + (root GDK_WINDOW_ROOT) + (toplevel GDK_WINDOW_TOPLEVEL) + (child GDK_WINDOW_CHILD) + (dialog GDK_WINDOW_DIALOG) + (temp GDK_WINDOW_TEMP) + (pixmap GDK_WINDOW_PIXMAP)) + +(define-enum GdkWindowClass + (input-output GDK_INPUT_OUTPUT) + (input-only GDK_INPUT_ONLY)) + +(define-enum GdkImageType + (normal GDK_IMAGE_NORMAL) + (shared GDK_IMAGE_SHARED) + (fastest GDK_IMAGE_FASTEST)) + +(define-enum GdkVisualType + (static-gray GDK_VISUAL_STATIC_GRAY) + (grayscale GDK_VISUAL_GRAYSCALE) + (static-color GDK_VISUAL_STATIC_COLOR) + (pseudo-color GDK_VISUAL_PSEUDO_COLOR) + (true-color GDK_VISUAL_TRUE_COLOR) + (direct-color GDK_VISUAL_DIRECT_COLOR)) + +(define-flags GdkWindowAttributesType + (title GDK_WA_TITLE) + (x GDK_WA_X) + (y GDK_WA_Y) + (cursor GDK_WA_CURSOR) + (colormap GDK_WA_COLORMAP) + (visual GDK_WA_VISUAL)) + +(define-flags GdkWindowHints + (pos GDK_HINT_POS) + (min-size GDK_HINT_MIN_SIZE) + (max-size GDK_HINT_MAX_SIZE)) + +(define-enum GdkFunction + (copy GDK_COPY) + (invert GDK_INVERT) + (xor GDK_XOR)) + +(define-enum GdkFill + (solid GDK_SOLID) + (tiled GDK_TILED) + (stippled GDK_STIPPLED) + (opaque-stippled GDK_OPAQUE_STIPPLED)) + +(define-enum GdkLineStyle + (solid GDK_LINE_SOLID) + (on-off-dash GDK_LINE_ON_OFF_DASH) + (double-dash GDK_LINE_DOUBLE_DASH)) + +(define-enum GdkCapStyle + (not-last GDK_CAP_NOT_LAST) + (butt GDK_CAP_BUTT) + (round GDK_CAP_ROUND) + (projecting GDK_CAP_PROJECTING)) + +(define-enum GdkJoinStyle + (miter GDK_JOIN_MITER) + (round GDK_JOIN_ROUND) + (bevel GDK_JOIN_BEVEL)) + +(define-enum GdkCursorType + (cursor GDK_LAST_CURSOR)) + +(define-enum GdkEventType + (nothing GDK_NOTHING) + (delete GDK_DELETE) + (destroy GDK_DESTROY) + (expose GDK_EXPOSE) + (motion-notify GDK_MOTION_NOTIFY) + (button-press GDK_BUTTON_PRESS) + (2button-press GDK_2BUTTON_PRESS) + (3button-press GDK_3BUTTON_PRESS) + (button-release GDK_BUTTON_RELEASE) + (key-press GDK_KEY_PRESS) + (key-release GDK_KEY_RELEASE) + (enter-notify GDK_ENTER_NOTIFY) + (leave-notify GDK_LEAVE_NOTIFY) + (focus-change GDK_FOCUS_CHANGE) + (configure GDK_CONFIGURE) + (map GDK_MAP) + (unmap GDK_UNMAP) + (property-notify GDK_PROPERTY_NOTIFY) + (selection-clear GDK_SELECTION_CLEAR) + (selection-request GDK_SELECTION_REQUEST) + (selection-notify GDK_SELECTION_NOTIFY) + (other-event GDK_OTHER_EVENT)) + +(define-flags GdkEventMask + (exposure-mask GDK_EXPOSURE_MASK) + (pointer-motion-mask GDK_POINTER_MOTION_MASK) + (pointer-motion-hint-mask GDK_POINTER_MOTION_HINT_MASK) + (button-motion-mask GDK_BUTTON_MOTION_MASK) + (button1-motion-mask GDK_BUTTON1_MOTION_MASK) + (button2-motion-mask GDK_BUTTON2_MOTION_MASK) + (button3-motion-mask GDK_BUTTON3_MOTION_MASK) + (button-press-mask GDK_BUTTON_PRESS_MASK) + (button-release-mask GDK_BUTTON_RELEASE_MASK) + (key-press-mask GDK_KEY_PRESS_MASK) + (key-release-mask GDK_KEY_RELEASE_MASK) + (enter-notify-mask GDK_ENTER_NOTIFY_MASK) + (leave-notify-mask GDK_LEAVE_NOTIFY_MASK) + (focus-change-mask GDK_FOCUS_CHANGE_MASK) + (structure-mask GDK_STRUCTURE_MASK) + (all-events-mask GDK_ALL_EVENTS_MASK)) + +(define-enum GdkNotifyType + (ancestor GDK_NOTIFY_ANCESTOR) + (virtual GDK_NOTIFY_VIRTUAL) + (inferior GDK_NOTIFY_INFERIOR) + (nonlinear GDK_NOTIFY_NONLINEAR) + (nonlinear-virtual GDK_NOTIFY_NONLINEAR_VIRTUAL) + (unknown GDK_NOTIFY_UNKNOWN)) + +(define-flags GdkModifierType + (shift-mask GDK_SHIFT_MASK) + (lock-mask GDK_LOCK_MASK) + (control-mask GDK_CONTROL_MASK) + (mod1-mask GDK_MOD1_MASK) + (mod2-mask GDK_MOD2_MASK) + (mod3-mask GDK_MOD3_MASK) + (mod4-mask GDK_MOD4_MASK) + (mod5-mask GDK_MOD5_MASK) + (button1-mask GDK_BUTTON1_MASK) + (button2-mask GDK_BUTTON2_MASK) + (button3-mask GDK_BUTTON3_MASK) + (button4-mask GDK_BUTTON4_MASK) + (button5-mask GDK_BUTTON5_MASK)) + +(define-enum GdkSubwindowMode + (clip-by-children GDK_CLIP_BY_CHILDREN) + (include-inferiors GDK_INCLUDE_INFERIORS)) + +(define-flags GdkInputCondition + (read GDK_INPUT_READ) + (write GDK_INPUT_WRITE) + (exception GDK_INPUT_EXCEPTION)) + +(define-enum GdkStatus + (ok GDK_OK) + (error GDK_ERROR) + (error-param GDK_ERROR_PARAM) + (error-file GDK_ERROR_FILE) + (error-mem GDK_ERROR_MEM)) + +(define-enum GdkByteOrder + (lsb-first GDK_LSB_FIRST) + (msb-first GDK_MSB_FIRST)) + +(define-flags GdkGCValuesMask + (foreground GDK_GC_FOREGROUND) + (background GDK_GC_BACKGROUND) + (font GDK_GC_FONT) + (function GDK_GC_FUNCTION) + (fill GDK_GC_FILL) + (tile GDK_GC_TILE) + (stipple GDK_GC_STIPPLE) + (clip-mask GDK_GC_CLIP_MASK) + (subwindow GDK_GC_SUBWINDOW) + (ts-x-origin GDK_GC_TS_X_ORIGIN) + (ts-y-origin GDK_GC_TS_Y_ORIGIN) + (clip-x-origin GDK_GC_CLIP_X_ORIGIN) + (clip-y-origin GDK_GC_CLIP_Y_ORIGIN) + (exposures GDK_GC_EXPOSURES) + (line-width GDK_GC_LINE_WIDTH) + (line-style GDK_GC_LINE_STYLE) + (cap-style GDK_GC_CAP_STYLE) + (join-style GDK_GC_JOIN_STYLE)) + +(define-enum GdkSelection + (primary GDK_SELECTION_PRIMARY) + (secondary GDK_SELECTION_SECONDARY)) + +(define-enum GdkPropertyState + (new-value GDK_PROPERTY_NEW_VALUE) + (delete GDK_PROPERTY_DELETE)) + +(define-enum GdkPropMode + (replace GDK_PROP_MODE_REPLACE) + (prepend GDK_PROP_MODE_PREPEND) + (append GDK_PROP_MODE_APPEND)) + +;;; Gtk boxed types + +(define-boxed GtkAcceleratorTable + gtk_accelerator_table_ref + gtk_accelerator_table_unref) + +(define-boxed GtkStyle + gtk_style_ref + gtk_style_unref) + +;;; Gdk boxed types + +;(define-boxed GdkPoint +; gdk_point_copy +; gdk_point_destroy) + +(define-boxed GdkColormap + gdk_colormap_ref + gdk_colormap_unref) + +(define-boxed GdkVisual + gdk_visual_ref + gdk_visual_unref) + +(define-boxed GdkFont + gdk_font_ref + gdk_font_free) + +(define-boxed GdkWindow + gdk_window_ref + gdk_window_unref) + +(define-boxed GdkEvent + gdk_event_copy + gdk_event_free) + +;;; Functions + +(define-func gtk_exit + none + (int code 0)) + +(define-func gtk_rc_parse + none + (string file)) + +(define-func g_mem_chunk_info + none) + +;; GtkObject + +(define-func gtk_object_destroy + none + (GtkObject object)) + +;; GtkWidget + +(define-object GtkWidget (GtkObject)) + +(define-func GTK_WIDGET_STATE + GtkStateType + (GtkWidget widget)) + +(define-func GTK_WIDGET_FLAGS + GtkWidgetFlags + (GtkWidget widget)) + +(define-func GTK_WIDGET_SET_FLAGS + none + (GtkWidget widget) + (GtkWidgetFlags flags)) + +(define-func GTK_WIDGET_UNSET_FLAGS + none + (GtkWidget widget) + (GtkWidgetFlags flags)) + +(define-func gtk_widget_destroy + none + (GtkWidget widget)) + +(define-func gtk_widget_unparent + none + (GtkWidget widget)) + +(define-func gtk_widget_show + none + (GtkWidget widget)) + +(define-func gtk_widget_hide + none + (GtkWidget widget)) + +(define-func gtk_widget_map + none + (GtkWidget widget)) + +(define-func gtk_widget_unmap + none + (GtkWidget widget)) + +(define-func gtk_widget_realize + none + (GtkWidget widget)) + +(define-func gtk_widget_unrealize + none + (GtkWidget widget)) + +;(define-func gtk_widget_install_accelerator +; none +; (GtkWidget widget) +; (GtkAcceleratorTable table) +; (string signal_name) +; (char key) +; (...)) + +(define-func gtk_widget_remove_accelerator + none + (GtkWidget widget) + (GtkAcceleratorTable table) + (string signal_name)) + +;(define-func gtk_widget_event +; bool +; (GtkWidget widget) +; (GdkEvent event)) + +(define-func gtk_widget_activate + none + (GtkWidget widget)) + +(define-func gtk_widget_reparent + none + (GtkWidget widget) + (GtkWidget new_parent)) + +(define-func gtk_widget_popup + none + (GtkWidget widget) + (int x) + (int y)) + +(define-func gtk_widget_basic + bool + (GtkWidget widget)) + +(define-func gtk_widget_grab_focus + none + (GtkWidget widget)) + +(define-func gtk_widget_grab_default + none + (GtkWidget widget)) + +(define-func gtk_widget_restore_state + none + (GtkWidget widget)) + +(define-func gtk_widget_set_name + none + (GtkWidget widget) + (string name)) + +(define-func gtk_widget_get_name + static_string + (GtkWidget widget)) + +(define-func gtk_widget_set_state + none + (GtkWidget widget) + (GtkStateType state)) + +(define-func gtk_widget_set_sensitive + none + (GtkWidget widget) + (bool sensitive)) + +(define-func gtk_widget_set_style + none + (GtkWidget widget) + (GtkStyle style)) + +(define-func gtk_widget_set_uposition + none + (GtkWidget widget) + (int x) + (int y)) + +(define-func gtk_widget_set_usize + none + (GtkWidget widget) + (int height) + (int width)) + +(define-func gtk_widget_set_events + none + (GtkWidget widget) + (GdkEventMask events)) + +(define-func gtk_widget_set_extension_events + none + (GtkWidget widget) + (GdkEventMask events)) + +(define-func gtk_widget_get_toplevel + GtkWidget + (GtkWidget widget)) + +;(define-func gtk_widget_get_ancestor +; GtkWidget +; (GtkWidget widget) +; (GtkType type)) + +(define-func gtk_widget_get_colormap + GdkColormap + (GtkWidget widget)) + +(define-func gtk_widget_get_visual + GdkVisual + (GtkWidget widget)) + +(define-func gtk_widget_get_style + GtkStyle + (GtkWidget widget)) + +(define-func gtk_widget_get_events + GdkEventMask + (GtkWidget widget)) + +(define-func gtk_widget_get_extension_events + GdkEventMask + (GtkWidget widget)) + +(define-func gtk_widget_push_colormap + none + (GdkColormap cmap)) + +(define-func gtk_widget_push_visual + none + (GdkVisual visual)) + +(define-func gtk_widget_push_style + none + (GtkStyle style)) + +(define-func gtk_widget_pop_colormap + none) + +(define-func gtk_widget_pop_visual + none) + +(define-func gtk_widget_pop_style + none) + +(define-func gtk_widget_set_default_colormap + none + (GdkColormap cmap)) + +(define-func gtk_widget_set_default_visual + none + (GdkVisual visual)) + +(define-func gtk_widget_set_default_style + none + (GtkStyle style)) + +(define-func gtk_widget_get_default_colormap + GdkColormap) + +(define-func gtk_widget_get_default_visual + GdkVisual) + +(define-func gtk_widget_get_default_style + GtkStyle) + +;;; Container + +(define-object GtkContainer (GtkWidget)) + +(define-func gtk_container_border_width + none + (GtkContainer container) + (int border_width)) + +(define-func gtk_container_add + none + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_remove + none + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_disable_resize + none + (GtkContainer container)) + +(define-func gtk_container_enable_resize + none + (GtkContainer container)) + +(define-func gtk_container_block_resize + none + (GtkContainer container)) + +(define-func gtk_container_unblock_resize + none + (GtkContainer container)) + +(define-func gtk_container_need_resize + bool + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_check_resize + none + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_focus + GtkDirectionType + (GtkContainer container) + (GtkDirectionType direction)) + +;;; Bin + +(define-object GtkBin (GtkContainer)) + +;;; Window + +(define-object GtkWindow (GtkBin)) + +(define-func gtk_window_new + GtkWidget + (GtkWindowType type)) + +(define-func gtk_window_set_title + none + (GtkWindow window) + (string title)) + +(define-func gtk_window_set_focus + none + (GtkWindow window) + (GtkWidget focus)) + +(define-func gtk_window_set_default + none + (GtkWindow window) + (GtkWidget default)) + +(define-func gtk_window_set_policy + none + (GtkWindow window) + (bool allow_shrink) + (bool allow_grow) + (bool auto_shrink)) + +(define-func gtk_window_add_accelerator_table + none + (GtkWindow window) + (GtkAcceleratorTable table)) + +(define-func gtk_window_remove_accelerator_table + none + (GtkWindow window) + (GtkAcceleratorTable table)) + +(define-func gtk_window_position + none + (GtkWindow window) + (GtkWindowPosition position)) + +;;; Box + +(define-object GtkBox (GtkContainer)) + +;;; Table + +(define-object GtkTable (GtkContainer)) + +;;; Button + +(define-object GtkButton (GtkContainer)) + +;;; ToggleButton + +(define-object GtkToggleButton (GtkButton)) + +;;; CheckButton + +(define-object GtkCheckButton (GtkToggleButton)) + +;;; RadioButton + +(define-object GtkRadioButton (GtkCheckButton)) + + +;; misc + + +(define-func gtk_button_new_with_label + GtkWidget + (string label)) + +(define-func gtk_vbox_new + GtkWidget + (bool homogenous) + (int spacing)) + +(define-func gtk_hbox_new + GtkWidget + (bool homogenous) + (int spacing)) + +(define-func gtk_hseparator_new + GtkWidget) + +(define-func gtk_box_pack_start + none + (GtkBox box) + (GtkWidget child) + (bool expand) + (bool fill) + (int padding)) + +(define-func gtk_table_new + GtkWidget + (int rows) + (int columns) + (bool homogenous)) + +(define-func gtk_table_attach + none + (GtkTable table) + (GtkWidget child) + (int left_attach) + (int right_attach) + (int top_attach) + (int bottom_attach) + (GtkAttachOptions xoptions) + (GtkAttachOptions yoptions) + (int xpadding) + (int ypadding)) + +(define-func gtk_table_attach_defaults + none + (GtkTable table) + (GtkWidget child) + (int left_attach) + (int right_attach) + (int top_attach) + (int bottom_attach)) + +(define-func gtk_table_set_row_spacing + none + (GtkTable table) + (int row) + (int spacing)) + +(define-func gtk_table_set_col_spacing + none + (GtkTable table) + (int col) + (int spacing)) + +(define-func gtk_table_set_row_spacings + none + (GtkTable table) + (int spacing)) + +(define-func gtk_table_set_col_spacings + none + (GtkTable table) + (int spacing)) + +(define-func gtk_toggle_button_new_with_label + GtkWidget + (string label)) + +(define-func gtk_check_button_new_with_label + GtkWidget + (string label)) + +(define-func gtk_radio_button_new_with_label_from_widget + GtkWidget + (GtkRadioButton group) + (string label)) + +(define-func gtk_label_new + GtkWidget + (string label)) + +(define-func gtk_frame_new + GtkWidget + (string label)) diff --git a/gtk/gtk.h b/gtk/gtk.h new file mode 100644 index 0000000000..acd1b10468 --- /dev/null +++ b/gtk/gtk.h @@ -0,0 +1,106 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_H__ +#define __GTK_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkaccelerator.h> +#include <gtk/gtkadjustment.h> +#include <gtk/gtkalignment.h> +#include <gtk/gtkaspectframe.h> +#include <gtk/gtkarrow.h> +#include <gtk/gtkbin.h> +#include <gtk/gtkbox.h> +#include <gtk/gtkbbox.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkcheckbutton.h> +#include <gtk/gtkcheckmenuitem.h> +#include <gtk/gtkcolorsel.h> +#include <gtk/gtkcontainer.h> +#include <gtk/gtkcurve.h> +#include <gtk/gtkdata.h> +#include <gtk/gtkdialog.h> +#include <gtk/gtkdrawingarea.h> +#include <gtk/gtkentry.h> +#include <gtk/gtkenums.h> +#include <gtk/gtkeventbox.h> +#include <gtk/gtkfilesel.h> +#include <gtk/gtkfixed.h> +#include <gtk/gtkframe.h> +#include <gtk/gtkgamma.h> +#include <gtk/gtkgc.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkhbbox.h> +#include <gtk/gtkhpaned.h> +#include <gtk/gtkhruler.h> +#include <gtk/gtkhscale.h> +#include <gtk/gtkhscrollbar.h> +#include <gtk/gtkhseparator.h> +#include <gtk/gtkimage.h> +#include <gtk/gtkinputdialog.h> +#include <gtk/gtkitem.h> +#include <gtk/gtklabel.h> +#include <gtk/gtklist.h> +#include <gtk/gtklistitem.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenubar.h> +#include <gtk/gtkmenufactory.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkmenushell.h> +#include <gtk/gtkmisc.h> +#include <gtk/gtknotebook.h> +#include <gtk/gtkobject.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtkpaned.h> +#include <gtk/gtkpixmap.h> +#include <gtk/gtkpreview.h> +#include <gtk/gtkprogressbar.h> +#include <gtk/gtkradiobutton.h> +#include <gtk/gtkradiomenuitem.h> +#include <gtk/gtkrange.h> +#include <gtk/gtkrc.h> +#include <gtk/gtkruler.h> +#include <gtk/gtkscale.h> +#include <gtk/gtkscrollbar.h> +#include <gtk/gtkscrolledwindow.h> +#include <gtk/gtkselection.h> +#include <gtk/gtkseparator.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkstyle.h> +#include <gtk/gtktable.h> +#include <gtk/gtktext.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtktooltips.h> +#include <gtk/gtktree.h> +#include <gtk/gtktreeitem.h> +#include <gtk/gtktypeutils.h> +#include <gtk/gtkvbox.h> +#include <gtk/gtkvbbox.h> +#include <gtk/gtkviewport.h> +#include <gtk/gtkvpaned.h> +#include <gtk/gtkvruler.h> +#include <gtk/gtkvscale.h> +#include <gtk/gtkvscrollbar.h> +#include <gtk/gtkvseparator.h> +#include <gtk/gtkwidget.h> +#include <gtk/gtkwindow.h> + + +#endif /* __GTK_H__ */ diff --git a/gtk/gtkaccelerator.c b/gtk/gtkaccelerator.c new file mode 100644 index 0000000000..a06a06a995 --- /dev/null +++ b/gtk/gtkaccelerator.c @@ -0,0 +1,352 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <ctype.h> +#include "gtkaccelerator.h" +#include "gtksignal.h" +#include "gtkwidget.h" + + +typedef struct _GtkAcceleratorEntry GtkAcceleratorEntry; + +struct _GtkAcceleratorEntry +{ + guint8 modifiers; + GtkObject *object; + gint signal_num; +}; + + +static void gtk_accelerator_table_init (GtkAcceleratorTable *table); +static void gtk_accelerator_table_clean (GtkAcceleratorTable *table); + + +static GtkAcceleratorTable *default_table = NULL; +static GSList *tables = NULL; +static guint8 gtk_accelerator_table_default_mod_mask = ~0; + + +GtkAcceleratorTable* +gtk_accelerator_table_new () +{ + GtkAcceleratorTable *table; + + table = g_new (GtkAcceleratorTable, 1); + gtk_accelerator_table_init (table); + + tables = g_slist_prepend (tables, table); + + return table; +} + +GtkAcceleratorTable* +gtk_accelerator_table_find (GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods) +{ + GtkAcceleratorTable *table; + GtkAcceleratorEntry *entry; + GSList *tmp_list; + GList *entries; + gint signal_num; + guint hash; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (signal_name != NULL, NULL); + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object)); + hash = (guint) accelerator_key; + + tmp_list = tables; + while (tmp_list) + { + table = tmp_list->data; + tmp_list = tmp_list->next; + + entries = table->entries[hash]; + while (entries) + { + entry = entries->data; + entries = entries->next; + + if ((entry->object == object) && + (entry->signal_num == signal_num) && + ((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask))) + return table; + } + } + + return NULL; +} + +void +gtk_accelerator_table_destroy (GtkAcceleratorTable *table) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (table->ref_count <= 0); + + tables = g_slist_remove (tables, table); + gtk_accelerator_table_clean (table); + g_free (table); +} + +GtkAcceleratorTable* +gtk_accelerator_table_ref (GtkAcceleratorTable *table) +{ + g_return_val_if_fail (table != NULL, NULL); + + table->ref_count += 1; + return table; +} + +void +gtk_accelerator_table_unref (GtkAcceleratorTable *table) +{ + g_return_if_fail (table != NULL); + + table->ref_count -= 1; + if (table->ref_count <= 0) + gtk_accelerator_table_destroy (table); +} + +void +gtk_accelerator_table_install (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods) +{ + GtkAcceleratorEntry *entry; + GList *entries; + gchar *signame; + gint signal_num; + guint hash; + + g_return_if_fail (object != NULL); + + if (!table) + { + if (!default_table) + default_table = gtk_accelerator_table_new (); + table = default_table; + } + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object)); + g_return_if_fail (signal_num != 0); + + hash = (guint) accelerator_key; + entries = table->entries[hash]; + + while (entries) + { + entry = entries->data; + + if ((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask)) + { + if (GTK_IS_WIDGET (entry->object)) + { + signame = gtk_signal_name (entry->signal_num); + gtk_signal_emit_by_name (entry->object, + "remove_accelerator", + signame); + } + + entry->modifiers = accelerator_mods; + entry->object = object; + entry->signal_num = signal_num; + return; + } + + entries = entries->next; + } + + entry = g_new (GtkAcceleratorEntry, 1); + entry->modifiers = accelerator_mods; + entry->object = object; + entry->signal_num = signal_num; + + table->entries[hash] = g_list_prepend (table->entries[hash], entry); +} + +void +gtk_accelerator_table_remove (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name) +{ + GtkAcceleratorEntry *entry; + GList *entries; + GList *temp_list; + gint signal_num; + gint i; + + g_return_if_fail (object != NULL); + + if (!table) + { + if (!default_table) + default_table = gtk_accelerator_table_new (); + table = default_table; + } + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object)); + g_return_if_fail (signal_num != 0); + + for (i = 0; i < 256; i++) + { + entries = table->entries[i]; + + while (entries) + { + entry = entries->data; + + if ((entry->object == object) && (entry->signal_num == signal_num)) + { + g_free (entry); + + temp_list = entries; + if (entries->next) + entries->next->prev = entries->prev; + if (entries->prev) + entries->prev->next = entries->next; + if (table->entries[i] == entries) + table->entries[i] = entries->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + + return; + } + + entries = entries->next; + } + } +} + +gint +gtk_accelerator_table_check (GtkAcceleratorTable *table, + const guchar accelerator_key, + guint8 accelerator_mods) +{ + GtkAcceleratorEntry *entry; + GList *entries; + guint hash; + + if (!table) + { + if (!default_table) + default_table = gtk_accelerator_table_new (); + table = default_table; + } + + hash = (guint) accelerator_key; + entries = table->entries[hash]; + + while (entries) + { + entry = entries->data; + + if ((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask)) + { + gtk_signal_emit (entry->object, entry->signal_num); + return TRUE; + } + + entries = entries->next; + } + + if (!isupper (hash)) + { + hash = toupper (hash); + entries = table->entries[hash]; + + while (entries) + { + entry = entries->data; + + if (((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask)) && + (GTK_IS_WIDGET (entry->object) && + GTK_WIDGET_SENSITIVE (entry->object))) + { + gtk_signal_emit (entry->object, entry->signal_num); + return TRUE; + } + + entries = entries->next; + } + } + + return FALSE; +} + +void +gtk_accelerator_table_set_mod_mask (GtkAcceleratorTable *table, + guint8 modifier_mask) +{ + if (table == NULL) + { + gtk_accelerator_table_default_mod_mask = modifier_mask; + } + else + { + table->modifier_mask = modifier_mask; + } +} + +static void +gtk_accelerator_table_init (GtkAcceleratorTable *table) +{ + gint i; + + g_return_if_fail (table != NULL); + + for (i = 0; i < 256; i++) + table->entries[i] = NULL; + + table->ref_count = 0; + table->modifier_mask = gtk_accelerator_table_default_mod_mask; +} + +static void +gtk_accelerator_table_clean (GtkAcceleratorTable *table) +{ + GtkAcceleratorEntry *entry; + GList *entries; + gint i; + + g_return_if_fail (table != NULL); + + for (i = 0; i < 256; i++) + { + entries = table->entries[i]; + while (entries) + { + entry = entries->data; + entries = entries->next; + + g_free (entry); + } + + g_list_free (table->entries[i]); + table->entries[i] = NULL; + } +} diff --git a/gtk/gtkaccelerator.h b/gtk/gtkaccelerator.h new file mode 100644 index 0000000000..ac6323209c --- /dev/null +++ b/gtk/gtkaccelerator.h @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ACCELERATOR_H__ +#define __GTK_ACCELERATOR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkobject.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GtkAcceleratorTable GtkAcceleratorTable; + +struct _GtkAcceleratorTable +{ + GList *entries[256]; + gint ref_count; + guint8 modifier_mask; +}; + + +/* Accelerator tables. + */ +GtkAcceleratorTable* gtk_accelerator_table_new (void); +GtkAcceleratorTable* gtk_accelerator_table_find (GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods); + +void gtk_accelerator_table_destroy (GtkAcceleratorTable *table); +GtkAcceleratorTable *gtk_accelerator_table_ref (GtkAcceleratorTable *table); +void gtk_accelerator_table_unref (GtkAcceleratorTable *table); +void gtk_accelerator_table_install (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods); +void gtk_accelerator_table_remove (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name); +gint gtk_accelerator_table_check (GtkAcceleratorTable *table, + const guchar accelerator_key, + guint8 accelerator_mods); + +void gtk_accelerator_table_set_mod_mask (GtkAcceleratorTable *table, + guint8 modifier_mask); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ACCELERATOR_H__ */ diff --git a/gtk/gtkadjustment.c b/gtk/gtkadjustment.c new file mode 100644 index 0000000000..ab6e63d216 --- /dev/null +++ b/gtk/gtkadjustment.c @@ -0,0 +1,118 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkadjustment.h" +#include "gtksignal.h" + + +enum { + CHANGED, + VALUE_CHANGED, + LAST_SIGNAL +}; + + +static void gtk_adjustment_class_init (GtkAdjustmentClass *klass); +static void gtk_adjustment_init (GtkAdjustment *adjustment); + + +static gint adjustment_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_adjustment_get_type () +{ + static guint adjustment_type = 0; + + if (!adjustment_type) + { + GtkTypeInfo adjustment_info = + { + "GtkAdjustment", + sizeof (GtkAdjustment), + sizeof (GtkAdjustmentClass), + (GtkClassInitFunc) gtk_adjustment_class_init, + (GtkObjectInitFunc) gtk_adjustment_init, + (GtkArgFunc) NULL, + }; + + adjustment_type = gtk_type_unique (gtk_data_get_type (), &adjustment_info); + } + + return adjustment_type; +} + +static void +gtk_adjustment_class_init (GtkAdjustmentClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + adjustment_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_FIRST | GTK_RUN_NO_RECURSE, + object_class->type, + GTK_SIGNAL_OFFSET (GtkAdjustmentClass, changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + adjustment_signals[VALUE_CHANGED] = + gtk_signal_new ("value_changed", + GTK_RUN_FIRST | GTK_RUN_NO_RECURSE, + object_class->type, + GTK_SIGNAL_OFFSET (GtkAdjustmentClass, value_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, adjustment_signals, LAST_SIGNAL); + + class->changed = NULL; + class->value_changed = NULL; +} + +static void +gtk_adjustment_init (GtkAdjustment *adjustment) +{ + adjustment->value = 0.0; + adjustment->lower = 0.0; + adjustment->upper = 0.0; + adjustment->step_increment = 0.0; + adjustment->page_increment = 0.0; + adjustment->page_size = 0.0; +} + +GtkObject* +gtk_adjustment_new (gfloat value, + gfloat lower, + gfloat upper, + gfloat step_increment, + gfloat page_increment, + gfloat page_size) +{ + GtkAdjustment *adjustment; + + adjustment = gtk_type_new (gtk_adjustment_get_type ()); + + adjustment->value = value; + adjustment->lower = lower; + adjustment->upper = upper; + adjustment->step_increment = step_increment; + adjustment->page_increment = page_increment; + adjustment->page_size = page_size; + + return GTK_OBJECT (adjustment); +} diff --git a/gtk/gtkadjustment.h b/gtk/gtkadjustment.h new file mode 100644 index 0000000000..7832d1dd1f --- /dev/null +++ b/gtk/gtkadjustment.h @@ -0,0 +1,74 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ADJUSTMENT_H__ +#define __GTK_ADJUSTMENT_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkdata.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ADJUSTMENT(obj) GTK_CHECK_CAST (obj, gtk_adjustment_get_type (), GtkAdjustment) +#define GTK_ADJUSTMENT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_adjustment_get_type (), GtkAdjustmentClass) +#define GTK_IS_ADJUSTMENT(obj) GTK_CHECK_TYPE (obj, gtk_adjustment_get_type ()) + + +typedef struct _GtkAdjustment GtkAdjustment; +typedef struct _GtkAdjustmentClass GtkAdjustmentClass; + +struct _GtkAdjustment +{ + GtkData data; + + gfloat lower; + gfloat upper; + gfloat value; + gfloat step_increment; + gfloat page_increment; + gfloat page_size; +}; + +struct _GtkAdjustmentClass +{ + GtkDataClass parent_class; + + void (* changed) (GtkAdjustment *adjustment); + void (* value_changed) (GtkAdjustment *adjustment); +}; + + +guint gtk_adjustment_get_type (void); +GtkObject* gtk_adjustment_new (gfloat value, + gfloat lower, + gfloat upper, + gfloat step_increment, + gfloat page_increment, + gfloat page_size); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ADJUSTMENT_H__ */ diff --git a/gtk/gtkalignment.c b/gtk/gtkalignment.c new file mode 100644 index 0000000000..b562cff770 --- /dev/null +++ b/gtk/gtkalignment.c @@ -0,0 +1,193 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkalignment.h" + + +static void gtk_alignment_class_init (GtkAlignmentClass *klass); +static void gtk_alignment_init (GtkAlignment *alignment); +static void gtk_alignment_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_alignment_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_alignment_get_type () +{ + static guint alignment_type = 0; + + if (!alignment_type) + { + GtkTypeInfo alignment_info = + { + "GtkAlignment", + sizeof (GtkAlignment), + sizeof (GtkAlignmentClass), + (GtkClassInitFunc) gtk_alignment_class_init, + (GtkObjectInitFunc) gtk_alignment_init, + (GtkArgFunc) NULL, + }; + + alignment_type = gtk_type_unique (gtk_bin_get_type (), &alignment_info); + } + + return alignment_type; +} + +static void +gtk_alignment_class_init (GtkAlignmentClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_alignment_size_request; + widget_class->size_allocate = gtk_alignment_size_allocate; +} + +static void +gtk_alignment_init (GtkAlignment *alignment) +{ + GTK_WIDGET_SET_FLAGS (alignment, GTK_NO_WINDOW | GTK_BASIC); + + alignment->xalign = 0.5; + alignment->yalign = 0.5; + alignment->xscale = 1.0; + alignment->yscale = 1.0; +} + +GtkWidget* +gtk_alignment_new (gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale) +{ + GtkAlignment *alignment; + + alignment = gtk_type_new (gtk_alignment_get_type ()); + + alignment->xalign = CLAMP (xalign, 0.0, 1.0); + alignment->yalign = CLAMP (yalign, 0.0, 1.0); + alignment->xscale = CLAMP (xscale, 0.0, 1.0); + alignment->yscale = CLAMP (yscale, 0.0, 1.0); + + return GTK_WIDGET (alignment); +} + +void +gtk_alignment_set (GtkAlignment *alignment, + gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale) +{ + g_return_if_fail (alignment != NULL); + g_return_if_fail (GTK_IS_ALIGNMENT (alignment)); + + xalign = CLAMP (xalign, 0.0, 1.0); + yalign = CLAMP (yalign, 0.0, 1.0); + xscale = CLAMP (xscale, 0.0, 1.0); + yscale = CLAMP (yscale, 0.0, 1.0); + + if ((alignment->xalign != xalign) || + (alignment->yalign != yalign) || + (alignment->xscale != xscale) || + (alignment->yscale != yscale)) + { + alignment->xalign = xalign; + alignment->yalign = yalign; + alignment->xscale = xscale; + alignment->yscale = yscale; + + gtk_widget_size_allocate (GTK_WIDGET (alignment), &(GTK_WIDGET (alignment)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (alignment)); + } +} + + +static void +gtk_alignment_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkAlignment *alignment; + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ALIGNMENT (widget)); + g_return_if_fail (requisition != NULL); + + alignment = GTK_ALIGNMENT (widget); + bin = GTK_BIN (widget); + + requisition->width = GTK_CONTAINER (widget)->border_width * 2; + requisition->height = GTK_CONTAINER (widget)->border_width * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_alignment_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkAlignment *alignment; + GtkBin *bin; + GtkAllocation child_allocation; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ALIGNMENT (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + alignment = GTK_ALIGNMENT (widget); + bin = GTK_BIN (widget); + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + x = GTK_CONTAINER (alignment)->border_width; + y = GTK_CONTAINER (alignment)->border_width; + width = allocation->width - 2 * x; + height = allocation->height - 2 * y; + + if (width > bin->child->requisition.width) + child_allocation.width = (bin->child->requisition.width * + (1.0 - alignment->xscale) + + width * alignment->xscale); + else + child_allocation.width = width; + + if (height > bin->child->requisition.height) + child_allocation.height = (bin->child->requisition.height * + (1.0 - alignment->yscale) + + height * alignment->yscale); + else + child_allocation.height = height; + + child_allocation.x = alignment->xalign * (width - child_allocation.width) + allocation->x + x; + child_allocation.y = alignment->yalign * (height - child_allocation.height) + allocation->y + y; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} diff --git a/gtk/gtkalignment.h b/gtk/gtkalignment.h new file mode 100644 index 0000000000..c80ad7f14b --- /dev/null +++ b/gtk/gtkalignment.h @@ -0,0 +1,72 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ALIGNMENT_H__ +#define __GTK_ALIGNMENT_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbin.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ALIGNMENT(obj) GTK_CHECK_CAST (obj, gtk_alignment_get_type (), GtkAlignment) +#define GTK_ALIGNMENT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_alignment_get_type (), GtkAlignmentClass) +#define GTK_IS_ALIGNMENT(obj) GTK_CHECK_TYPE (obj, gtk_alignment_get_type ()) + + +typedef struct _GtkAlignment GtkAlignment; +typedef struct _GtkAlignmentClass GtkAlignmentClass; + +struct _GtkAlignment +{ + GtkBin bin; + + gfloat xalign; + gfloat yalign; + gfloat xscale; + gfloat yscale; +}; + +struct _GtkAlignmentClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_alignment_get_type (void); +GtkWidget* gtk_alignment_new (gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale); +void gtk_alignment_set (GtkAlignment *alignment, + gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ALIGNMENT_H__ */ diff --git a/gtk/gtkarrow.c b/gtk/gtkarrow.c new file mode 100644 index 0000000000..b8bc2143ed --- /dev/null +++ b/gtk/gtkarrow.c @@ -0,0 +1,165 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkarrow.h" + + +#define MIN_ARROW_SIZE 11 + + +static void gtk_arrow_class_init (GtkArrowClass *klass); +static void gtk_arrow_init (GtkArrow *arrow); +static gint gtk_arrow_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_arrow_get_type () +{ + static guint arrow_type = 0; + + if (!arrow_type) + { + GtkTypeInfo arrow_info = + { + "GtkArrow", + sizeof (GtkArrow), + sizeof (GtkArrowClass), + (GtkClassInitFunc) gtk_arrow_class_init, + (GtkObjectInitFunc) gtk_arrow_init, + (GtkArgFunc) NULL, + }; + + arrow_type = gtk_type_unique (gtk_misc_get_type (), &arrow_info); + } + + return arrow_type; +} + +static void +gtk_arrow_class_init (GtkArrowClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_arrow_expose; +} + +static void +gtk_arrow_init (GtkArrow *arrow) +{ + GTK_WIDGET_SET_FLAGS (arrow, GTK_NO_WINDOW); + + arrow->arrow_type = GTK_ARROW_RIGHT; + arrow->shadow_type = GTK_SHADOW_OUT; +} + +GtkWidget* +gtk_arrow_new (GtkArrowType arrow_type, + GtkShadowType shadow_type) +{ + GtkArrow *arrow; + + arrow = gtk_type_new (gtk_arrow_get_type ()); + + GTK_WIDGET (arrow)->requisition.width = MIN_ARROW_SIZE + GTK_MISC (arrow)->xpad * 2; + GTK_WIDGET (arrow)->requisition.height = MIN_ARROW_SIZE + GTK_MISC (arrow)->ypad * 2; + + arrow->arrow_type = arrow_type; + arrow->shadow_type = shadow_type; + + return GTK_WIDGET (arrow); +} + +void +gtk_arrow_set (GtkArrow *arrow, + GtkArrowType arrow_type, + GtkShadowType shadow_type) +{ + g_return_if_fail (arrow != NULL); + g_return_if_fail (GTK_IS_ARROW (arrow)); + + if (((GtkArrowType) arrow->arrow_type != arrow_type) || + ((GtkShadowType) arrow->shadow_type != shadow_type)) + { + arrow->arrow_type = arrow_type; + arrow->shadow_type = shadow_type; + + if (GTK_WIDGET_DRAWABLE (arrow)) + { + gdk_window_clear_area (GTK_WIDGET (arrow)->window, + GTK_WIDGET (arrow)->allocation.x + 1, + GTK_WIDGET (arrow)->allocation.y + 1, + GTK_WIDGET (arrow)->allocation.width - 2, + GTK_WIDGET (arrow)->allocation.height - 2); + gtk_widget_queue_draw (GTK_WIDGET (arrow)); + } + } +} + + +static gint +gtk_arrow_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkArrow *arrow; + GtkMisc *misc; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + gint extent; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ARROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + arrow = GTK_ARROW (widget); + misc = GTK_MISC (widget); + + width = widget->allocation.width - misc->xpad * 2; + height = widget->allocation.height - misc->ypad * 2; + extent = MIN (width, height); + + x = ((widget->allocation.x + misc->xpad) * (1.0 - misc->xalign) + + (widget->allocation.x + widget->allocation.width - extent - misc->ypad) * misc->xalign); + y = ((widget->allocation.y + misc->ypad) * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height - extent - misc->ypad) * misc->yalign); + + shadow_type = arrow->shadow_type; + + if (widget->state == GTK_STATE_ACTIVE) + { + if (shadow_type == GTK_SHADOW_IN) + shadow_type = GTK_SHADOW_OUT; + else if (shadow_type == GTK_SHADOW_OUT) + shadow_type = GTK_SHADOW_IN; + else if (shadow_type == GTK_SHADOW_ETCHED_IN) + shadow_type = GTK_SHADOW_ETCHED_OUT; + else if (shadow_type == GTK_SHADOW_ETCHED_OUT) + shadow_type = GTK_SHADOW_ETCHED_IN; + } + + gtk_draw_arrow (widget->style, widget->window, + widget->state, shadow_type, arrow->arrow_type, TRUE, + x, y, extent, extent); + } + + return FALSE; +} diff --git a/gtk/gtkarrow.h b/gtk/gtkarrow.h new file mode 100644 index 0000000000..5a2edb0f5d --- /dev/null +++ b/gtk/gtkarrow.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ARROW_H__ +#define __GTK_ARROW_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkmisc.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ARROW(obj) GTK_CHECK_CAST (obj, gtk_arrow_get_type (), GtkArrow) +#define GTK_ARROW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_arrow_get_type (), GtkArrowClass) +#define GTK_IS_ARROW(obj) GTK_CHECK_TYPE (obj, gtk_arrow_get_type ()) + + +typedef struct _GtkArrow GtkArrow; +typedef struct _GtkArrowClass GtkArrowClass; + +struct _GtkArrow +{ + GtkMisc misc; + + gint16 arrow_type; + gint16 shadow_type; +}; + +struct _GtkArrowClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_arrow_get_type (void); +GtkWidget* gtk_arrow_new (GtkArrowType arrow_type, + GtkShadowType shadow_type); +void gtk_arrow_set (GtkArrow *arrow, + GtkArrowType arrow_type, + GtkShadowType shadow_type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ARROW_H__ */ diff --git a/gtk/gtkaspectframe.c b/gtk/gtkaspectframe.c new file mode 100644 index 0000000000..2e4795bcae --- /dev/null +++ b/gtk/gtkaspectframe.c @@ -0,0 +1,336 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkAspectFrame: Ensure that the child window has a specified aspect ratio + * or, if obey_child, has the same aspect ratio as its requested size + * + * Copyright Owen Taylor 4/9/97 + * + * 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 "gtkaspectframe.h" + +static void gtk_aspect_frame_class_init (GtkAspectFrameClass *klass); +static void gtk_aspect_frame_init (GtkAspectFrame *aspect_frame); +static void gtk_aspect_frame_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_aspect_frame_paint (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_aspect_frame_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_aspect_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +#define MAX_RATIO 10000.0 +#define MIN_RATIO 0.0001 + +guint +gtk_aspect_frame_get_type () +{ + static guint aspect_frame_type = 0; + + if (!aspect_frame_type) + { + GtkTypeInfo aspect_frame_info = + { + "GtkAspectFrame", + sizeof (GtkAspectFrame), + sizeof (GtkAspectFrameClass), + (GtkClassInitFunc) gtk_aspect_frame_class_init, + (GtkObjectInitFunc) gtk_aspect_frame_init, + (GtkArgFunc) NULL, + }; + + aspect_frame_type = gtk_type_unique (gtk_frame_get_type (), &aspect_frame_info); + } + + return aspect_frame_type; +} + +static void +gtk_aspect_frame_class_init (GtkAspectFrameClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->draw = gtk_aspect_frame_draw; + widget_class->expose_event = gtk_aspect_frame_expose; + widget_class->size_allocate = gtk_aspect_frame_size_allocate; +} + +static void +gtk_aspect_frame_init (GtkAspectFrame *aspect_frame) +{ + aspect_frame->xalign = 0.5; + aspect_frame->yalign = 0.5; + aspect_frame->ratio = 1.0; + aspect_frame->obey_child = 1; + aspect_frame->center_allocation.x = -1; + aspect_frame->center_allocation.y = -1; + aspect_frame->center_allocation.width = 1; + aspect_frame->center_allocation.height = 1; +} + +GtkWidget* +gtk_aspect_frame_new (const gchar *label, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child) +{ + GtkAspectFrame *aspect_frame; + + aspect_frame = gtk_type_new (gtk_aspect_frame_get_type ()); + + aspect_frame->xalign = CLAMP (xalign, 0.0, 1.0); + aspect_frame->yalign = CLAMP (yalign, 0.0, 1.0); + aspect_frame->ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO); + aspect_frame->obey_child = obey_child; + + gtk_frame_set_label (GTK_FRAME(aspect_frame), label); + + return GTK_WIDGET (aspect_frame); +} + +void +gtk_aspect_frame_set (GtkAspectFrame *aspect_frame, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child) +{ + g_return_if_fail (aspect_frame != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (aspect_frame)); + + xalign = CLAMP (xalign, 0.0, 1.0); + yalign = CLAMP (yalign, 0.0, 1.0); + ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO); + + if ((aspect_frame->xalign != xalign) || + (aspect_frame->yalign != yalign) || + (aspect_frame->ratio != ratio) || + (aspect_frame->obey_child != obey_child)) + { + aspect_frame->xalign = xalign; + aspect_frame->yalign = yalign; + aspect_frame->ratio = ratio; + aspect_frame->obey_child = obey_child; + + gtk_widget_size_allocate (GTK_WIDGET (aspect_frame), &(GTK_WIDGET (aspect_frame)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (aspect_frame)); + } +} + +static void +gtk_aspect_frame_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkFrame *frame; + GtkStateType state; + gint height_extra; + gint label_area_width; + gint x, y; + GtkAllocation *allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + frame = GTK_FRAME (widget); + allocation = >K_ASPECT_FRAME(widget)->center_allocation; + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + height_extra = frame->label_height - widget->style->klass->xthickness; + height_extra = MAX (height_extra, 0); + + x = GTK_CONTAINER (frame)->border_width; + y = GTK_CONTAINER (frame)->border_width; + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, frame->shadow_type, + allocation->x + x, + allocation->y + y + height_extra / 2, + allocation->width - x * 2, + allocation->height - y * 2 - height_extra / 2); + + if (frame->label) + { + label_area_width = (allocation->width + + GTK_CONTAINER (frame)->border_width * 2 - + widget->style->klass->xthickness * 2); + + x = ((label_area_width - frame->label_width) * frame->label_xalign + + GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness); + y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent); + + gdk_window_clear_area (widget->window, + allocation->x + x + 2, + allocation->y + GTK_CONTAINER (frame)->border_width, + frame->label_width - 4, frame->label_height); + gtk_draw_string (widget->style, widget->window, state, + allocation->x + x + 3, + allocation->y + y, + frame->label); + } + } +} + +/* the only modification to the next two routines is to call + gtk_aspect_frame_paint instead of gtk_frame_paint */ + +static void +gtk_aspect_frame_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_aspect_frame_paint (widget, area); + + if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } +} + +static gint +gtk_aspect_frame_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ASPECT_FRAME (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_aspect_frame_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_aspect_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkFrame *frame; + GtkAspectFrame *aspect_frame; + GtkBin *bin; + + GtkAllocation child_allocation; + gint x,y; + gint width,height; + gdouble ratio; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (allocation != NULL); + + aspect_frame = GTK_ASPECT_FRAME (widget); + frame = GTK_FRAME (widget); + bin = GTK_BIN (widget); + + if (GTK_WIDGET_MAPPED (widget) && + ((widget->allocation.x != allocation->x) || + (widget->allocation.y != allocation->y) || + (widget->allocation.width != allocation->width) || + (widget->allocation.height != allocation->height)) && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->allocation = *allocation; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + if (aspect_frame->obey_child) + { + if (bin->child->requisition.height != 0) + { + ratio = (gdouble)bin->child->requisition.width / + bin->child->requisition.height; + if (ratio < MIN_RATIO) ratio = MIN_RATIO; + } + else + if (bin->child->requisition.height != 0) + ratio = MAX_RATIO; + else + ratio = 1.0; + } + else + ratio = aspect_frame->ratio; + + x = (GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->xthickness); + width = allocation->width - x * 2; + + y = (GTK_CONTAINER (frame)->border_width + + MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness)); + height = (allocation->height - y - + GTK_CONTAINER (frame)->border_width - + GTK_WIDGET (frame)->style->klass->ythickness); + + if (ratio * height > width) + { + child_allocation.width = width; + child_allocation.height = width/ratio; + } + else + { + child_allocation.width = ratio*height; + child_allocation.height = height; + } + + child_allocation.x = aspect_frame->xalign * (width - child_allocation.width) + allocation->x + x; + child_allocation.y = aspect_frame->yalign * (height - child_allocation.height) + allocation->y + y; + + aspect_frame->center_allocation.width = child_allocation.width + 2*x; + aspect_frame->center_allocation.x = child_allocation.x - x; + aspect_frame->center_allocation.height = child_allocation.height + y + + GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->ythickness; + aspect_frame->center_allocation.y = child_allocation.y - y; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} diff --git a/gtk/gtkaspectframe.h b/gtk/gtkaspectframe.h new file mode 100644 index 0000000000..07f08a4cce --- /dev/null +++ b/gtk/gtkaspectframe.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ASPECT_FRAME_H__ +#define __GTK_ASPECT_FRAME_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbin.h> +#include <gtk/gtkframe.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ASPECT_FRAME(obj) ((GtkAspectFrame*) obj) +#define GTK_ASPECT_FRAME_CLASS(obj) ((GtkAspectFrameClass*) GTK_OBJECT_CLASS (obj)) +#define GTK_IS_ASPECT_FRAME(obj) (gtk_type_is_a (GTK_WIDGET_TYPE (obj), gtk_aspect_frame_get_type ())) + + +typedef struct _GtkAspectFrame GtkAspectFrame; +typedef struct _GtkAspectFrameClass GtkAspectFrameClass; + +struct _GtkAspectFrame +{ + GtkFrame frame; + + gfloat xalign; + gfloat yalign; + gfloat ratio; + gint obey_child; + + GtkAllocation center_allocation; +}; + +struct _GtkAspectFrameClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_aspect_frame_get_type (void); +GtkWidget* gtk_aspect_frame_new (const gchar *label, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child); +void gtk_aspect_frame_set (GtkAspectFrame *aspect_frame, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ASPECT_FRAME_H__ */ diff --git a/gtk/gtkbbox.c b/gtk/gtkbbox.c new file mode 100644 index 0000000000..818493f9a2 --- /dev/null +++ b/gtk/gtkbbox.c @@ -0,0 +1,228 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkbbox.h" + + +static void gtk_button_box_class_init (GtkButtonBoxClass *klass); +static void gtk_button_box_init (GtkButtonBox *box); + + +static gint default_child_min_width = 85; +static gint default_child_min_height = 27; +static gint default_child_ipad_x = 7; +static gint default_child_ipad_y = 0; + + +guint +gtk_button_box_get_type () +{ + static guint button_box_type = 0; + + if (!button_box_type) + { + GtkTypeInfo button_box_info = + { + "GtkButtonBox", + sizeof (GtkButtonBox), + sizeof (GtkButtonBoxClass), + (GtkClassInitFunc) gtk_button_box_class_init, + (GtkObjectInitFunc) gtk_button_box_init, + (GtkArgFunc) NULL, + }; + + button_box_type = gtk_type_unique (gtk_box_get_type (), &button_box_info); + } + + return button_box_type; +} + +static void +gtk_button_box_class_init (GtkButtonBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; +} + +static void +gtk_button_box_init (GtkButtonBox *button_box) +{ + button_box->spacing = GTK_BUTTONBOX_DEFAULT; + button_box->child_min_width = GTK_BUTTONBOX_DEFAULT; + button_box->child_min_height = GTK_BUTTONBOX_DEFAULT; + button_box->child_ipad_x = GTK_BUTTONBOX_DEFAULT; + button_box->child_ipad_y = GTK_BUTTONBOX_DEFAULT; + button_box->layout_style = GTK_BUTTONBOX_DEFAULT; +} + + +/* set default values for child size and child internal padding */ +/* default spacing is in defined in subclasses */ + +void gtk_button_box_set_child_size_default (gint width, gint height) +{ + default_child_min_width = width; + default_child_min_height = height; +} + +void gtk_button_box_set_child_ipadding_default (gint ipad_x, gint ipad_y) +{ + default_child_ipad_x = ipad_x; + default_child_ipad_y = ipad_y; +} + +/* get default values for child size and child internal padding */ + +void gtk_button_box_get_child_size_default (gint *width, gint *height) +{ + *width = default_child_min_width; + *height = default_child_min_height; +} + +void gtk_button_box_get_child_ipadding_default (gint *ipad_x, gint *ipad_y) +{ + *ipad_x = default_child_ipad_x; + *ipad_y = default_child_ipad_y; +} + +/* set per widget values for spacing, child size and child internal padding */ + +void gtk_button_box_set_spacing (GtkButtonBox *widget, gint spacing) +{ + widget->spacing = spacing; +} + +void gtk_button_box_set_child_size (GtkButtonBox *widget, gint width, gint height) +{ + widget->child_min_width = width; + widget->child_min_height = height; +} + +void gtk_button_box_set_child_ipadding (GtkButtonBox *widget, + gint ipad_x, gint ipad_y) +{ + widget->child_ipad_x = ipad_x; + widget->child_ipad_y = ipad_y; +} + +void gtk_button_box_set_layout (GtkButtonBox *widget, gint layout_style) +{ + widget->layout_style = layout_style; +} + + +/* get per widget values for spacing, child size and child internal padding */ + +gint gtk_button_box_get_spacing (GtkButtonBox *widget) +{ + return widget->spacing; +} + +void gtk_button_box_get_child_size (GtkButtonBox *widget, + gint *width, gint *height) +{ + *width = widget->child_min_width; + *height = widget->child_min_height; +} + +void gtk_button_box_get_child_ipadding (GtkButtonBox *widget, + gint* ipad_x, gint *ipad_y) +{ + *ipad_x = widget->child_ipad_x; + *ipad_y = widget->child_ipad_y; +} + +gint gtk_button_box_get_layout (GtkButtonBox *widget) +{ + return widget->layout_style; +} + + + +/* Ask children how much space they require and round up + to match minimum size and internal padding. + Returns the size each single child should have. */ +void +gtk_button_box_child_requisition (GtkWidget *widget, + int *nvis_children, + int *width, + int *height) +{ + GtkButtonBox *bbox; + GtkBoxChild *child; + GList *children; + gint nchildren; + gint needed_width; + gint needed_height; + GtkRequisition child_requisition; + gint ipad_w; + gint ipad_h; + gint width_default; + gint height_default; + gint ipad_x_default; + gint ipad_y_default; + + gint child_min_width; + gint child_min_height; + gint ipad_x; + gint ipad_y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON_BOX (widget)); + + bbox = GTK_BUTTON_BOX (widget); + + gtk_button_box_get_child_size_default (&width_default, &height_default); + gtk_button_box_get_child_ipadding_default (&ipad_x_default, &ipad_y_default); + + child_min_width = bbox->child_min_width != GTK_BUTTONBOX_DEFAULT + ? bbox->child_min_width : width_default; + child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT + ? bbox->child_min_height : height_default; + ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT + ? bbox->child_ipad_x : ipad_x_default; + ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT + ? bbox->child_ipad_y : ipad_y_default; + + nchildren = 0; + children = GTK_BOX(bbox)->children; + needed_width = child_min_width; + needed_height = child_min_height; + ipad_w = ipad_x * 2; + ipad_h = ipad_y * 2; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + nchildren += 1; + gtk_widget_size_request (child->widget, &child_requisition); + if (child_requisition.width + ipad_w > needed_width) + needed_width = child_requisition.width + ipad_w; + if (child_requisition.height + ipad_h > needed_height) + needed_height = child_requisition.height + ipad_h; + } + } + + *nvis_children = nchildren; + *width = needed_width; + *height = needed_height; +} diff --git a/gtk/gtkbbox.h b/gtk/gtkbbox.h new file mode 100644 index 0000000000..816f1f0c24 --- /dev/null +++ b/gtk/gtkbbox.h @@ -0,0 +1,93 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_BUTTON_BOX_H__ +#define __GTK_BUTTON_BOX_H__ + +#include "gtkbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BUTTON_BOX(obj) GTK_CHECK_CAST (obj, gtk_button_box_get_type (), GtkButtonBox) +#define GTK_BUTTON_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_button_box_get_type (), GtkButtonBoxClass) +#define GTK_IS_BUTTON_BOX(obj) GTK_CHECK_TYPE (obj, gtk_button_box_get_type ()) + +#define GTK_BUTTONBOX_DEFAULT -1 +#define GTK_BUTTONBOX_SPREAD 1 +#define GTK_BUTTONBOX_EDGE 2 +#define GTK_BUTTONBOX_START 3 +#define GTK_BUTTONBOX_END 4 + +typedef struct _GtkButtonBox GtkButtonBox; +typedef struct _GtkButtonBoxClass GtkButtonBoxClass; + +struct _GtkButtonBox +{ + GtkBox box; + gint spacing; + gint child_min_width; + gint child_min_height; + gint child_ipad_x; + gint child_ipad_y; + gint layout_style; +}; + +struct _GtkButtonBoxClass +{ + GtkBoxClass parent_class; +}; + + +guint gtk_button_box_get_type (void); + +void gtk_button_box_get_child_size_default (gint *min_width, gint *min_height); +void gtk_button_box_get_child_ipadding_default (gint *ipad_x, gint *ipad_y); + +void gtk_button_box_set_child_size_default (gint min_width, gint min_height); +void gtk_button_box_set_child_ipadding_default (gint ipad_x, gint ipad_y); + +gint gtk_button_box_get_spacing (GtkButtonBox *widget); +gint gtk_button_box_get_layout (GtkButtonBox *widget); +void gtk_button_box_get_child_size (GtkButtonBox *widget, + gint *min_width, gint *min_height); +void gtk_button_box_get_child_ipadding (GtkButtonBox *widget, gint *ipad_x, gint *ipad_y); + +void gtk_button_box_set_spacing (GtkButtonBox *widget, gint spacing); +void gtk_button_box_set_layout (GtkButtonBox *widget, gint layout_style); +void gtk_button_box_set_child_size (GtkButtonBox *widget, + gint min_width, gint min_height); +void gtk_button_box_set_child_ipadding (GtkButtonBox *widget, gint ipad_x, gint ipad_y); + + +/* Internal method - do not use. */ +void gtk_button_box_child_requisition (GtkWidget *widget, + int *nvis_children, + int *width, + int *height); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BUTTON_BOX_H__ */ + + diff --git a/gtk/gtkbin.c b/gtk/gtkbin.c new file mode 100644 index 0000000000..4cb7efcc19 --- /dev/null +++ b/gtk/gtkbin.c @@ -0,0 +1,286 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkbin.h" + + +static void gtk_bin_class_init (GtkBinClass *klass); +static void gtk_bin_init (GtkBin *bin); +static void gtk_bin_destroy (GtkObject *object); +static void gtk_bin_map (GtkWidget *widget); +static void gtk_bin_unmap (GtkWidget *widget); +static void gtk_bin_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_bin_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_bin_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_bin_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_bin_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_bin_get_type () +{ + static guint bin_type = 0; + + if (!bin_type) + { + GtkTypeInfo bin_info = + { + "GtkBin", + sizeof (GtkBin), + sizeof (GtkBinClass), + (GtkClassInitFunc) gtk_bin_class_init, + (GtkObjectInitFunc) gtk_bin_init, + (GtkArgFunc) NULL, + }; + + bin_type = gtk_type_unique (gtk_container_get_type (), &bin_info); + } + + return bin_type; +} + +static void +gtk_bin_class_init (GtkBinClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_bin_destroy; + + widget_class->map = gtk_bin_map; + widget_class->unmap = gtk_bin_unmap; + widget_class->draw = gtk_bin_draw; + widget_class->expose_event = gtk_bin_expose; + + container_class->add = gtk_bin_add; + container_class->remove = gtk_bin_remove; + container_class->foreach = gtk_bin_foreach; +} + +static void +gtk_bin_init (GtkBin *bin) +{ + GTK_WIDGET_SET_FLAGS (bin, GTK_NO_WINDOW); + + bin->child = NULL; +} + + +static void +gtk_bin_destroy (GtkObject *object) +{ + GtkBin *bin; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_BIN (object)); + + bin = GTK_BIN (object); + + if (bin->child) + { + bin->child->parent = NULL; + gtk_object_unref (GTK_OBJECT (bin->child)); + gtk_widget_destroy (bin->child); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_bin_map (GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BIN (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + bin = GTK_BIN (widget); + + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_show (widget->window); + else + gtk_widget_queue_draw (widget); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); +} + +static void +gtk_bin_unmap (GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BIN (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + bin = GTK_BIN (widget); + + if (GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + else + gdk_window_hide (widget->window); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_unmap (bin->child); +} + +static void +gtk_bin_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BIN (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + bin = GTK_BIN (widget); + + if (bin->child && + gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } +} + +static gint +gtk_bin_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BIN (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + + +static void +gtk_bin_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BIN (container)); + g_return_if_fail (widget != NULL); + + bin = GTK_BIN (container); + + if (!bin->child) + { + gtk_widget_set_parent (widget, GTK_WIDGET (container)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + bin->child = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (widget); + } +} + +static void +gtk_bin_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BIN (container)); + g_return_if_fail (widget != NULL); + + bin = GTK_BIN (container); + + if (bin->child == widget) + { + gtk_widget_unparent (widget); + + bin->child = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +gtk_bin_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkBin *bin; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BIN (container)); + g_return_if_fail (callback != NULL); + + bin = GTK_BIN (container); + + if (bin->child) + (* callback) (bin->child, callback_data); +} diff --git a/gtk/gtkbin.h b/gtk/gtkbin.h new file mode 100644 index 0000000000..c8676ab849 --- /dev/null +++ b/gtk/gtkbin.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_BIN_H__ +#define __GTK_BIN_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BIN(obj) GTK_CHECK_CAST (obj, gtk_bin_get_type (), GtkBin) +#define GTK_BIN_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_bin_get_type (), GtkBinClass) +#define GTK_IS_BIN(obj) GTK_CHECK_TYPE (obj, gtk_bin_get_type ()) + + +typedef struct _GtkBin GtkBin; +typedef struct _GtkBinClass GtkBinClass; + +struct _GtkBin +{ + GtkContainer container; + + GtkWidget *child; +}; + +struct _GtkBinClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_bin_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BIN_H__ */ diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c new file mode 100644 index 0000000000..dfb2fed087 --- /dev/null +++ b/gtk/gtkbox.c @@ -0,0 +1,453 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkbox.h" + + +static void gtk_box_class_init (GtkBoxClass *klass); +static void gtk_box_init (GtkBox *box); +static void gtk_box_destroy (GtkObject *object); +static void gtk_box_map (GtkWidget *widget); +static void gtk_box_unmap (GtkWidget *widget); +static void gtk_box_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_box_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_box_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_box_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_box_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_box_get_type () +{ + static guint box_type = 0; + + if (!box_type) + { + GtkTypeInfo box_info = + { + "GtkBox", + sizeof (GtkBox), + sizeof (GtkBoxClass), + (GtkClassInitFunc) gtk_box_class_init, + (GtkObjectInitFunc) gtk_box_init, + (GtkArgFunc) NULL, + }; + + box_type = gtk_type_unique (gtk_container_get_type (), &box_info); + } + + return box_type; +} + +static void +gtk_box_class_init (GtkBoxClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_box_destroy; + + widget_class->map = gtk_box_map; + widget_class->unmap = gtk_box_unmap; + widget_class->draw = gtk_box_draw; + widget_class->expose_event = gtk_box_expose; + + container_class->add = gtk_box_add; + container_class->remove = gtk_box_remove; + container_class->foreach = gtk_box_foreach; +} + +static void +gtk_box_init (GtkBox *box) +{ + GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW | GTK_BASIC); + + box->children = NULL; + box->spacing = 0; + box->homogeneous = FALSE; +} + +void +gtk_box_pack_start (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding) +{ + GtkBoxChild *child_info; + + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + child_info = g_new (GtkBoxChild, 1); + child_info->widget = child; + child_info->padding = padding; + child_info->expand = expand ? TRUE : FALSE; + child_info->fill = fill ? TRUE : FALSE; + child_info->pack = GTK_PACK_START; + + box->children = g_list_append (box->children, child_info); + + gtk_widget_set_parent (child, GTK_WIDGET (box)); + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box))) + { + if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box)) + gtk_widget_queue_resize (child); +} + +void +gtk_box_pack_end (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding) +{ + GtkBoxChild *child_info; + + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + child_info = g_new (GtkBoxChild, 1); + child_info->widget = child; + child_info->padding = padding; + child_info->expand = expand ? TRUE : FALSE; + child_info->fill = fill ? TRUE : FALSE; + child_info->pack = GTK_PACK_END; + + box->children = g_list_append (box->children, child_info); + + gtk_widget_set_parent (child, GTK_WIDGET (box)); + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box))) + { + if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box)) + gtk_widget_queue_resize (child); +} + +void +gtk_box_pack_start_defaults (GtkBox *box, + GtkWidget *child) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + gtk_box_pack_start (box, child, TRUE, TRUE, 0); +} + +void +gtk_box_pack_end_defaults (GtkBox *box, + GtkWidget *child) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + gtk_box_pack_end (box, child, TRUE, TRUE, 0); +} + +void +gtk_box_set_homogeneous (GtkBox *box, + gint homogeneous) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + + if ((homogeneous ? TRUE : FALSE) != box->homogeneous) + { + box->homogeneous = homogeneous ? TRUE : FALSE; + gtk_widget_queue_resize (GTK_WIDGET (box)); + } +} + +void +gtk_box_set_spacing (GtkBox *box, + gint spacing) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + + if (spacing != box->spacing) + { + box->spacing = spacing; + gtk_widget_queue_resize (GTK_WIDGET (box)); + } +} + + +static void +gtk_box_destroy (GtkObject *object) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_BOX (object)); + + box = GTK_BOX (object); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + child->widget->parent = NULL; + gtk_object_unref (GTK_OBJECT (child->widget)); + gtk_widget_destroy (child->widget); + g_free (child); + } + + g_list_free (box->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_box_map (GtkWidget *widget) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BOX (widget)); + + box = GTK_BOX (widget); + GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); + } +} + +static void +gtk_box_unmap (GtkWidget *widget) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BOX (widget)); + + box = GTK_BOX (widget); + GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); + } +} + +static void +gtk_box_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBox *box; + GtkBoxChild *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BOX (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + box = GTK_BOX (widget); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); + } + } +} + +static gint +gtk_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBox *box; + GtkBoxChild *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + box = GTK_BOX (widget); + + child_event = *event; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static void +gtk_box_add (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BOX (container)); + g_return_if_fail (widget != NULL); + + gtk_box_pack_start_defaults (GTK_BOX (container), widget); +} + +static void +gtk_box_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BOX (container)); + g_return_if_fail (widget != NULL); + + box = GTK_BOX (container); + + children = box->children; + while (children) + { + child = children->data; + + if (child->widget == widget) + { + gtk_widget_unparent (widget); + + box->children = g_list_remove_link (box->children, children); + g_list_free (children); + g_free (child); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + children = children->next; + } +} + +static void +gtk_box_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BOX (container)); + g_return_if_fail (callback != NULL); + + box = GTK_BOX (container); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (child->pack == GTK_PACK_START) + (* callback) (child->widget, callback_data); + } + + children = g_list_last (box->children); + while (children) + { + child = children->data; + children = children->prev; + + if (child->pack == GTK_PACK_END) + (* callback) (child->widget, callback_data); + } +} diff --git a/gtk/gtkbox.h b/gtk/gtkbox.h new file mode 100644 index 0000000000..5ff0dd22af --- /dev/null +++ b/gtk/gtkbox.h @@ -0,0 +1,90 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_BOX_H__ +#define __GTK_BOX_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BOX(obj) GTK_CHECK_CAST (obj, gtk_box_get_type (), GtkBox) +#define GTK_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_box_get_type (), GtkBoxClass) +#define GTK_IS_BOX(obj) GTK_CHECK_TYPE (obj, gtk_box_get_type ()) + + +typedef struct _GtkBox GtkBox; +typedef struct _GtkBoxClass GtkBoxClass; +typedef struct _GtkBoxChild GtkBoxChild; + +struct _GtkBox +{ + GtkContainer container; + + GList *children; + gint16 spacing; + guint homogeneous : 1; +}; + +struct _GtkBoxClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkBoxChild +{ + GtkWidget *widget; + guint16 padding; + guint expand : 1; + guint fill : 1; + guint pack : 1; +}; + + +guint gtk_box_get_type (void); +void gtk_box_pack_start (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding); +void gtk_box_pack_end (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding); +void gtk_box_pack_start_defaults (GtkBox *box, + GtkWidget *widget); +void gtk_box_pack_end_defaults (GtkBox *box, + GtkWidget *widget); +void gtk_box_set_homogeneous (GtkBox *box, + gint homogeneous); +void gtk_box_set_spacing (GtkBox *box, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BOX_H__ */ diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c new file mode 100644 index 0000000000..18afb177ac --- /dev/null +++ b/gtk/gtkbutton.c @@ -0,0 +1,915 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkbutton.h" +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtksignal.h" + + +#define CHILD_SPACING 1 +#define DEFAULT_LEFT_POS 4 +#define DEFAULT_TOP_POS 4 +#define DEFAULT_SPACING 7 + + +enum { + PRESSED, + RELEASED, + CLICKED, + ENTER, + LEAVE, + LAST_SIGNAL +}; + + +static void gtk_button_class_init (GtkButtonClass *klass); +static void gtk_button_init (GtkButton *button); +static void gtk_button_arg (GtkButton *button, + GtkArg *arg); +static void gtk_button_destroy (GtkObject *object); +static void gtk_button_map (GtkWidget *widget); +static void gtk_button_unmap (GtkWidget *widget); +static void gtk_button_realize (GtkWidget *widget); +static void gtk_button_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_button_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_button_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_button_draw_focus (GtkWidget *widget); +static void gtk_button_draw_default (GtkWidget *widget); +static gint gtk_button_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_button_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_button_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_button_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_button_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_button_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_button_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_button_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_button_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_button_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_real_button_pressed (GtkButton *button); +static void gtk_real_button_released (GtkButton *button); +static void gtk_real_button_enter (GtkButton *button); +static void gtk_real_button_leave (GtkButton *button); + + +static GtkContainerClass *parent_class; +static gint button_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_button_get_type () +{ + static guint button_type = 0; + + if (!button_type) + { + GtkTypeInfo button_info = + { + "GtkButton", + sizeof (GtkButton), + sizeof (GtkButtonClass), + (GtkClassInitFunc) gtk_button_class_init, + (GtkObjectInitFunc) gtk_button_init, + (GtkArgFunc) gtk_button_arg, + }; + + button_type = gtk_type_unique (gtk_container_get_type (), &button_info); + } + + return button_type; +} + +static void +gtk_button_class_init (GtkButtonClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + gtk_object_add_arg_type ("GtkButton::label", GTK_TYPE_STRING); + + button_signals[PRESSED] = + gtk_signal_new ("pressed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, pressed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[RELEASED] = + gtk_signal_new ("released", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, released), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[CLICKED] = + gtk_signal_new ("clicked", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, clicked), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[ENTER] = + gtk_signal_new ("enter", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, enter), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[LEAVE] = + gtk_signal_new ("leave", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, leave), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, button_signals, LAST_SIGNAL); + + object_class->destroy = gtk_button_destroy; + + widget_class->activate_signal = button_signals[CLICKED]; + widget_class->map = gtk_button_map; + widget_class->unmap = gtk_button_unmap; + widget_class->realize = gtk_button_realize; + widget_class->draw = gtk_button_draw; + widget_class->draw_focus = gtk_button_draw_focus; + widget_class->draw_default = gtk_button_draw_default; + widget_class->size_request = gtk_button_size_request; + widget_class->size_allocate = gtk_button_size_allocate; + widget_class->expose_event = gtk_button_expose; + widget_class->button_press_event = gtk_button_button_press; + widget_class->button_release_event = gtk_button_button_release; + widget_class->enter_notify_event = gtk_button_enter_notify; + widget_class->leave_notify_event = gtk_button_leave_notify; + widget_class->focus_in_event = gtk_button_focus_in; + widget_class->focus_out_event = gtk_button_focus_out; + + container_class->add = gtk_button_add; + container_class->remove = gtk_button_remove; + container_class->foreach = gtk_button_foreach; + + klass->pressed = gtk_real_button_pressed; + klass->released = gtk_real_button_released; + klass->clicked = NULL; + klass->enter = gtk_real_button_enter; + klass->leave = gtk_real_button_leave; +} + +static void +gtk_button_init (GtkButton *button) +{ + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS); + + button->child = NULL; + button->in_button = FALSE; + button->button_down = FALSE; +} + +static void +gtk_button_arg (GtkButton *button, + GtkArg *arg) +{ + if (strcmp (arg->name, "label") == 0) + { + GtkWidget *label; + + gtk_container_disable_resize (GTK_CONTAINER (button)); + + if (button->child) + gtk_widget_destroy (button->child); + + label = gtk_label_new (GTK_VALUE_STRING(*arg)); + gtk_widget_show (label); + + gtk_container_add (GTK_CONTAINER (button), label); + gtk_container_enable_resize (GTK_CONTAINER (button)); + } +} + +GtkWidget* +gtk_button_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_button_get_type ())); +} + +GtkWidget* +gtk_button_new_with_label (const gchar *label) +{ + GtkWidget *button; + GtkWidget *label_widget; + + button = gtk_button_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5); + + gtk_container_add (GTK_CONTAINER (button), label_widget); + gtk_widget_show (label_widget); + + return button; +} + +void +gtk_button_pressed (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[PRESSED]); +} + +void +gtk_button_released (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[RELEASED]); +} + +void +gtk_button_clicked (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]); +} + +void +gtk_button_enter (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[ENTER]); +} + +void +gtk_button_leave (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[LEAVE]); +} + +static void +gtk_button_destroy (GtkObject *object) +{ + GtkButton *button; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_BUTTON (object)); + + button = GTK_BUTTON (object); + + if (button->child) + { + button->child->parent = NULL; + gtk_object_unref (GTK_OBJECT (button->child)); + gtk_widget_destroy (button->child); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_button_map (GtkWidget *widget) +{ + GtkButton *button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + button = GTK_BUTTON (widget); + + if (button->child && + GTK_WIDGET_VISIBLE (button->child) && + !GTK_WIDGET_MAPPED (button->child)) + gtk_widget_map (button->child); +} + +static void +gtk_button_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_button_realize (GtkWidget *widget) +{ + GtkButton *button; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + button = GTK_BUTTON (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, button); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_button_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkButton *button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + g_return_if_fail (requisition != NULL); + + button = GTK_BUTTON (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING + + GTK_WIDGET (widget)->style->klass->xthickness) * 2; + requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING + + GTK_WIDGET (widget)->style->klass->ythickness) * 2; + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + requisition->width += (GTK_WIDGET (widget)->style->klass->xthickness * 2 + + DEFAULT_SPACING); + requisition->height += (GTK_WIDGET (widget)->style->klass->ythickness * 2 + + DEFAULT_SPACING); + } + + if (button->child && GTK_WIDGET_VISIBLE (button->child)) + { + gtk_widget_size_request (button->child, &button->child->requisition); + + requisition->width += button->child->requisition.width; + requisition->height += button->child->requisition.height; + } +} + +static void +gtk_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkButton *button; + GtkAllocation child_allocation; + gint border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + border_width = GTK_CONTAINER (widget)->border_width; + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + widget->allocation.x + border_width, + widget->allocation.y + border_width, + widget->allocation.width - border_width * 2, + widget->allocation.height - border_width * 2); + + button = GTK_BUTTON (widget); + + if (button->child && GTK_WIDGET_VISIBLE (button->child)) + { + child_allocation.x = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->xthickness); + child_allocation.y = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->ythickness); + + child_allocation.width = widget->allocation.width - child_allocation.x * 2 - + border_width * 2; + child_allocation.height = widget->allocation.height - child_allocation.y * 2 - + border_width * 2; + + if (GTK_WIDGET_CAN_DEFAULT (button)) + { + child_allocation.x += (GTK_WIDGET (widget)->style->klass->xthickness + + DEFAULT_LEFT_POS); + child_allocation.y += (GTK_WIDGET (widget)->style->klass->ythickness + + DEFAULT_TOP_POS); + child_allocation.width -= (GTK_WIDGET (widget)->style->klass->xthickness * 2 + + DEFAULT_SPACING); + child_allocation.height -= (GTK_WIDGET (widget)->style->klass->xthickness * 2 + + DEFAULT_SPACING); + } + + gtk_widget_size_allocate (button->child, &child_allocation); + } +} + +static void +gtk_button_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GdkRectangle restrict_area; + GdkRectangle new_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + restrict_area.x = GTK_WIDGET (widget)->style->klass->xthickness; + restrict_area.y = GTK_WIDGET (widget)->style->klass->ythickness; + restrict_area.width = (GTK_WIDGET (widget)->allocation.width - restrict_area.x * 2 - + GTK_CONTAINER (widget)->border_width * 2); + restrict_area.height = (GTK_WIDGET (widget)->allocation.height - restrict_area.y * 2 - + GTK_CONTAINER (widget)->border_width * 2); + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + restrict_area.x += DEFAULT_LEFT_POS; + restrict_area.y += DEFAULT_TOP_POS; + restrict_area.width -= DEFAULT_SPACING; + restrict_area.height -= DEFAULT_SPACING; + } + + if (gdk_rectangle_intersect (area, &restrict_area, &new_area)) + { + gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget)); + gdk_window_clear_area (widget->window, + new_area.x, new_area.y, + new_area.width, new_area.height); + } + } +} + +static void +gtk_button_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkButton *button; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + button = GTK_BUTTON (widget); + + gtk_button_paint (widget, area); + + if (button->child && gtk_widget_intersect (button->child, area, &child_area)) + gtk_widget_draw (button->child, &child_area); + + gtk_widget_draw_default (widget); + gtk_widget_draw_focus (widget); + } +} + +static void +gtk_button_draw_focus (GtkWidget *widget) +{ + GtkButton *button; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + button = GTK_BUTTON (widget); + + x = 0; + y = 0; + width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2; + height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2; + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + x += widget->style->klass->xthickness; + y += widget->style->klass->ythickness; + width -= 2 * x + DEFAULT_SPACING; + height -= 2 * y + DEFAULT_SPACING; + x += DEFAULT_LEFT_POS; + y += DEFAULT_TOP_POS; + } + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + else + { + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 1, y + 1, width - 4, height - 4); + else + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 2, y + 2, width - 5, height - 5); + } + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x -= 1; + y -= 1; + width += 2; + height += 2; + + gdk_draw_rectangle (widget->window, + widget->style->black_gc, FALSE, + x, y, width - 1, height - 1); + } + } +} + +static void +gtk_button_draw_default (GtkWidget *widget) +{ + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + x = 0; + y = 0; + width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2; + height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2; + + if (GTK_WIDGET_HAS_DEFAULT (widget)) + { + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + } + else + { + gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL], + FALSE, x, y, width - 1, height - 1); + gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL], + FALSE, x + 1, y + 1, width - 3, height - 3); + } + } +} + +static gint +gtk_button_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkButton *button; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + button = GTK_BUTTON (widget); + + gtk_button_paint (widget, &event->area); + + child_event = *event; + if (button->child && GTK_WIDGET_NO_WINDOW (button->child) && + gtk_widget_intersect (button->child, &event->area, &child_event.area)) + gtk_widget_event (button->child, (GdkEvent*) &child_event); + + gtk_widget_draw_default (widget); + gtk_widget_draw_focus (widget); + } + + return FALSE; +} + +static gint +gtk_button_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkButton *button; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->type == GDK_BUTTON_PRESS) + { + button = GTK_BUTTON (widget); + + if (GTK_WIDGET_CAN_DEFAULT (widget) && (event->button == 1)) + gtk_widget_grab_default (widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if (event->button == 1) + { + gtk_grab_add (GTK_WIDGET (button)); + gtk_button_pressed (button); + } + } + + return TRUE; +} + +static gint +gtk_button_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkButton *button; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->button == 1) + { + button = GTK_BUTTON (widget); + gtk_grab_remove (GTK_WIDGET (button)); + gtk_button_released (button); + } + + return TRUE; +} + +static gint +gtk_button_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkButton *button; + GtkWidget *event_widget; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + button = GTK_BUTTON (widget); + event_widget = gtk_get_event_widget ((GdkEvent*) event); + + if ((event_widget == widget) && + (event->detail != GDK_NOTIFY_INFERIOR)) + { + button->in_button = TRUE; + gtk_button_enter (button); + } + + return FALSE; +} + +static gint +gtk_button_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkButton *button; + GtkWidget *event_widget; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + button = GTK_BUTTON (widget); + event_widget = gtk_get_event_widget ((GdkEvent*) event); + + if ((event_widget == widget) && + (event->detail != GDK_NOTIFY_INFERIOR)) + { + button->in_button = FALSE; + gtk_button_leave (button); + } + + return FALSE; +} + +static gint +gtk_button_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_button_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static void +gtk_button_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkButton *button; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BUTTON (container)); + g_return_if_fail (widget != NULL); + g_return_if_fail (gtk_widget_basic (widget)); + + button = GTK_BUTTON (container); + + if (!button->child) + { + gtk_widget_set_parent (widget, GTK_WIDGET (container)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + button->child = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (widget); + } +} + +static void +gtk_button_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkButton *button; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BUTTON (container)); + + button = GTK_BUTTON (container); + + if (button->child == widget) + { + gtk_widget_unparent (widget); + + button->child = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +gtk_button_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkButton *button; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BUTTON (container)); + g_return_if_fail (callback != NULL); + + button = GTK_BUTTON (container); + + if (button->child) + (* callback) (button->child, callback_data); +} + +static void +gtk_real_button_pressed (GtkButton *button) +{ + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + button->button_down = TRUE; + + new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_real_button_released (GtkButton *button) +{ + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + if (button->button_down) + { + button->button_down = FALSE; + + if (button->in_button) + gtk_button_clicked (button); + + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } + } +} + +static void +gtk_real_button_enter (GtkButton *button) +{ + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_real_button_leave (GtkButton *button) +{ + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL) + { + gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} diff --git a/gtk/gtkbutton.h b/gtk/gtkbutton.h new file mode 100644 index 0000000000..ec72c99f78 --- /dev/null +++ b/gtk/gtkbutton.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_BUTTON_H__ +#define __GTK_BUTTON_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_button_get_type (), GtkButton) +#define GTK_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_button_get_type (), GtkButtonClass) +#define GTK_IS_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_button_get_type ()) + + +typedef struct _GtkButton GtkButton; +typedef struct _GtkButtonClass GtkButtonClass; + +struct _GtkButton +{ + GtkContainer container; + + GtkWidget *child; + + guint in_button : 1; + guint button_down : 1; +}; + +struct _GtkButtonClass +{ + GtkContainerClass parent_class; + + void (* pressed) (GtkButton *button); + void (* released) (GtkButton *button); + void (* clicked) (GtkButton *button); + void (* enter) (GtkButton *button); + void (* leave) (GtkButton *button); +}; + + +guint gtk_button_get_type (void); +GtkWidget* gtk_button_new (void); +GtkWidget* gtk_button_new_with_label (const gchar *label); +void gtk_button_pressed (GtkButton *button); +void gtk_button_released (GtkButton *button); +void gtk_button_clicked (GtkButton *button); +void gtk_button_enter (GtkButton *button); +void gtk_button_leave (GtkButton *button); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BUTTON_H__ */ diff --git a/gtk/gtkcheckbutton.c b/gtk/gtkcheckbutton.c new file mode 100644 index 0000000000..d7f72ce1c2 --- /dev/null +++ b/gtk/gtkcheckbutton.c @@ -0,0 +1,362 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkcheckbutton.h" +#include "gtklabel.h" + + +#define INDICATOR_SIZE 10 +#define INDICATOR_SPACING 2 + +#define CHECK_BUTTON_CLASS(w) GTK_CHECK_BUTTON_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_check_button_class_init (GtkCheckButtonClass *klass); +static void gtk_check_button_init (GtkCheckButton *check_button); +static void gtk_check_button_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_check_button_draw_focus (GtkWidget *widget); +static void gtk_check_button_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_check_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_check_button_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area); +static void gtk_real_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area); + + +static GtkToggleButtonClass *parent_class = NULL; + + +guint +gtk_check_button_get_type () +{ + static guint check_button_type = 0; + + if (!check_button_type) + { + GtkTypeInfo check_button_info = + { + "GtkCheckButton", + sizeof (GtkCheckButton), + sizeof (GtkCheckButtonClass), + (GtkClassInitFunc) gtk_check_button_class_init, + (GtkObjectInitFunc) gtk_check_button_init, + (GtkArgFunc) NULL, + }; + + check_button_type = gtk_type_unique (gtk_toggle_button_get_type (), &check_button_info); + } + + return check_button_type; +} + +static void +gtk_check_button_class_init (GtkCheckButtonClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + parent_class = gtk_type_class (gtk_toggle_button_get_type ()); + + widget_class->draw = gtk_check_button_draw; + widget_class->draw_focus = gtk_check_button_draw_focus; + widget_class->size_request = gtk_check_button_size_request; + widget_class->size_allocate = gtk_check_button_size_allocate; + widget_class->expose_event = gtk_check_button_expose; + + class->indicator_size = INDICATOR_SIZE; + class->indicator_spacing = INDICATOR_SPACING; + class->draw_indicator = gtk_real_check_button_draw_indicator; +} + +static void +gtk_check_button_init (GtkCheckButton *check_button) +{ + check_button->toggle_button.draw_indicator = TRUE; +} + +GtkWidget* +gtk_check_button_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_check_button_get_type ())); +} + + +GtkWidget* +gtk_check_button_new_with_label (const gchar *label) +{ + GtkWidget *check_button; + GtkWidget *label_widget; + + check_button = gtk_check_button_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (check_button), label_widget); + gtk_widget_show (label_widget); + + return check_button; +} + +static void +gtk_check_button_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkButton *button; + GtkCheckButton *check_button; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + check_button = GTK_CHECK_BUTTON (widget); + + if (check_button->toggle_button.draw_indicator) + { + button = GTK_BUTTON (widget); + + gtk_check_button_draw_indicator (check_button, area); + + if (button->child && GTK_WIDGET_NO_WINDOW (button->child) && + gtk_widget_intersect (button->child, area, &child_area)) + gtk_widget_draw (button->child, &child_area); + + gtk_widget_draw_focus (widget); + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->draw) + (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area); + } + } +} + +static void +gtk_check_button_draw_focus (GtkWidget *widget) +{ + GtkCheckButton *check_button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + check_button = GTK_CHECK_BUTTON (widget); + if (check_button->toggle_button.draw_indicator) + { + if (GTK_WIDGET_HAS_FOCUS (widget)) + gdk_draw_rectangle (widget->window, + widget->style->black_gc, FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + else + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_STATE_NORMAL], FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->draw_focus) + (* GTK_WIDGET_CLASS (parent_class)->draw_focus) (widget); + } + } +} + +static void +gtk_check_button_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkCheckButton *check_button; + GtkButton *button; + gint temp; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + g_return_if_fail (requisition != NULL); + + check_button = GTK_CHECK_BUTTON (widget); + + if (GTK_WIDGET_CLASS (parent_class)->size_request) + (* GTK_WIDGET_CLASS (parent_class)->size_request) (widget, requisition); + + if (check_button->toggle_button.draw_indicator) + { + button = GTK_BUTTON (widget); + + requisition->width += (CHECK_BUTTON_CLASS (widget)->indicator_size + + CHECK_BUTTON_CLASS (widget)->indicator_spacing * 3 + 2); + + temp = (CHECK_BUTTON_CLASS (widget)->indicator_size + + CHECK_BUTTON_CLASS (widget)->indicator_spacing * 2); + requisition->height = MAX (requisition->height, temp) + 2; + } +} + +static void +gtk_check_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkCheckButton *check_button; + GtkButton *button; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + g_return_if_fail (allocation != NULL); + + check_button = GTK_CHECK_BUTTON (widget); + if (check_button->toggle_button.draw_indicator) + { + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + button = GTK_BUTTON (widget); + + if (button->child && GTK_WIDGET_VISIBLE (button->child)) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + CHECK_BUTTON_CLASS (widget)->indicator_size + + CHECK_BUTTON_CLASS (widget)->indicator_spacing * 3 + 1); + child_allocation.y = GTK_CONTAINER (widget)->border_width + 1; + child_allocation.width = (allocation->width - child_allocation.x - + GTK_CONTAINER (widget)->border_width - 1); + child_allocation.height = allocation->height - child_allocation.y * 2; + + gtk_widget_size_allocate (button->child, &child_allocation); + } + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->size_allocate) + (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); + } +} + +static gint +gtk_check_button_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkButton *button; + GtkCheckButton *check_button; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CHECK_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + check_button = GTK_CHECK_BUTTON (widget); + + if (check_button->toggle_button.draw_indicator) + { + button = GTK_BUTTON (widget); + + gtk_check_button_draw_indicator (check_button, &event->area); + + child_event = *event; + if (button->child && GTK_WIDGET_NO_WINDOW (button->child) && + gtk_widget_intersect (button->child, &event->area, &child_event.area)) + gtk_widget_event (button->child, (GdkEvent*) &child_event); + + gtk_widget_draw_focus (widget); + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->expose_event) + (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); + } + } + + return FALSE; +} + + +static void +gtk_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area) +{ + GtkCheckButtonClass *class; + + g_return_if_fail (check_button != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button)); + g_return_if_fail (CHECK_BUTTON_CLASS (check_button) != NULL); + + class = CHECK_BUTTON_CLASS (check_button); + + if (class->draw_indicator) + (* class->draw_indicator) (check_button, area); +} + +static void +gtk_real_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkToggleButton *toggle_button; + GtkStateType state_type; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (check_button != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button)); + + if (GTK_WIDGET_DRAWABLE (check_button)) + { + widget = GTK_WIDGET (check_button); + toggle_button = GTK_TOGGLE_BUTTON (check_button); + + state_type = GTK_WIDGET_STATE (widget); + if ((state_type != GTK_STATE_NORMAL) && + (state_type != GTK_STATE_PRELIGHT)) + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (widget->style, widget->window, state_type); + gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); + + x = CHECK_BUTTON_CLASS (widget)->indicator_spacing + GTK_CONTAINER (widget)->border_width; + y = (widget->allocation.height - CHECK_BUTTON_CLASS (widget)->indicator_size) / 2; + width = CHECK_BUTTON_CLASS (widget)->indicator_size; + height = CHECK_BUTTON_CLASS (widget)->indicator_size; + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) && toggle_button->active) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], + TRUE, x + 1, y + 1, width, height); + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x + 1, y + 1, width, height); + } +} diff --git a/gtk/gtkcheckbutton.h b/gtk/gtkcheckbutton.h new file mode 100644 index 0000000000..8994db563e --- /dev/null +++ b/gtk/gtkcheckbutton.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_CHECK_BUTTON_H__ +#define __GTK_CHECK_BUTTON_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtktogglebutton.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CHECK_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_check_button_get_type (), GtkCheckButton) +#define GTK_CHECK_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_check_button_get_type (), GtkCheckButtonClass) +#define GTK_IS_CHECK_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_check_button_get_type ()) + + +typedef struct _GtkCheckButton GtkCheckButton; +typedef struct _GtkCheckButtonClass GtkCheckButtonClass; + +struct _GtkCheckButton +{ + GtkToggleButton toggle_button; +}; + +struct _GtkCheckButtonClass +{ + GtkToggleButtonClass parent_class; + + guint16 indicator_size; + guint16 indicator_spacing; + + void (* draw_indicator) (GtkCheckButton *check_button, + GdkRectangle *area); +}; + + +guint gtk_check_button_get_type (void); +GtkWidget* gtk_check_button_new (void); +GtkWidget* gtk_check_button_new_with_label (const gchar *label); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CHECK_BUTTON_H__ */ diff --git a/gtk/gtkcheckmenuitem.c b/gtk/gtkcheckmenuitem.c new file mode 100644 index 0000000000..a36dfa75a0 --- /dev/null +++ b/gtk/gtkcheckmenuitem.c @@ -0,0 +1,250 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkcheckmenuitem.h" +#include "gtklabel.h" +#include "gtksignal.h" + + +#define CHECK_MENU_ITEM_CLASS(w) GTK_CHECK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) + + +enum { + TOGGLED, + LAST_SIGNAL +}; + + +static void gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass); +static void gtk_check_menu_item_init (GtkCheckMenuItem *check_menu_item); +static void gtk_check_menu_item_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_check_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_check_menu_item_activate (GtkMenuItem *menu_item); +static void gtk_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); +static void gtk_real_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); + + +static GtkMenuItemClass *parent_class = NULL; +static gint check_menu_item_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_check_menu_item_get_type () +{ + static guint check_menu_item_type = 0; + + if (!check_menu_item_type) + { + GtkTypeInfo check_menu_item_info = + { + "GtkCheckMenuItem", + sizeof (GtkCheckMenuItem), + sizeof (GtkCheckMenuItemClass), + (GtkClassInitFunc) gtk_check_menu_item_class_init, + (GtkObjectInitFunc) gtk_check_menu_item_init, + (GtkArgFunc) NULL, + }; + + check_menu_item_type = gtk_type_unique (gtk_menu_item_get_type (), &check_menu_item_info); + } + + return check_menu_item_type; +} + +GtkWidget* +gtk_check_menu_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_check_menu_item_get_type ())); +} + +GtkWidget* +gtk_check_menu_item_new_with_label (const gchar *label) +{ + GtkWidget *check_menu_item; + GtkWidget *label_widget; + + check_menu_item = gtk_check_menu_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (check_menu_item), label_widget); + gtk_widget_show (label_widget); + + return check_menu_item; +} + +void +gtk_check_menu_item_set_state (GtkCheckMenuItem *check_menu_item, + gint state) +{ + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item)); + + if (check_menu_item->active != state) + gtk_menu_item_activate (GTK_MENU_ITEM (check_menu_item)); +} + +void +gtk_check_menu_item_toggled (GtkCheckMenuItem *check_menu_item) +{ + gtk_signal_emit (GTK_OBJECT (check_menu_item), check_menu_item_signals[TOGGLED]); +} + + +static void +gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkMenuItemClass *menu_item_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + menu_item_class = (GtkMenuItemClass*) klass; + + parent_class = gtk_type_class (gtk_menu_item_get_type ()); + + check_menu_item_signals[TOGGLED] = + gtk_signal_new ("toggled", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCheckMenuItemClass, toggled), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, check_menu_item_signals, LAST_SIGNAL); + + widget_class->draw = gtk_check_menu_item_draw; + widget_class->expose_event = gtk_check_menu_item_expose; + + menu_item_class->activate = gtk_check_menu_item_activate; + menu_item_class->toggle_size = 12; + + klass->toggled = NULL; + klass->draw_indicator = gtk_real_check_menu_item_draw_indicator; +} + +static void +gtk_check_menu_item_init (GtkCheckMenuItem *check_menu_item) +{ + check_menu_item->active = FALSE; +} + +static void +gtk_check_menu_item_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_CLASS (parent_class)->draw) + (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area); + + gtk_check_menu_item_draw_indicator (GTK_CHECK_MENU_ITEM (widget), area); +} + +static gint +gtk_check_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CHECK_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_CLASS (parent_class)->expose_event) + (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); + + gtk_check_menu_item_draw_indicator (GTK_CHECK_MENU_ITEM (widget), &event->area); + + return FALSE; +} + +static void +gtk_check_menu_item_activate (GtkMenuItem *menu_item) +{ + GtkCheckMenuItem *check_menu_item; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (menu_item)); + + check_menu_item = GTK_CHECK_MENU_ITEM (menu_item); + check_menu_item->active = !check_menu_item->active; + + gtk_check_menu_item_toggled (check_menu_item); + gtk_widget_queue_draw (GTK_WIDGET (check_menu_item)); +} + +static void +gtk_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area) +{ + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item)); + g_return_if_fail (CHECK_MENU_ITEM_CLASS (check_menu_item) != NULL); + + if (CHECK_MENU_ITEM_CLASS (check_menu_item)->draw_indicator) + (* CHECK_MENU_ITEM_CLASS (check_menu_item)->draw_indicator) (check_menu_item, area); +} + +static void +gtk_real_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkStateType state_type; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item)); + + if (GTK_WIDGET_DRAWABLE (check_menu_item)) + { + widget = GTK_WIDGET (check_menu_item); + + width = 8; + height = 8; + x = (GTK_CONTAINER (check_menu_item)->border_width + + widget->style->klass->xthickness + 2); + y = (widget->allocation.height - height) / 2; + + gdk_window_clear_area (widget->window, x, y, width, height); + + if (check_menu_item->active || + (GTK_WIDGET_STATE (check_menu_item) == GTK_STATE_PRELIGHT)) + { + state_type = GTK_WIDGET_STATE (widget); + + shadow_type = GTK_SHADOW_IN; + if (check_menu_item->active && (state_type == GTK_STATE_PRELIGHT)) + shadow_type = GTK_SHADOW_OUT; + + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[state_type], + TRUE, x, y, width, height); + gtk_draw_shadow (widget->style, widget->window, + state_type, shadow_type, + x, y, width, height); + } + } +} diff --git a/gtk/gtkcheckmenuitem.h b/gtk/gtkcheckmenuitem.h new file mode 100644 index 0000000000..1dc816c7c7 --- /dev/null +++ b/gtk/gtkcheckmenuitem.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MENU_CHECK_ITEM_H__ +#define __GTK_MENU_CHECK_ITEM_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkmenuitem.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CHECK_MENU_ITEM(obj) ((GtkCheckMenuItem*) obj) +#define GTK_CHECK_MENU_ITEM_CLASS(obj) ((GtkCheckMenuItemClass*) GTK_OBJECT_CLASS (obj)) +#define GTK_IS_CHECK_MENU_ITEM(obj) (gtk_type_is_a (GTK_WIDGET_TYPE (obj), gtk_check_menu_item_get_type ())) + + +typedef struct _GtkCheckMenuItem GtkCheckMenuItem; +typedef struct _GtkCheckMenuItemClass GtkCheckMenuItemClass; + +struct _GtkCheckMenuItem +{ + GtkMenuItem menu_item; + + guint active : 1; +}; + +struct _GtkCheckMenuItemClass +{ + GtkMenuItemClass parent_class; + + void (* toggled) (GtkCheckMenuItem *check_menu_item); + void (* draw_indicator) (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); +}; + + +guint gtk_check_menu_item_get_type (void); +GtkWidget* gtk_check_menu_item_new (void); +GtkWidget* gtk_check_menu_item_new_with_label (const gchar *label); +void gtk_check_menu_item_set_state (GtkCheckMenuItem *check_menu_item, + gint state); +void gtk_check_menu_item_toggled (GtkCheckMenuItem *check_menu_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CHECK_MENU_ITEM_H__ */ diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c new file mode 100644 index 0000000000..78780b2ff4 --- /dev/null +++ b/gtk/gtkcolorsel.c @@ -0,0 +1,1463 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <math.h> +#include "gtkcolorsel.h" + + +#define DEGTORAD(a) (2.0*M_PI*a/360.0) +#define SQR(a) (a*a) + +#define TIMER_DELAY 300 + +#define CIRCLE_RADIUS 65 + +#define WHEEL_WIDTH 2*CIRCLE_RADIUS+2 +#define WHEEL_HEIGHT 2*CIRCLE_RADIUS+2 + +#define VALUE_WIDTH 32 +#define VALUE_HEIGHT WHEEL_HEIGHT + +#define SAMPLE_WIDTH WHEEL_WIDTH+VALUE_WIDTH+5 +#define SAMPLE_HEIGHT 28 + + +enum +{ + COLOR_CHANGED, + LAST_SIGNAL +}; + +enum +{ + RGB_INPUTS = 1 << 0, + HSV_INPUTS = 1 << 1, + OPACITY_INPUTS = 1 << 2 +}; + +enum +{ + SCALE, + ENTRY, + BOTH +}; + +enum +{ + HUE, + SATURATION, + VALUE, + RED, + GREEN, + BLUE, + OPACITY, + NUM_CHANNELS +}; + +typedef struct +{ + gchar *label; + gfloat lower, upper, step_inc, page_inc; + GtkSignalFunc updater; +} scale_val_type; + + +#define HSV_TO_RGB() gtk_color_selection_hsv_to_rgb( \ + colorsel->values[HUE], \ + colorsel->values[SATURATION], \ + colorsel->values[VALUE], \ + &colorsel->values[RED], \ + &colorsel->values[GREEN], \ + &colorsel->values[BLUE]) + +#define RGB_TO_HSV() gtk_color_selection_rgb_to_hsv( \ + colorsel->values[RED], \ + colorsel->values[GREEN], \ + colorsel->values[BLUE], \ + &colorsel->values[HUE], \ + &colorsel->values[SATURATION], \ + &colorsel->values[VALUE]) + + +static void gtk_color_selection_hsv_updater (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_rgb_updater (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_opacity_updater (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_realize (GtkWidget *widget); +static void gtk_color_selection_destroy (GtkObject *object); +static void gtk_color_selection_color_changed (GtkColorSelection *colorsel); +static void gtk_color_selection_update_input (GtkWidget *scale, + GtkWidget *entry, + gdouble value); +static void gtk_color_selection_update_inputs (GtkColorSelection *colorsel, + gint inputs, + gint which); +static void gtk_color_selection_update_value (GtkColorSelection *colorsel, + gint y); +static void gtk_color_selection_update_wheel (GtkColorSelection *colorsel, + gint x, + gint y); +static void gtk_color_selection_value_resize (GtkWidget *widget, + gpointer data); +static gint gtk_color_selection_value_events (GtkWidget *area, + GdkEvent *event); +static gint gtk_color_selection_value_timeout (GtkColorSelection *colorsel); +static void gtk_color_selection_wheel_resize (GtkWidget *widget, + gpointer data); +static gint gtk_color_selection_wheel_events (GtkWidget *area, + GdkEvent *event); +static gint gtk_color_selection_wheel_timeout (GtkColorSelection *colorsel); +static void gtk_color_selection_sample_resize (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_drop_handle (GtkWidget *widget, + GdkEvent *event); +static void gtk_color_selection_drag_handle (GtkWidget *widget, + GdkEvent *event); +static void gtk_color_selection_draw_wheel_marker (GtkColorSelection *colorsel); +static void gtk_color_selection_draw_wheel_frame (GtkColorSelection *colorsel); +static void gtk_color_selection_draw_value_marker (GtkColorSelection *colorsel); +static void gtk_color_selection_draw_value_bar (GtkColorSelection *colorsel, + gint resize); +static void gtk_color_selection_draw_wheel (GtkColorSelection *colorsel, + gint resize); +static void gtk_color_selection_draw_sample (GtkColorSelection *colorsel, + gint resize); + +static gint gtk_color_selection_eval_wheel (gint x, gint y, + gdouble cx, gdouble cy, + gdouble *h, gdouble *s); + +static void gtk_color_selection_hsv_to_rgb (gdouble h, gdouble s, gdouble v, + gdouble *r, gdouble *g, gdouble *b); +static void gtk_color_selection_rgb_to_hsv (gdouble r, gdouble g, gdouble b, + gdouble *h, gdouble *s, gdouble *v); + +static void gtk_color_selection_dialog_destroy (GtkObject *object); + + +static GtkVBoxClass *color_selection_parent_class = NULL; +static GtkWindowClass *color_selection_dialog_parent_class = NULL; + + +static gint color_selection_signals[LAST_SIGNAL] = {0}; + + +#define SF GtkSignalFunc + + +scale_val_type scale_vals[NUM_CHANNELS] = +{ + {"Hue:", 0.0, 360.0, 1.00, 10.00, (SF) gtk_color_selection_hsv_updater}, + {"Saturation:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_hsv_updater}, + {"Value:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_hsv_updater}, + {"Red:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, + {"Green:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, + {"Blue:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, + {"Opacity:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_opacity_updater} +}; + +guint +gtk_color_selection_get_type () +{ + static guint color_selection_type = 0; + + if (!color_selection_type) + { + GtkTypeInfo colorsel_info = + { + "color selection widget", + sizeof (GtkColorSelection), + sizeof (GtkColorSelectionClass), + (GtkClassInitFunc) gtk_color_selection_class_init, + (GtkObjectInitFunc) gtk_color_selection_init, + }; + + color_selection_type = gtk_type_unique (gtk_vbox_get_type (), &colorsel_info); + } + + return color_selection_type; +} + +void +gtk_color_selection_class_init (GtkColorSelectionClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + color_selection_parent_class = gtk_type_class (gtk_vbox_get_type ()); + + color_selection_signals[COLOR_CHANGED] = + gtk_signal_new ("color_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkColorSelectionClass, color_changed), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, color_selection_signals, LAST_SIGNAL); + + object_class->destroy = gtk_color_selection_destroy; + + widget_class->realize = gtk_color_selection_realize; +} + +void +gtk_color_selection_init (GtkColorSelection *colorsel) +{ + GtkWidget *frame, *hbox, *vbox, *hbox2, *label, *table; + GtkObject *adj; + gint old_mask, n; + gchar txt[32]; + + for (n = RED; n <= OPACITY; n++) + colorsel->values[n] = 1.0; + + RGB_TO_HSV (); + + for (n = HUE; n <= OPACITY; n++) + colorsel->old_values[n] = colorsel->values[n]; + + colorsel->wheel_gc = NULL; + colorsel->value_gc = NULL; + colorsel->sample_gc = NULL; + colorsel->wheel_buf = NULL; + colorsel->value_buf = NULL; + colorsel->sample_buf = NULL; + + colorsel->use_opacity = FALSE; + colorsel->timer_active = FALSE; + colorsel->policy = GTK_UPDATE_CONTINUOUS; + + hbox = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (hbox), 5); + gtk_container_add (GTK_CONTAINER (colorsel), hbox); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_add (GTK_CONTAINER (hbox), vbox); + gtk_widget_show (vbox); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_container_add (GTK_CONTAINER (vbox), hbox2); + gtk_widget_show (hbox2); + + colorsel->wheel_area = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_widget_set_events (colorsel->wheel_area, + old_mask | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + gtk_preview_size (GTK_PREVIEW (colorsel->wheel_area), WHEEL_WIDTH, WHEEL_HEIGHT); + gtk_preview_set_expand (GTK_PREVIEW (colorsel->wheel_area), TRUE); + gtk_container_add (GTK_CONTAINER (hbox2), colorsel->wheel_area); + gtk_widget_show (colorsel->wheel_area); + + old_mask = gtk_widget_get_events (colorsel->wheel_area); + + gtk_signal_connect (GTK_OBJECT (colorsel->wheel_area), "event", + (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area); + gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "expose_event", + (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area); + gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "size_allocate", + (SF) gtk_color_selection_wheel_resize, (gpointer) colorsel->wheel_area); + gtk_object_set_data (GTK_OBJECT (colorsel->wheel_area), "_GtkColorSelection", (gpointer) colorsel); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_container_border_width (GTK_CONTAINER (frame), 0); + gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + colorsel->value_area = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (colorsel->value_area), VALUE_WIDTH, VALUE_HEIGHT); + gtk_preview_set_expand (GTK_PREVIEW (colorsel->value_area), TRUE); + gtk_container_add (GTK_CONTAINER (frame), colorsel->value_area); + gtk_widget_show (colorsel->value_area); + + old_mask = gtk_widget_get_events (colorsel->value_area); + gtk_widget_set_events (colorsel->value_area, + old_mask | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "expose_event", + (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area); + gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "size_allocate", + (SF) gtk_color_selection_value_resize, (gpointer) colorsel->value_area); + gtk_signal_connect (GTK_OBJECT (colorsel->value_area), "event", + (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area); + gtk_object_set_data (GTK_OBJECT (colorsel->value_area), "_GtkColorSelection", (gpointer) colorsel); + + /* New/old color samples */ + /* ===================== */ + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + +/* colorsel->sample_area_eb = gtk_button_new (); + gtk_container_add (GTK_CONTAINER (frame), colorsel->sample_area_eb); + gtk_widget_show (colorsel->sample_area_eb); */ + + colorsel->sample_area = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (colorsel->sample_area), SAMPLE_WIDTH, SAMPLE_HEIGHT); + gtk_preview_set_expand (GTK_PREVIEW (colorsel->sample_area), TRUE); + gtk_container_add (GTK_CONTAINER (frame), + colorsel->sample_area); + gtk_widget_set_events(colorsel->sample_area, + gtk_widget_get_events(colorsel->sample_area) + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_show (colorsel->sample_area); + + gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area), + "size_allocate", + GTK_SIGNAL_FUNC (gtk_color_selection_sample_resize), + colorsel->sample_area); + gtk_object_set_data (GTK_OBJECT (colorsel->sample_area), "_GtkColorSelection", (gpointer) colorsel); + + table = gtk_table_new (NUM_CHANNELS, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 3); + gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, TRUE, 0); + + for (n = HUE; n <= OPACITY; n++) + { + label = gtk_label_new (scale_vals[n].label); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, n, n + 1); + + adj = gtk_adjustment_new (colorsel->values[n], scale_vals[n].lower, + scale_vals[n].upper, scale_vals[n].step_inc, + scale_vals[n].page_inc, 0.0); + colorsel->scales[n] = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_set_usize (colorsel->scales[n], 128, 0); + gtk_scale_set_value_pos (GTK_SCALE (colorsel->scales[n]), GTK_POS_TOP); + + gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), colorsel->policy); + gtk_scale_set_draw_value (GTK_SCALE (colorsel->scales[n]), FALSE); + gtk_scale_set_digits (GTK_SCALE (colorsel->scales[n]), 2); + gtk_table_attach_defaults (GTK_TABLE (table), colorsel->scales[n], 1, 2, n, n + 1); + + colorsel->entries[n] = gtk_entry_new (); + gtk_widget_set_usize (colorsel->entries[n], 40, 0); + sprintf (txt, "%.2f", colorsel->values[n]); + gtk_entry_set_text (GTK_ENTRY (colorsel->entries[n]), txt); + gtk_table_attach_defaults (GTK_TABLE (table), colorsel->entries[n], 2, 3, n, n + 1); + + if (n != OPACITY) + { + gtk_widget_show (label); + gtk_widget_show (colorsel->scales[n]); + gtk_widget_show (colorsel->entries[n]); + } + + gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed", + scale_vals[n].updater, (gpointer) colorsel->scales[n]); + gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), "_GtkColorSelection", (gpointer) colorsel); + gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), "_ValueIndex", (gpointer) n); + gtk_signal_connect_object (GTK_OBJECT (colorsel->entries[n]), "changed", + scale_vals[n].updater, (gpointer) colorsel->entries[n]); + gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), "_GtkColorSelection", (gpointer) colorsel); + gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), "_ValueIndex", (gpointer) n); + } + + colorsel->opacity_label = label; + + gtk_widget_show (table); + gtk_widget_show (hbox); +} + +GtkWidget * +gtk_color_selection_new (void) +{ + GtkColorSelection *colorsel; + + colorsel = gtk_type_new (gtk_color_selection_get_type ()); + + return GTK_WIDGET (colorsel); +} + +void +gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, + GtkUpdateType policy) +{ + gint n; + + g_return_if_fail (colorsel != NULL); + + if (policy != colorsel->policy) + { + colorsel->policy = policy; + + for (n = 0; n < NUM_CHANNELS; n++) + gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), policy); + } +} + + +void +gtk_color_selection_set_color (GtkColorSelection *colorsel, + gdouble *color) +{ + gint n, i = 0; + + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel))) + gtk_color_selection_draw_wheel_marker (colorsel); + + for (n = RED; n <= BLUE; n++) + { + colorsel->old_values[n] = colorsel->values[n]; + colorsel->values[n] = color[i++]; + } + + if (colorsel->use_opacity == TRUE) + { + colorsel->old_values[OPACITY] = colorsel->values[OPACITY]; + colorsel->values[OPACITY] = color[i]; + } + + RGB_TO_HSV (); + + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS | OPACITY_INPUTS, BOTH); + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel))) + { + gtk_color_selection_draw_value_bar (colorsel, FALSE); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_draw_wheel_marker (colorsel); + } +} + +void +gtk_color_selection_get_color (GtkColorSelection *colorsel, + gdouble *color) +{ + gint n, i = 0; + + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + + for (n = RED; n <= BLUE; n++) + color[i++] = colorsel->values[n]; + if (colorsel->use_opacity == TRUE) + color[i] = colorsel->values[OPACITY]; +} + +static void +gtk_color_selection_realize (GtkWidget *widget) +{ + GtkColorSelection *colorsel; + gchar *type_accept_list[] = {"application/x-color"}; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (widget)); + + colorsel = GTK_COLOR_SELECTION (widget); + + if (GTK_WIDGET_CLASS (color_selection_parent_class)->realize) + (*GTK_WIDGET_CLASS (color_selection_parent_class)->realize) (widget); + + gtk_widget_dnd_drag_set (colorsel->sample_area, + 1, type_accept_list, 1); + gtk_widget_dnd_drop_set (colorsel->sample_area, + 1, type_accept_list, 1, 0); + gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area), + "drop_data_available_event", + GTK_SIGNAL_FUNC (gtk_color_selection_drop_handle), + NULL); + gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area), + "drag_request_event", + GTK_SIGNAL_FUNC (gtk_color_selection_drag_handle), + NULL); +} + +static void +gtk_color_selection_destroy (GtkObject *object) +{ + GtkColorSelection *colorsel; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (object)); + + colorsel = GTK_COLOR_SELECTION (object); + + if (colorsel->wheel_buf != NULL) + g_free (colorsel->wheel_buf); + if (colorsel->value_buf != NULL) + g_free (colorsel->value_buf); + if (colorsel->sample_buf != NULL) + g_free (colorsel->sample_buf); + + if (GTK_OBJECT_CLASS (color_selection_parent_class)->destroy) + (*GTK_OBJECT_CLASS (color_selection_parent_class)->destroy) (object); +} + +static void +gtk_color_selection_color_changed (GtkColorSelection *colorsel) +{ + gtk_signal_emit (GTK_OBJECT (colorsel), color_selection_signals[COLOR_CHANGED]); +} + +static void +gtk_color_selection_update_input (GtkWidget *scale, + GtkWidget *entry, + gdouble value) +{ + GtkAdjustment *adj; + gchar txt[32]; + + if (scale != NULL) + { + adj = gtk_range_get_adjustment (GTK_RANGE (scale)); + adj->value = (gfloat) value; + gtk_signal_handler_block_by_data (GTK_OBJECT (adj), (gpointer) scale); + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); + gtk_range_slider_update (GTK_RANGE (scale)); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), (gpointer) scale); + } + + if (entry != NULL) + { + gtk_signal_handler_block_by_data (GTK_OBJECT (entry), (gpointer) entry); + sprintf (txt, "%.2f", value); + gtk_entry_set_text (GTK_ENTRY (entry), txt); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (entry), (gpointer) entry); + } +} + +static void +gtk_color_selection_update_inputs (GtkColorSelection *colorsel, + gint inputs, + gint which) +{ + gint n; + + switch (which) + { + case SCALE: + if ((inputs & RGB_INPUTS) != 0) + for (n = RED; n <= BLUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], NULL, + colorsel->values[n]); + if ((inputs & HSV_INPUTS) != 0) + for (n = HUE; n <= VALUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], NULL, + colorsel->values[n]); + if ((inputs & OPACITY_INPUTS) != 0) + gtk_color_selection_update_input(colorsel->scales[OPACITY], NULL, + colorsel->values[OPACITY]); + break; + case ENTRY: + if ((inputs & RGB_INPUTS) != 0) + for (n = RED; n <= BLUE; n++) + gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]); + if ((inputs & HSV_INPUTS) != 0) + for (n = HUE; n <= VALUE; n++) + gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]); + if ((inputs & OPACITY_INPUTS) != 0) + gtk_color_selection_update_input(NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]); + break; + default: + if ((inputs & RGB_INPUTS) != 0) + for (n = RED; n <= BLUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n], + colorsel->values[n]); + if ((inputs & HSV_INPUTS) != 0) + for (n = HUE; n <= VALUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n], + colorsel->values[n]); + if ((inputs & OPACITY_INPUTS) != 0) + gtk_color_selection_update_input(colorsel->scales[OPACITY], colorsel->entries[OPACITY], + colorsel->values[OPACITY]); + break; + } +} + +static void +gtk_color_selection_hsv_updater (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + GtkAdjustment *adj; + gdouble newvalue; + gint i, which = SCALE; + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget))) + { + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + i = (gint) gtk_object_get_data (GTK_OBJECT (widget), "_ValueIndex"); + + if (GTK_IS_SCALE (widget)) + { + adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget))); + newvalue = (gdouble) adj->value; + which = ENTRY; + } + else + newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); + + if (i == VALUE) + { + gtk_color_selection_draw_value_marker (colorsel); + colorsel->values[i] = newvalue; + + HSV_TO_RGB (); + + gtk_color_selection_draw_value_marker (colorsel); + } + else + { + gtk_color_selection_draw_wheel_marker (colorsel); + colorsel->values[i] = newvalue; + + HSV_TO_RGB (); + + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_value_bar (colorsel, FALSE); + } + + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_color_changed (colorsel); + gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, which); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH); + } +} + +static void +gtk_color_selection_rgb_updater (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + GtkAdjustment *adj; + gdouble newvalue; + gint i, which = SCALE; + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget))) + { + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + i = (gint) gtk_object_get_data (GTK_OBJECT (widget), "_ValueIndex"); + + if (GTK_IS_SCALE (widget)) + { + adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget))); + newvalue = (gdouble) adj->value; + which = ENTRY; + } + else + newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); + + gtk_color_selection_draw_wheel_marker (colorsel); + + colorsel->values[i] = newvalue; + RGB_TO_HSV (); + + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_value_bar (colorsel, FALSE); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_color_changed (colorsel); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, which); + gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, BOTH); + } +} + +static void +gtk_color_selection_opacity_updater (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + GtkAdjustment *adj; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + + if (GTK_IS_SCALE (widget)) + { + adj = gtk_range_get_adjustment (GTK_RANGE (widget)); + colorsel->values[OPACITY] = (gdouble) adj->value; + gtk_color_selection_update_input (NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]); + } + else + { + colorsel->values[OPACITY] = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); + gtk_color_selection_update_input (colorsel->scales[OPACITY], NULL, colorsel->values[OPACITY]); + } + + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_color_changed (colorsel); +} + +void +gtk_color_selection_set_opacity (GtkColorSelection *colorsel, + gint use_opacity) +{ + g_return_if_fail (colorsel != NULL); + + colorsel->use_opacity = use_opacity; + + if (use_opacity == FALSE && GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY])) + { + gtk_widget_hide (colorsel->opacity_label); + gtk_widget_hide (colorsel->scales[OPACITY]); + gtk_widget_hide (colorsel->entries[OPACITY]); + } + else if (use_opacity == TRUE && !GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY])) + { + gtk_widget_show (colorsel->opacity_label); + gtk_widget_show (colorsel->scales[OPACITY]); + gtk_widget_show (colorsel->entries[OPACITY]); + } + + if (GTK_WIDGET_DRAWABLE (colorsel->sample_area)) + gtk_color_selection_draw_sample (colorsel, FALSE); +} + +static void +gtk_color_selection_value_resize (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + gtk_color_selection_draw_value_bar (colorsel, TRUE); +} + +static void +gtk_color_selection_wheel_resize (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + gtk_color_selection_draw_wheel (colorsel, TRUE); +} + +static void +gtk_color_selection_sample_resize (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + gtk_color_selection_draw_sample (colorsel, TRUE); +} + +static void +gtk_color_selection_drop_handle (GtkWidget *widget, GdkEvent *event) +{ + int i; + GtkColorSelection *w; + gdouble *newbuf; + g_print("Handling drop in color selection\n"); + gtk_color_selection_set_color(GTK_COLOR_SELECTION(widget), + event->dropdataavailable.data); + g_free(event->dropdataavailable.data); + g_free(event->dropdataavailable.data_type); +} + +static void +gtk_color_selection_drag_handle (GtkWidget *widget, GdkEvent *event) +{ + g_print("Handling drag in color selector\n"); + gtk_widget_dnd_data_set(widget, event, GTK_COLOR_SELECTION(widget)->values, + sizeof(GTK_COLOR_SELECTION(widget)->values)); +} + +static void +gtk_color_selection_draw_wheel_marker (GtkColorSelection *colorsel) +{ + gint xpos, ypos; + + gdk_gc_set_function (colorsel->wheel_gc, GDK_INVERT); + + xpos = (gint) ((-(gdouble) (colorsel->wheel_area->allocation.width) / 2.0) * + colorsel->values[SATURATION] * cos (DEGTORAD ((colorsel->values[HUE] - 90)))) + + (colorsel->wheel_area->allocation.width >> 1) - 4; + ypos = (gint) (((gdouble) (colorsel->wheel_area->allocation.height) / 2.0) * + colorsel->values[SATURATION] * sin (DEGTORAD ((colorsel->values[HUE] - 90)))) + + (colorsel->wheel_area->allocation.height >> 1) - 4; + + gdk_draw_arc (colorsel->wheel_area->window, colorsel->wheel_gc, FALSE, xpos, ypos, 8, 8, 0, 360 * 64); +} + +static void +gtk_color_selection_draw_value_marker (GtkColorSelection *colorsel) +{ + gint y; + + gdk_gc_set_function (colorsel->value_gc, GDK_INVERT); + + y = (gint) ((gdouble) (colorsel->value_area->allocation.height) * (1.0 - colorsel->values[VALUE])); + gdk_draw_line (colorsel->value_area->window, colorsel->value_gc, + 0, y, colorsel->value_area->allocation.width, y); +} + +static void +gtk_color_selection_update_value (GtkColorSelection *colorsel, + gint y) +{ + gtk_color_selection_draw_value_marker (colorsel); + + if (y < 0) + y = 0; + else if (y > colorsel->value_area->allocation.height - 1) + y = colorsel->value_area->allocation.height - 1; + + colorsel->values[VALUE] = 1.0 - (gdouble) y / (gdouble) (colorsel->value_area->allocation.height); + + HSV_TO_RGB (); + + gtk_color_selection_draw_value_marker (colorsel); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_update_input (colorsel->scales[VALUE], colorsel->entries[VALUE], + colorsel->values[VALUE]); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH); +} + +static void +gtk_color_selection_update_wheel (GtkColorSelection *colorsel, + gint x, + gint y) +{ + gdouble wid, heig; + gint res; + + gtk_color_selection_draw_wheel_marker (colorsel); + + wid = (gdouble) (colorsel->wheel_area->allocation.width) / 2.0; + heig = (gdouble) (colorsel->wheel_area->allocation.height) / 2.0; + + res = gtk_color_selection_eval_wheel (x, y, wid, heig, &colorsel->values[HUE], + &colorsel->values[SATURATION]); + + HSV_TO_RGB (); + + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_value_bar (colorsel, FALSE); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS, BOTH); +} + +static gint +gtk_color_selection_value_timeout (GtkColorSelection *colorsel) +{ + gint x, y; + + gdk_window_get_pointer (colorsel->value_area->window, &x, &y, NULL); + gtk_color_selection_update_value (colorsel, y); + gtk_color_selection_color_changed (colorsel); + + return (TRUE); +} + +static gint +gtk_color_selection_value_events (GtkWidget *area, + GdkEvent *event) +{ + GtkColorSelection *colorsel; + gint y; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection"); + + switch (event->type) + { + case GDK_MAP: + gtk_color_selection_draw_value_marker (colorsel); + break; + case GDK_EXPOSE: + if (colorsel->value_gc == NULL) + colorsel->value_gc = gdk_gc_new (colorsel->value_area->window); + gtk_color_selection_draw_value_marker (colorsel); + break; + case GDK_BUTTON_PRESS: + gtk_grab_add (area); + gtk_color_selection_update_value (colorsel, event->button.y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_BUTTON_RELEASE: + gtk_grab_remove (area); + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + colorsel->timer_active = FALSE; + + y = event->button.y; + if (event->button.window != area->window) + gdk_window_get_pointer (area->window, NULL, &y, NULL); + + gtk_color_selection_update_value (colorsel, y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_MOTION_NOTIFY: + y = event->motion.y; + + if (event->motion.is_hint || (event->motion.window != area->window)) + gdk_window_get_pointer (area->window, NULL, &y, NULL); + + switch (colorsel->policy) + { + case GTK_UPDATE_CONTINUOUS: + gtk_color_selection_update_value (colorsel, y); + gtk_color_selection_color_changed (colorsel); + break; + case GTK_UPDATE_DELAYED: + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + + colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY, + (GtkFunction) gtk_color_selection_value_timeout, + (gpointer) colorsel); + colorsel->timer_active = TRUE; + break; + default: + break; + } + break; + default: + break; + } + + return (FALSE); +} + +static gint +gtk_color_selection_wheel_timeout (GtkColorSelection *colorsel) +{ + gint x, y; + + gdk_window_get_pointer (colorsel->wheel_area->window, &x, &y, NULL); + gtk_color_selection_update_wheel (colorsel, x, y); + gtk_color_selection_color_changed (colorsel); + + return (TRUE); +} + +static gint +gtk_color_selection_wheel_events (GtkWidget *area, + GdkEvent *event) +{ + GtkColorSelection *colorsel; + gint x, y; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection"); + + switch (event->type) + { + case GDK_MAP: + gtk_color_selection_draw_wheel (colorsel, TRUE); + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_sample (colorsel, TRUE); + break; + case GDK_EXPOSE: + if (colorsel->wheel_gc == NULL) + colorsel->wheel_gc = gdk_gc_new (colorsel->wheel_area->window); + if (colorsel->sample_gc == NULL) + colorsel->sample_gc = gdk_gc_new (colorsel->sample_area->window); + if (colorsel->value_gc == NULL) + colorsel->value_gc = gdk_gc_new (colorsel->value_area->window); + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_wheel_frame (colorsel); + break; + case GDK_BUTTON_PRESS: + gtk_grab_add (area); + gtk_color_selection_update_wheel (colorsel, event->button.x, event->button.y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_BUTTON_RELEASE: + gtk_grab_remove (area); + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + colorsel->timer_active = FALSE; + + x = event->button.x; + y = event->button.y; + + if (event->button.window != area->window) + gdk_window_get_pointer (area->window, &x, &y, NULL); + + gtk_color_selection_update_wheel (colorsel, x, y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_MOTION_NOTIFY: + x = event->motion.x; + y = event->motion.y; + + if (event->motion.is_hint || (event->motion.window != area->window)) + gdk_window_get_pointer (area->window, &x, &y, NULL); + + switch (colorsel->policy) + { + case GTK_UPDATE_CONTINUOUS: + gtk_color_selection_update_wheel (colorsel, x, y); + gtk_color_selection_color_changed (colorsel); + break; + case GTK_UPDATE_DELAYED: + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY, + (GtkFunction) gtk_color_selection_wheel_timeout, + (gpointer) colorsel); + colorsel->timer_active = TRUE; + break; + default: + break; + } + break; + default: + break; + } + + return (FALSE); +} + +static void +gtk_color_selection_draw_value_bar (GtkColorSelection *colorsel, + gint resize) +{ + gint x, y, i, wid, heig, n; + gdouble sv, v, c[3]; + guchar rc[3]; + + wid = colorsel->value_area->allocation.width; + heig = colorsel->value_area->allocation.height; + + if (resize) + { + if (colorsel->value_buf != NULL) + g_free (colorsel->value_buf); + + colorsel->value_buf = g_new(guchar, 3 * wid); + } + + v = 1.0; + sv = 1.0 / (gdouble) (heig - 1); + + for (y = 0; y < heig; y++) + { + i = 0; + + gtk_color_selection_hsv_to_rgb (colorsel->values[HUE],colorsel->values[SATURATION],v, + &c[0], &c[1], &c[2]); + + for (n = 0; n < 3; n++) + rc[n] = (guchar) (255.0 * c[n]); + + for (x = 0; x < wid; x++) + { + for (n = 0; n < 3; n++) + colorsel->value_buf[i++] = rc[n]; + } + + gtk_preview_draw_row (GTK_PREVIEW (colorsel->value_area), colorsel->value_buf, 0, y, wid); + v -= sv; + } + + gtk_widget_draw (colorsel->value_area, NULL); +} + +static void +gtk_color_selection_draw_wheel_frame (GtkColorSelection *colorsel) +{ + GtkStyle *style; + gint w, h; + + style = gtk_widget_get_style (GTK_WIDGET (colorsel)); + + w = colorsel->wheel_area->allocation.width; + h = colorsel->wheel_area->allocation.height; + + gdk_draw_arc (colorsel->wheel_area->window, style->black_gc, + FALSE, 1, 1, w - 1, h - 1, 30 * 64, 180 * 64); + gdk_draw_arc (colorsel->wheel_area->window, style->mid_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, w, h, 30 * 64, 180 * 64); + + gdk_draw_arc (colorsel->wheel_area->window, style->bg_gc[GTK_STATE_NORMAL], + FALSE, 1, 1, w - 1, h - 1, 210 * 64, 180 * 64); + gdk_draw_arc (colorsel->wheel_area->window, style->light_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, w, h, 210 * 64, 180 * 64); +} + +static void +gtk_color_selection_draw_wheel (GtkColorSelection *colorsel, + gint resize) +{ + gint x, y, i, wid, heig, n; + gdouble cx, cy, h, s, c[3]; + guchar bg[3]; + GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (colorsel)); + + wid = colorsel->wheel_area->allocation.width; + heig = colorsel->wheel_area->allocation.height; + + if (resize) + { + if (colorsel->wheel_buf != NULL) + g_free (colorsel->wheel_buf); + + colorsel->wheel_buf = g_new(guchar, 3 * wid); + } + + cx = (gdouble) (wid) / 2.0; + cy = (gdouble) (heig) / 2.0; + + bg[0] = style->bg[GTK_STATE_NORMAL].red >> 8; + bg[1] = style->bg[GTK_STATE_NORMAL].green >> 8; + bg[2] = style->bg[GTK_STATE_NORMAL].blue >> 8; + + for (y = 0; y < heig; y++) + { + i = 0; + for (x = 0; x < wid; x++) + { + if (gtk_color_selection_eval_wheel (x, y, cx, cy, &h, &s) == TRUE) + { + for (n = 0; n < 3; n++) + colorsel->wheel_buf[i++] = bg[n]; + } + else + { + gtk_color_selection_hsv_to_rgb (h, s, 1.0, &c[0], &c[1], &c[2]); + for (n = 0; n < 3; n++) + colorsel->wheel_buf[i++] = (guchar) (255.0 * c[n]); + } + } + + gtk_preview_draw_row (GTK_PREVIEW (colorsel->wheel_area), colorsel->wheel_buf, 0, y, wid); + } + + gtk_widget_draw (colorsel->wheel_area, NULL); +} + +static void +gtk_color_selection_draw_sample (GtkColorSelection *colorsel, + gint resize) +{ + gint x, y, i, wid, heig, f, half, n; + guchar c[3 * 2], cc[3 * 4], *cp = c; + gdouble o, oldo; + + wid = colorsel->sample_area->allocation.width; + heig = colorsel->sample_area->allocation.height; + half = wid >> 1; + + if (resize) + { + if (colorsel->sample_buf != NULL) + g_free (colorsel->sample_buf); + + colorsel->sample_buf = g_new(guchar, 3 * wid); + } + + i = RED; + for (n = 0; n < 3; n++) + { + c[n] = (guchar) (255.0 * colorsel->old_values[i]); + c[n + 3] = (guchar) (255.0 * colorsel->values[i++]); + } + + if (colorsel->use_opacity == TRUE) + { + o = colorsel->values[OPACITY]; + oldo = colorsel->old_values[OPACITY]; + + for (n = 0; n < 3; n++) + { + cc[n] = (guchar) ((1.0 - oldo) * 192 + (oldo * (gdouble) c[n])); + cc[n + 3] = (guchar) ((1.0 - oldo) * 128 + (oldo * (gdouble) c[n])); + cc[n + 6] = (guchar) ((1.0 - o) * 192 + (o * (gdouble) c[n + 3])); + cc[n + 9] = (guchar) ((1.0 - o) * 128 + (o * (gdouble) c[n + 3])); + } + cp = cc; + } + + for (y = 0; y < heig; y++) + { + i = 0; + for (x = 0; x < wid; x++) + { + if (colorsel->use_opacity) + { + f = 3 * (((x % 32) < 16) ^ ((y % 32) < 16)); + f += (x > half) * 6; + } + else + f = (x > half) * 3; + + for (n = 0; n < 3; n++) + colorsel->sample_buf[i++] = cp[n + f]; + } + + gtk_preview_draw_row (GTK_PREVIEW (colorsel->sample_area), colorsel->sample_buf, 0, y, wid); + } + + gtk_widget_draw (colorsel->sample_area, NULL); +} + +static gint +gtk_color_selection_eval_wheel (gint x, gint y, + gdouble cx, gdouble cy, + gdouble *h, gdouble *s) +{ + gdouble d, r, rx, ry, l; + + rx = (gdouble) x - cx; + ry = (gdouble) y - cy; + + d = (SQR (cy) * SQR (rx) + SQR (cx) * SQR (ry) - SQR (cx) * SQR (cy)); + + r = sqrt (SQR (rx) + SQR (ry)); + + if (r != 0.0) + *h = atan2 (rx / r, ry / r); + else + *h = 0.0; + + l = sqrt (SQR ((cx * cos (*h + 0.5 * M_PI))) + SQR ((cy * sin (*h + 0.5 * M_PI)))); + *s = r / l; + *h = 360.0 * (*h) / (2.0 * M_PI) + 180; + + if (*s == 0.0) + *s = 0.00001; + else if (*s > 1.0) + *s = 1.0; + + return ((d > 0.0)); +} + +static void +gtk_color_selection_hsv_to_rgb (gdouble h, gdouble s, gdouble v, + gdouble *r, gdouble *g, gdouble *b) +{ + gint i; + gdouble f, w, q, t; + + if (s == 0.0) + s = 0.000001; + + if (h == -1.0) + { + *r = v; + *g = v; + *b = v; + } + else + { + if (h == 360.0) + h = 0.0; + h = h / 60.0; + i = (gint) h; + f = h - i; + w = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + switch (i) + { + case 0: + *r = v; + *g = t; + *b = w; + break; + case 1: + *r = q; + *g = v; + *b = w; + break; + case 2: + *r = w; + *g = v; + *b = t; + break; + case 3: + *r = w; + *g = q; + *b = v; + break; + case 4: + *r = t; + *g = w; + *b = v; + break; + case 5: + *r = v; + *g = w; + *b = q; + break; + } + } +} + +static void +gtk_color_selection_rgb_to_hsv (gdouble r, gdouble g, gdouble b, + gdouble *h, gdouble *s, gdouble *v) +{ + double max, min, delta; + + max = r; + if (g > max) + max = g; + if (b > max) + max = b; + + min = r; + if (g < min) + min = g; + if (b < min) + min = b; + + *v = max; + + if (max != 0.0) + *s = (max - min) / max; + else + *s = 0.0; + + if (*s == 0.0) + *h = -1.0; + else + { + delta = max - min; + + if (r == max) + *h = (g - b) / delta; + else if (g == max) + *h = 2.0 + (b - r) / delta; + else if (b == max) + *h = 4.0 + (r - g) / delta; + + *h = *h * 60.0; + + if (*h < 0.0) + *h = *h + 360; + } +} + +/***************************/ +/* GtkColorSelectionDialog */ +/***************************/ + +guint +gtk_color_selection_dialog_get_type () +{ + static guint color_selection_dialog_type = 0; + + if (!color_selection_dialog_type) + { + GtkTypeInfo colorsel_diag_info = + { + "color selection dialog", + sizeof (GtkColorSelectionDialog), + sizeof (GtkColorSelectionDialogClass), + (GtkClassInitFunc) gtk_color_selection_dialog_class_init, + (GtkObjectInitFunc) gtk_color_selection_dialog_init, + }; + + color_selection_dialog_type = gtk_type_unique (gtk_window_get_type (), &colorsel_diag_info); + } + + return color_selection_dialog_type; +} + +void +gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + color_selection_dialog_parent_class = gtk_type_class (gtk_window_get_type ()); + + object_class->destroy = gtk_color_selection_dialog_destroy; +} + +void +gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag) +{ + GtkWidget *action_area, *frame; + + colorseldiag->main_vbox = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (colorseldiag), 10); + gtk_container_add (GTK_CONTAINER (colorseldiag), colorseldiag->main_vbox); + gtk_widget_show (colorseldiag->main_vbox); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_container_add (GTK_CONTAINER (colorseldiag->main_vbox), frame); + gtk_widget_show (frame); + + colorseldiag->colorsel = gtk_color_selection_new (); + gtk_container_add (GTK_CONTAINER (frame), colorseldiag->colorsel); + gtk_widget_show (colorseldiag->colorsel); + + action_area = gtk_hbox_new (TRUE, 10); + gtk_box_pack_end (GTK_BOX (colorseldiag->main_vbox), action_area, FALSE, FALSE, 0); + gtk_widget_show (action_area); + + colorseldiag->ok_button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (colorseldiag->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->ok_button, TRUE, TRUE, 0); + gtk_widget_grab_default (colorseldiag->ok_button); + gtk_widget_show (colorseldiag->ok_button); + + colorseldiag->cancel_button = gtk_button_new_with_label ("Cancel"); + GTK_WIDGET_SET_FLAGS (colorseldiag->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (colorseldiag->cancel_button); + + colorseldiag->help_button = gtk_button_new_with_label ("Help"); + GTK_WIDGET_SET_FLAGS (colorseldiag->help_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->help_button, TRUE, TRUE, 0); + gtk_widget_show (colorseldiag->help_button); +} + +GtkWidget * +gtk_color_selection_dialog_new (const gchar *title) +{ + GtkColorSelectionDialog *colorseldiag; + + colorseldiag = gtk_type_new (gtk_color_selection_dialog_get_type ()); + gtk_window_set_title (GTK_WINDOW (colorseldiag), title); + + return GTK_WIDGET (colorseldiag); +} + +static void +gtk_color_selection_dialog_destroy (GtkObject *object) +{ + GtkColorSelectionDialog *colorseldiag; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION_DIALOG (object)); + + colorseldiag = GTK_COLOR_SELECTION_DIALOG (object); + + + if (GTK_OBJECT_CLASS (color_selection_dialog_parent_class)->destroy) + (*GTK_OBJECT_CLASS (color_selection_dialog_parent_class)->destroy) (object); +} diff --git a/gtk/gtkcolorsel.h b/gtk/gtkcolorsel.h new file mode 100644 index 0000000000..c29ea64f45 --- /dev/null +++ b/gtk/gtkcolorsel.h @@ -0,0 +1,152 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_COLORSEL_H__ +#define __GTK_COLORSEL_H__ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <gdk/gdk.h> + +#include "gtkwindow.h" +#include "gtkvbox.h" +#include "gtkframe.h" +#include "gtkpreview.h" +#include "gtkbutton.h" +#include "gtkentry.h" +#include "gtkhbox.h" +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtksignal.h" +#include "gtkmisc.h" +#include "gtkrange.h" +#include "gtkscale.h" +#include "gtkhscale.h" +#include "gtktable.h" +#include "gtkeventbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_COLOR_SELECTION(obj) GTK_CHECK_CAST (obj, gtk_color_selection_get_type (), GtkColorSelection) +#define GTK_COLOR_SELECTION_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_color_selection_get_type (), GtkColorSelectionClass) +#define GTK_IS_COLOR_SELECTION(obj) GTK_CHECK_TYPE (obj, gtk_color_selection_get_type ()) + +#define GTK_COLOR_SELECTION_DIALOG(obj) GTK_CHECK_CAST (obj, gtk_color_selection_dialog_get_type (), GtkColorSelectionDialog) +#define GTK_COLOR_SELECTION_DIALOG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_color_selection_dialog_get_type (), GtkColorSelectionDialogClass) +#define GTK_IS_COLOR_SELECTION_DIALOG(obj) GTK_CHECK_TYPE (obj, gtk_color_selection_dialog_get_type ()) + + +typedef struct _GtkColorSelection GtkColorSelection; +typedef struct _GtkColorSelectionClass GtkColorSelectionClass; + +typedef struct _GtkColorSelectionDialog GtkColorSelectionDialog; +typedef struct _GtkColorSelectionDialogClass GtkColorSelectionDialogClass; + + +struct _GtkColorSelection +{ + GtkVBox vbox; + + GtkWidget *wheel_area; + GtkWidget *value_area; + GtkWidget *sample_area, *sample_area_eb; + + GtkWidget *scales[8]; + GtkWidget *entries[8]; + GtkWidget *opacity_label; + + GdkGC *wheel_gc; + GdkGC *value_gc; + GdkGC *sample_gc; + + GtkUpdateType policy; + gint use_opacity; + gint timer_active; + gint timer_tag; + gdouble values[8]; + gdouble old_values[8]; + + guchar *wheel_buf; + guchar *value_buf; + guchar *sample_buf; +}; + +struct _GtkColorSelectionClass +{ + GtkVBoxClass parent_class; + + void (* color_changed) (GtkColorSelection *colorsel); +}; + +struct _GtkColorSelectionDialog +{ + GtkWindow window; + + GtkWidget *colorsel; + GtkWidget *main_vbox; + GtkWidget *ok_button; + GtkWidget *reset_button; + GtkWidget *cancel_button; + GtkWidget *help_button; +}; + +struct _GtkColorSelectionDialogClass +{ + GtkWindowClass parent_class; +}; + + +/* ColorSelection */ + +guint gtk_color_selection_get_type (void); +void gtk_color_selection_class_init (GtkColorSelectionClass *klass); +void gtk_color_selection_init (GtkColorSelection *colorsel); + +GtkWidget* gtk_color_selection_new (void); + +void gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, + GtkUpdateType policy); + +void gtk_color_selection_set_opacity (GtkColorSelection *colorsel, + gint use_opacity); + +void gtk_color_selection_set_color (GtkColorSelection *colorsel, + gdouble *color); + +void gtk_color_selection_get_color (GtkColorSelection *colorsel, + gdouble *color); + +/* ColorSelectionDialog */ + +guint gtk_color_selection_dialog_get_type (void); +void gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass); +void gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag); + +GtkWidget* gtk_color_selection_dialog_new (const gchar *title); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_COLORSEL_H__ */ diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c new file mode 100644 index 0000000000..977fabc29e --- /dev/null +++ b/gtk/gtkcontainer.c @@ -0,0 +1,844 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include "gtkcontainer.h" +#include "gtksignal.h" + + +enum { + ADD, + REMOVE, + NEED_RESIZE, + FOREACH, + FOCUS, + LAST_SIGNAL +}; + + +typedef void (*GtkContainerSignal1) (GtkObject *object, + gpointer arg1, + gpointer data); +typedef void (*GtkContainerSignal2) (GtkObject *object, + gpointer arg1, + gpointer arg2, + gpointer data); +typedef gint (*GtkContainerSignal3) (GtkObject *object, + gint arg1, + gpointer data); +typedef gint (*GtkContainerSignal4) (GtkObject *object, + gpointer data); + + +static void gtk_container_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_container_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_container_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_container_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + + +static void gtk_container_class_init (GtkContainerClass *klass); +static void gtk_container_init (GtkContainer *container); +static void gtk_container_arg (GtkContainer *container, + GtkArg *arg); +static gint gtk_real_container_need_resize (GtkContainer *container); +static gint gtk_real_container_focus (GtkContainer *container, + GtkDirectionType direction); +static gint gtk_container_focus_tab (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gint gtk_container_focus_up_down (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gint gtk_container_focus_left_right (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gint gtk_container_focus_move (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static void gtk_container_children_callback (GtkWidget *widget, + gpointer client_data); + + +static gint container_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_container_get_type () +{ + static guint container_type = 0; + + if (!container_type) + { + GtkTypeInfo container_info = + { + "GtkContainer", + sizeof (GtkContainer), + sizeof (GtkContainerClass), + (GtkClassInitFunc) gtk_container_class_init, + (GtkObjectInitFunc) gtk_container_init, + (GtkArgFunc) gtk_container_arg, + }; + + container_type = gtk_type_unique (gtk_widget_get_type (), &container_info); + } + + return container_type; +} + +static void +gtk_container_class_init (GtkContainerClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + gtk_object_add_arg_type ("GtkContainer::border_width", GTK_TYPE_LONG); + gtk_object_add_arg_type ("GtkContainer::auto_resize", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkContainer::block_resize", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkContainer::child", GTK_TYPE_WIDGET); + + container_signals[ADD] = + gtk_signal_new ("add", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, add), + gtk_container_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + container_signals[REMOVE] = + gtk_signal_new ("remove", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, remove), + gtk_container_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + container_signals[NEED_RESIZE] = + gtk_signal_new ("need_resize", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, need_resize), + gtk_container_marshal_signal_4, + GTK_TYPE_BOOL, 0, + GTK_TYPE_WIDGET); + container_signals[FOREACH] = + gtk_signal_new ("foreach", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, foreach), + gtk_container_marshal_signal_2, + GTK_TYPE_NONE, 1, + GTK_TYPE_C_CALLBACK); + container_signals[FOCUS] = + gtk_signal_new ("focus", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, focus), + gtk_container_marshal_signal_3, + GTK_TYPE_DIRECTION_TYPE, 1, + GTK_TYPE_DIRECTION_TYPE); + + gtk_object_class_add_signals (object_class, container_signals, LAST_SIGNAL); + + class->need_resize = gtk_real_container_need_resize; + class->focus = gtk_real_container_focus; +} + +static void +gtk_container_init (GtkContainer *container) +{ + container->focus_child = NULL; + container->border_width = 0; + container->auto_resize = TRUE; + container->need_resize = FALSE; + container->block_resize = FALSE; +} + +static void +gtk_container_arg (GtkContainer *container, + GtkArg *arg) +{ + if (strcmp (arg->name, "border_width") == 0) + { + gtk_container_border_width (container, GTK_VALUE_LONG (*arg)); + } + else if (strcmp (arg->name, "auto_resize") == 0) + { + if (GTK_VALUE_BOOL (*arg)) + gtk_container_enable_resize (container); + else + gtk_container_disable_resize (container); + } + else if (strcmp (arg->name, "block_resize") == 0) + { + if (GTK_VALUE_BOOL (*arg)) + gtk_container_block_resize (container); + else + gtk_container_unblock_resize (container); + } + else if (strcmp (arg->name, "child") == 0) + { + gtk_container_add (container, GTK_WIDGET (GTK_VALUE_OBJECT (*arg))); + } +} + +void +gtk_container_border_width (GtkContainer *container, + gint border_width) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (container->border_width != border_width) + { + container->border_width = border_width; + + if (container->widget.parent && GTK_WIDGET_VISIBLE (container)) + gtk_container_need_resize (GTK_CONTAINER (container->widget.parent)); + } +} + +void +gtk_container_add (GtkContainer *container, + GtkWidget *widget) +{ + gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget); +} + +void +gtk_container_remove (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (container->focus_child == widget) + container->focus_child = NULL; + + gtk_signal_emit (GTK_OBJECT (container), container_signals[REMOVE], widget); +} + +void +gtk_container_disable_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->auto_resize = FALSE; +} + +void +gtk_container_enable_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->auto_resize = TRUE; + if (container->need_resize) + { + container->need_resize = FALSE; + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +void +gtk_container_block_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->block_resize = TRUE; +} + +void +gtk_container_unblock_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->block_resize = FALSE; +} + +gint +gtk_container_need_resize (GtkContainer *container) +{ + gint return_val; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE); + + return_val = FALSE; + + if (!container->block_resize) + { + if (container->auto_resize) + gtk_signal_emit (GTK_OBJECT (container), + container_signals[NEED_RESIZE], + &return_val); + else + container->need_resize = TRUE; + } + + return return_val; +} + +void +gtk_container_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + gtk_signal_emit (GTK_OBJECT (container), + container_signals[FOREACH], + callback, callback_data); +} + +gint +gtk_container_focus (GtkContainer *container, + GtkDirectionType direction) +{ + gint return_val; + + gtk_signal_emit (GTK_OBJECT (container), + container_signals[FOCUS], + direction, &return_val); + + return return_val; +} + +GList* +gtk_container_children (GtkContainer *container) +{ + GList *children; + + children = NULL; + + gtk_container_foreach (container, + gtk_container_children_callback, + &children); + + return g_list_reverse (children); +} + + +static void +gtk_container_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal1 rfunc; + + rfunc = (GtkContainerSignal1) func; + + (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data); +} + +static void +gtk_container_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal2 rfunc; + + rfunc = (GtkContainerSignal2) func; + + (* rfunc) (object, + GTK_VALUE_C_CALLBACK(args[0]).func, + GTK_VALUE_C_CALLBACK(args[0]).func_data, + func_data); +} + +static void +gtk_container_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal3 rfunc; + gint *return_val; + + rfunc = (GtkContainerSignal3) func; + return_val = GTK_RETLOC_ENUM (args[1]); + + *return_val = (* rfunc) (object, GTK_VALUE_ENUM(args[0]), func_data); +} + +static void +gtk_container_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal4 rfunc; + gint *return_val; + + rfunc = (GtkContainerSignal4) func; + return_val = GTK_RETLOC_BOOL (args[0]); + + *return_val = (* rfunc) (object, func_data); +} + +static gint +gtk_real_container_need_resize (GtkContainer *container) +{ + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE); + + if (GTK_WIDGET_VISIBLE (container) && container->widget.parent) + return gtk_container_need_resize (GTK_CONTAINER (container->widget.parent)); + + return FALSE; +} + +static gint +gtk_real_container_focus (GtkContainer *container, + GtkDirectionType direction) +{ + GList *children; + GList *tmp_list; + GList *tmp_list2; + gint return_val; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE); + + /* Fail if the container is insensitive + */ + if (!GTK_WIDGET_SENSITIVE (container)) + return FALSE; + + return_val = FALSE; + + if (GTK_WIDGET_CAN_FOCUS (container)) + { + gtk_widget_grab_focus (GTK_WIDGET (container)); + return_val = TRUE; + } + else + { + /* Get a list of the containers children + */ + children = gtk_container_children (container); + + if (children) + { + /* Remove any children which are insensitive + */ + tmp_list = children; + while (tmp_list) + { + if (!GTK_WIDGET_SENSITIVE (tmp_list->data)) + { + tmp_list2 = tmp_list; + tmp_list = tmp_list->next; + + children = g_list_remove_link (children, tmp_list2); + g_list_free_1 (tmp_list2); + } + else + tmp_list = tmp_list->next; + } + + switch (direction) + { + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_TAB_BACKWARD: + return_val = gtk_container_focus_tab (container, children, direction); + break; + case GTK_DIR_UP: + case GTK_DIR_DOWN: + return_val = gtk_container_focus_up_down (container, children, direction); + break; + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + return_val = gtk_container_focus_left_right (container, children, direction); + break; + } + + g_list_free (children); + } + } + + return return_val; +} + +static gint +gtk_container_focus_tab (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *child; + GtkWidget *child2; + GList *tmp_list; + gint length; + gint i, j; + + length = g_list_length (children); + + /* sort the children in the y direction */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if (child->allocation.y < child2->allocation.y) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* sort the children in the x direction while + * maintaining the y direction sort. + */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if ((child->allocation.x < child2->allocation.x) && + (child->allocation.y >= child2->allocation.y)) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* if we are going backwards then reverse the order + * of the children. + */ + if (direction == GTK_DIR_TAB_BACKWARD) + children = g_list_reverse (children); + + return gtk_container_focus_move (container, children, direction); +} + +static gint +gtk_container_focus_up_down (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *child; + GtkWidget *child2; + GList *tmp_list; + gint dist1, dist2; + gint focus_x; + gint focus_width; + gint length; + gint i, j; + + /* return failure if there isn't a focus child */ + if (container->focus_child) + { + focus_width = container->focus_child->allocation.width / 2; + focus_x = container->focus_child->allocation.x + focus_width; + } + else + { + focus_width = GTK_WIDGET (container)->allocation.width; + if (GTK_WIDGET_NO_WINDOW (container)) + focus_x = GTK_WIDGET (container)->allocation.x; + else + focus_x = 0; + } + + length = g_list_length (children); + + /* sort the children in the y direction */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if (child->allocation.y < child2->allocation.y) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* sort the children in distance in the x direction + * in distance from the current focus child while maintaining the + * sort in the y direction + */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; + + while (j > 0) + { + child2 = tmp_list->prev->data; + dist2 = (child2->allocation.x + child2->allocation.width / 2) - focus_x; + + if ((dist1 < dist2) && + (child->allocation.y >= child2->allocation.y)) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* go and invalidate any widget which is too + * far from the focus widget. + */ + if (!container->focus_child && + (direction == GTK_DIR_UP)) + focus_x += focus_width; + + tmp_list = children; + while (tmp_list) + { + child = tmp_list->data; + + dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; + if (((direction == GTK_DIR_DOWN) && (dist1 < 0)) || + ((direction == GTK_DIR_UP) && (dist1 > 0))) + tmp_list->data = NULL; + + tmp_list = tmp_list->next; + } + + if (direction == GTK_DIR_UP) + children = g_list_reverse (children); + + return gtk_container_focus_move (container, children, direction); +} + +static gint +gtk_container_focus_left_right (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *child; + GtkWidget *child2; + GList *tmp_list; + gint dist1, dist2; + gint focus_y; + gint focus_height; + gint length; + gint i, j; + + /* return failure if there isn't a focus child */ + if (container->focus_child) + { + focus_height = container->focus_child->allocation.height / 2; + focus_y = container->focus_child->allocation.y + focus_height; + } + else + { + focus_height = GTK_WIDGET (container)->allocation.height; + if (GTK_WIDGET_NO_WINDOW (container)) + focus_y = GTK_WIDGET (container)->allocation.y; + else + focus_y = 0; + } + + length = g_list_length (children); + + /* sort the children in the x direction */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if (child->allocation.x < child2->allocation.x) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* sort the children in distance in the y direction + * in distance from the current focus child while maintaining the + * sort in the x direction + */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; + + while (j > 0) + { + child2 = tmp_list->prev->data; + dist2 = (child2->allocation.y + child2->allocation.height / 2) - focus_y; + + if ((dist1 < dist2) && + (child->allocation.x >= child2->allocation.x)) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* go and invalidate any widget which is too + * far from the focus widget. + */ + if (!container->focus_child && + (direction == GTK_DIR_LEFT)) + focus_y += focus_height; + + tmp_list = children; + while (tmp_list) + { + child = tmp_list->data; + + dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; + if (((direction == GTK_DIR_RIGHT) && (dist1 < 0)) || + ((direction == GTK_DIR_LEFT) && (dist1 > 0))) + tmp_list->data = NULL; + + tmp_list = tmp_list->next; + } + + if (direction == GTK_DIR_LEFT) + children = g_list_reverse (children); + + return gtk_container_focus_move (container, children, direction); +} + +static gint +gtk_container_focus_move (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *focus_child; + GtkWidget *child; + + focus_child = container->focus_child; + container->focus_child = NULL; + + while (children) + { + child = children->data; + children = children->next; + + if (!child) + continue; + + if (focus_child) + { + if (focus_child == child) + { + focus_child = NULL; + + if (GTK_WIDGET_VISIBLE (child) && + GTK_IS_CONTAINER (child) && + !GTK_WIDGET_HAS_FOCUS (child)) + if (gtk_container_focus (GTK_CONTAINER (child), direction)) + return TRUE; + } + } + else if (GTK_WIDGET_VISIBLE (child)) + { + if (GTK_WIDGET_CAN_FOCUS (child)) + { + gtk_widget_grab_focus (child); + return TRUE; + } + else if (GTK_IS_CONTAINER (child)) + { + if (gtk_container_focus (GTK_CONTAINER (child), direction)) + return TRUE; + } + } + } + + return FALSE; +} + + +static void +gtk_container_children_callback (GtkWidget *widget, + gpointer client_data) +{ + GList **children; + + children = (GList**) client_data; + *children = g_list_prepend (*children, widget); +} diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h new file mode 100644 index 0000000000..80c1ce0335 --- /dev/null +++ b/gtk/gtkcontainer.h @@ -0,0 +1,95 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_CONTAINER_H__ +#define __GTK_CONTAINER_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkenums.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CONTAINER(obj) GTK_CHECK_CAST (obj, gtk_container_get_type (), GtkContainer) +#define GTK_CONTAINER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_container_get_type, GtkContainerClass) +#define GTK_IS_CONTAINER(obj) GTK_CHECK_TYPE (obj, gtk_container_get_type ()) + +#define GTK_TYPE_CONTAINER (gtk_container_get_type ()) + +typedef struct _GtkContainer GtkContainer; +typedef struct _GtkContainerClass GtkContainerClass; + +struct _GtkContainer +{ + GtkWidget widget; + + GtkWidget *focus_child; + gint16 border_width; + guint auto_resize : 1; + guint need_resize : 1; + guint block_resize : 1; +}; + +struct _GtkContainerClass +{ + GtkWidgetClass parent_class; + + void (* add) (GtkContainer *container, + GtkWidget *widget); + void (* remove) (GtkContainer *container, + GtkWidget *widget); + gint (* need_resize) (GtkContainer *container); + void (* foreach) (GtkContainer *container, + GtkCallback callback, + gpointer callbabck_data); + gint (* focus) (GtkContainer *container, + GtkDirectionType direction); +}; + + + +guint gtk_container_get_type (void); +void gtk_container_border_width (GtkContainer *container, + gint border_width); +void gtk_container_add (GtkContainer *container, + GtkWidget *widget); +void gtk_container_remove (GtkContainer *container, + GtkWidget *widget); +void gtk_container_disable_resize (GtkContainer *container); +void gtk_container_enable_resize (GtkContainer *container); +void gtk_container_block_resize (GtkContainer *container); +void gtk_container_unblock_resize (GtkContainer *container); +gint gtk_container_need_resize (GtkContainer *container); +void gtk_container_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +gint gtk_container_focus (GtkContainer *container, + GtkDirectionType direction); +GList* gtk_container_children (GtkContainer *container); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CONTAINER_H__ */ diff --git a/gtk/gtkcurve.c b/gtk/gtkcurve.c new file mode 100644 index 0000000000..d2b6e08c84 --- /dev/null +++ b/gtk/gtkcurve.c @@ -0,0 +1,860 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1997 David Mosberger + * + * 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 <string.h> +#include <math.h> + +#include "gtkcurve.h" +#include "gtkdrawingarea.h" +#include "gtkmain.h" +#include "gtkradiobutton.h" +#include "gtksignal.h" +#include "gtktable.h" + +#define BOUNDS(a,x,y) (((a) < (x)) ? (x) : (((a) > (y)) ? (y) : (a))) +#define RADIUS 3 /* radius of the control points */ +#define MIN_DISTANCE 8 /* min distance between control points */ + +#define GRAPH_MASK (GDK_EXPOSURE_MASK | \ + GDK_POINTER_MOTION_MASK | \ + GDK_POINTER_MOTION_HINT_MASK | \ + GDK_ENTER_NOTIFY_MASK | \ + GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON_RELEASE_MASK | \ + GDK_BUTTON1_MOTION_MASK) + +static GtkDrawingAreaClass *parent_class = NULL; +static gint curve_type_changed_signal = 0; + + +/* forward declarations: */ +static void gtk_curve_class_init (GtkCurveClass *class); +static void gtk_curve_init (GtkCurve *curve); +static void gtk_curve_destroy (GtkObject *object); + + +guint +gtk_curve_get_type (void) +{ + static guint curve_type = 0; + + if (!curve_type) + { + GtkTypeInfo curve_info = + { + "GtkCurve", + sizeof (GtkCurve), + sizeof (GtkCurveClass), + (GtkClassInitFunc) gtk_curve_class_init, + (GtkObjectInitFunc) gtk_curve_init, + (GtkArgFunc) NULL, + }; + + curve_type = gtk_type_unique (gtk_drawing_area_get_type (), &curve_info); + } + return curve_type; +} + +static void +gtk_curve_class_init (GtkCurveClass *class) +{ + GtkObjectClass *object_class; + + parent_class = gtk_type_class (gtk_drawing_area_get_type ()); + + object_class = (GtkObjectClass *) class; + + curve_type_changed_signal = + gtk_signal_new ("curve_type_changed", GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCurveClass, curve_type_changed), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_object_class_add_signals (object_class, &curve_type_changed_signal, 1); + + object_class->destroy = gtk_curve_destroy; +} + +static void +gtk_curve_init (GtkCurve *curve) +{ + curve->cursor_type = GDK_TOP_LEFT_ARROW; + curve->pixmap = NULL; + curve->curve_type = GTK_CURVE_TYPE_SPLINE; + curve->height = 0; + curve->grab_point = -1; + + curve->num_points = 0; + curve->point = 0; + + curve->num_ctlpoints = 0; + curve->ctlpoint = NULL; +} + +static int +project (gfloat value, gfloat min, gfloat max, int norm) +{ + return (norm - 1) * ((value - min) / (max - min)) + 0.5; +} + +static gfloat +unproject (gint value, gfloat min, gfloat max, int norm) +{ + return value / (gfloat) (norm - 1) * (max - min) + min; +} + +/* Solve the tridiagonal equation system that determines the second + derivatives for the interpolation points. (Based on Numerical + Recipies 2nd Edition.) */ +static void +spline_solve (int n, gfloat x[], gfloat y[], gfloat y2[]) +{ + gfloat p, sig, *u; + gint i, k; + + u = g_malloc ((n - 1) * sizeof (u[0])); + + y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */ + + for (i = 1; i < n - 1; ++i) + { + sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); + p = sig * y2[i - 1] + 2.0; + y2[i] = (sig - 1.0) / p; + u[i] = ((y[i + 1] - y[i]) + / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1])); + u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; + } + + y2[n - 1] = 0.0; + for (k = n - 2; k >= 0; --k) + y2[k] = y2[k] * y2[k + 1] + u[k]; + + g_free (u); +} + +static gfloat +spline_eval (int n, gfloat x[], gfloat y[], gfloat y2[], gfloat val) +{ + gint k_lo, k_hi, k; + gfloat h, b, a; + + /* do a binary search for the right interval: */ + k_lo = 0; k_hi = n - 1; + while (k_hi - k_lo > 1) + { + k = (k_hi + k_lo) / 2; + if (x[k] > val) + k_hi = k; + else + k_lo = k; + } + + h = x[k_hi] - x[k_lo]; + g_assert (h > 0.0); + + a = (x[k_hi] - val) / h; + b = (val - x[k_lo]) / h; + return a*y[k_lo] + b*y[k_hi] + + ((a*a*a - a)*y2[k_lo] + (b*b*b - b)*y2[k_hi]) * (h*h)/6.0; +} + +static void +gtk_curve_interpolate (GtkCurve *c, gint width, gint height) +{ + gfloat *vector; + int i; + + vector = g_malloc (width * sizeof (vector[0])); + + gtk_curve_get_vector (c, width, vector); + + c->height = height; + if (c->num_points != width) + { + c->num_points = width; + if (c->point) + g_free (c->point); + c->point = g_malloc (c->num_points * sizeof (c->point[0])); + } + + for (i = 0; i < width; ++i) + { + c->point[i].x = RADIUS + i; + c->point[i].y = RADIUS + height + - project (vector[i], c->min_y, c->max_y, height); + } +} + +static void +gtk_curve_draw (GtkCurve *c, gint width, gint height) +{ + GtkStateType state; + GtkStyle *style; + gint i; + + if (!c->pixmap) + return; + + if (c->height != height || c->num_points != width) + gtk_curve_interpolate (c, width, height); + + state = GTK_STATE_NORMAL; + if (!GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (c))) + state = GTK_STATE_INSENSITIVE; + + style = GTK_WIDGET (c)->style; + + /* clear the pixmap: */ + gdk_draw_rectangle (c->pixmap, style->bg_gc[state], TRUE, + 0, 0, width + RADIUS * 2, height + RADIUS * 2); + + /* draw the grid lines: (XXX make more meaningful) */ + for (i = 0; i < 5; i++) + { + gdk_draw_line (c->pixmap, style->dark_gc[state], + RADIUS, i * (height / 4.0) + RADIUS, + width + RADIUS, i * (height / 4.0) + RADIUS); + gdk_draw_line (c->pixmap, style->dark_gc[state], + i * (width / 4.0) + RADIUS, RADIUS, + i * (width / 4.0) + RADIUS, height + RADIUS); + } + + gdk_draw_points (c->pixmap, style->fg_gc[state], c->point, c->num_points); + if (c->curve_type != GTK_CURVE_TYPE_FREE) + for (i = 0; i < c->num_ctlpoints; ++i) + { + gint x, y; + + if (c->ctlpoint[i][0] < c->min_x) + continue; + + x = project (c->ctlpoint[i][0], c->min_x, c->max_x, + width); + y = height - + project (c->ctlpoint[i][1], c->min_y, c->max_y, + height); + + /* draw a bullet: */ + gdk_draw_arc (c->pixmap, style->fg_gc[state], TRUE, x, y, + RADIUS * 2, RADIUS*2, 0, 360*64); + } + gdk_draw_pixmap (GTK_WIDGET (c)->window, style->fg_gc[state], c->pixmap, + 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2); +} + +static gint +gtk_curve_graph_events (GtkWidget *widget, GdkEvent *event, GtkCurve *c) +{ + GdkCursorType new_type = c->cursor_type; + gint i, src, dst, leftbound, rightbound; + GdkEventButton *bevent; + GdkEventMotion *mevent; + GtkWidget *w; + gint tx, ty; + gint cx, x, y, width, height; + gint closest_point = 0; + gfloat rx, ry, min_x; + guint distance; + gint x1, x2, y1, y2; + + w = GTK_WIDGET (c); + width = w->allocation.width - RADIUS * 2; + height = w->allocation.height - RADIUS * 2; + + /* get the pointer position */ + gdk_window_get_pointer (w->window, &tx, &ty, NULL); + x = BOUNDS ((tx - RADIUS), 0, width); + y = BOUNDS ((ty - RADIUS), 0, height); + + min_x = c->min_x; + + distance = ~0U; + for (i = 0; i < c->num_ctlpoints; ++i) + { + cx = project (c->ctlpoint[i][0], min_x, c->max_x, width); + if ((guint) abs (x - cx) < distance) + { + distance = abs (x - cx); + closest_point = i; + } + } + + switch (event->type) + { + case GDK_CONFIGURE: + if (c->pixmap) + gdk_pixmap_destroy (c->pixmap); + c->pixmap = 0; + /* fall through */ + case GDK_EXPOSE: + if (!c->pixmap) + c->pixmap = gdk_pixmap_new (w->window, + w->allocation.width, + w->allocation.height, -1); + gtk_curve_draw (c, width, height); + break; + + case GDK_BUTTON_PRESS: + gtk_grab_add (widget); + + bevent = (GdkEventButton *) event; + new_type = GDK_TCROSS; + + switch (c->curve_type) + { + case GTK_CURVE_TYPE_LINEAR: + case GTK_CURVE_TYPE_SPLINE: + if (distance > MIN_DISTANCE) + { + /* insert a new control point */ + if (c->num_ctlpoints > 0) + { + cx = project (c->ctlpoint[closest_point][0], min_x, + c->max_x, width); + if (x > cx) + ++closest_point; + } + ++c->num_ctlpoints; + c->ctlpoint = + g_realloc (c->ctlpoint, + c->num_ctlpoints * sizeof (*c->ctlpoint)); + for (i = c->num_ctlpoints - 1; i > closest_point; --i) + memcpy (c->ctlpoint + i, c->ctlpoint + i - 1, + sizeof (*c->ctlpoint)); + } + c->grab_point = closest_point; + c->ctlpoint[c->grab_point][0] = + unproject (x, min_x, c->max_x, width); + c->ctlpoint[c->grab_point][1] = + unproject (height - y, c->min_y, c->max_y, height); + + gtk_curve_interpolate (c, width, height); + break; + + case GTK_CURVE_TYPE_FREE: + c->point[x].x = RADIUS + x; + c->point[x].y = RADIUS + y; + c->grab_point = x; + c->last = y; + break; + } + gtk_curve_draw (c, width, height); + break; + + case GDK_BUTTON_RELEASE: + gtk_grab_remove (widget); + + /* delete inactive points: */ + if (c->curve_type != GTK_CURVE_TYPE_FREE) + { + for (src = dst = 0; src < c->num_ctlpoints; ++src) + { + if (c->ctlpoint[src][0] >= min_x) + { + memcpy (c->ctlpoint + dst, c->ctlpoint + src, + sizeof (*c->ctlpoint)); + ++dst; + } + } + if (dst < src) + { + c->num_ctlpoints -= (src - dst); + if (c->num_ctlpoints <= 0) + { + c->num_ctlpoints = 1; + c->ctlpoint[0][0] = min_x; + c->ctlpoint[0][1] = c->min_y; + gtk_curve_interpolate (c, width, height); + gtk_curve_draw (c, width, height); + } + c->ctlpoint = + g_realloc (c->ctlpoint, + c->num_ctlpoints * sizeof (*c->ctlpoint)); + } + } + new_type = GDK_FLEUR; + c->grab_point = -1; + break; + + case GDK_MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + if (mevent->is_hint) + { + mevent->x = tx; + mevent->y = ty; + } + switch (c->curve_type) + { + case GTK_CURVE_TYPE_LINEAR: + case GTK_CURVE_TYPE_SPLINE: + if (c->grab_point == -1) + { + /* if no point is grabbed... */ + if (distance <= MIN_DISTANCE) + new_type = GDK_FLEUR; + else + new_type = GDK_TCROSS; + } + else + { + /* drag the grabbed point */ + new_type = GDK_TCROSS; + + leftbound = -MIN_DISTANCE; + if (c->grab_point > 0) + leftbound = project (c->ctlpoint[c->grab_point - 1][0], + min_x, c->max_x, width); + + rightbound = width + RADIUS * 2 + MIN_DISTANCE; + if (c->grab_point + 1 < c->num_ctlpoints) + rightbound = project (c->ctlpoint[c->grab_point + 1][0], + min_x, c->max_x, width); + + if (tx <= leftbound || tx >= rightbound + || ty > height + RADIUS * 2 + MIN_DISTANCE + || ty < -MIN_DISTANCE) + c->ctlpoint[c->grab_point][0] = min_x - 1.0; + else + { + rx = unproject (x, min_x, c->max_x, width); + ry = unproject (height - y, c->min_y, c->max_y, height); + c->ctlpoint[c->grab_point][0] = rx; + c->ctlpoint[c->grab_point][1] = ry; + } + gtk_curve_interpolate (c, width, height); + gtk_curve_draw (c, width, height); + } + break; + + case GTK_CURVE_TYPE_FREE: + if (c->grab_point != -1) + { + if (c->grab_point > x) + { + x1 = x; + x2 = c->grab_point; + y1 = y; + y2 = c->last; + } + else + { + x1 = c->grab_point; + x2 = x; + y1 = c->last; + y2 = y; + } + + if (x2 != x1) + for (i = x1; i <= x2; i++) + { + c->point[i].x = RADIUS + i; + c->point[i].y = RADIUS + + (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1)); + } + else + { + c->point[x].x = RADIUS + x; + c->point[x].y = RADIUS + y; + } + c->grab_point = x; + c->last = y; + gtk_curve_draw (c, width, height); + } + if (mevent->state & GDK_BUTTON1_MASK) + new_type = GDK_TCROSS; + else + new_type = GDK_PENCIL; + break; + } + if (new_type != (GdkCursorType) c->cursor_type) + { + GdkCursor *cursor; + + c->cursor_type = new_type; + + cursor = gdk_cursor_new (c->cursor_type); + gdk_window_set_cursor (w->window, cursor); + gdk_cursor_destroy (cursor); + } + break; + + default: + break; + } + return FALSE; +} + +void +gtk_curve_set_curve_type (GtkCurve *c, GtkCurveType new_type) +{ + gfloat rx, dx; + gint x, i; + + if (new_type != c->curve_type) + { + gint width, height; + + width = GTK_WIDGET(c)->allocation.width - RADIUS * 2; + height = GTK_WIDGET(c)->allocation.height - RADIUS * 2; + + if (new_type == GTK_CURVE_TYPE_FREE) + { + gtk_curve_interpolate (c, width, height); + c->curve_type = new_type; + } + else if (c->curve_type == GTK_CURVE_TYPE_FREE) + { + if (c->ctlpoint) + g_free (c->ctlpoint); + c->num_ctlpoints = 9; + c->ctlpoint = g_malloc (c->num_ctlpoints * sizeof (*c->ctlpoint)); + + rx = 0.0; + dx = (width - 1) / (gfloat) (c->num_ctlpoints - 1); + + for (i = 0; i < c->num_ctlpoints; ++i, rx += dx) + { + x = (int) (rx + 0.5); + c->ctlpoint[i][0] = + unproject (x, c->min_x, c->max_x, width); + c->ctlpoint[i][1] = + unproject (RADIUS + height - c->point[x].y, + c->min_y, c->max_y, height); + } + c->curve_type = new_type; + gtk_curve_interpolate (c, width, height); + } + else + { + c->curve_type = new_type; + gtk_curve_interpolate (c, width, height); + } + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); + gtk_curve_draw (c, width, height); + } +} + +static void +gtk_curve_size_graph (GtkCurve *curve) +{ + gint width, height; + gfloat aspect; + + width = (curve->max_x - curve->min_x) + 1; + height = (curve->max_y - curve->min_y) + 1; + aspect = width / (gfloat) height; + if (width > gdk_screen_width () / 4) + width = gdk_screen_width () / 4; + if (height > gdk_screen_height () / 4) + height = gdk_screen_height () / 4; + + if (aspect < 1.0) + width = height * aspect; + else + height = width / aspect; + + gtk_drawing_area_size (GTK_DRAWING_AREA (curve), + width + RADIUS * 2, height + RADIUS * 2); +} + +static void +gtk_curve_reset_vector (GtkCurve *curve) +{ + if (curve->ctlpoint) + g_free (curve->ctlpoint); + + curve->num_ctlpoints = 2; + curve->ctlpoint = g_malloc (2 * sizeof (curve->ctlpoint[0])); + curve->ctlpoint[0][0] = curve->min_x; + curve->ctlpoint[0][1] = curve->min_y; + curve->ctlpoint[1][0] = curve->max_x; + curve->ctlpoint[1][1] = curve->max_y; + + if (curve->pixmap) + { + gint width, height; + + width = GTK_WIDGET (curve)->allocation.width - RADIUS * 2; + height = GTK_WIDGET (curve)->allocation.height - RADIUS * 2; + + if (curve->curve_type == GTK_CURVE_TYPE_FREE) + { + curve->curve_type = GTK_CURVE_TYPE_LINEAR; + gtk_curve_interpolate (curve, width, height); + curve->curve_type = GTK_CURVE_TYPE_FREE; + } + else + gtk_curve_interpolate (curve, width, height); + gtk_curve_draw (curve, width, height); + } +} + +void +gtk_curve_reset (GtkCurve *c) +{ + GtkCurveType old_type; + + old_type = c->curve_type; + c->curve_type = GTK_CURVE_TYPE_SPLINE; + gtk_curve_reset_vector (c); + + if (old_type != GTK_CURVE_TYPE_SPLINE) + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); +} + +void +gtk_curve_set_gamma (GtkCurve *c, gfloat gamma) +{ + gfloat x, one_over_gamma, height, one_over_width; + GtkCurveType old_type; + gint i; + + if (c->num_points < 2) + return; + + old_type = c->curve_type; + c->curve_type = GTK_CURVE_TYPE_FREE; + + if (gamma <= 0) + one_over_gamma = 1.0; + else + one_over_gamma = 1.0 / gamma; + one_over_width = 1.0 / (c->num_points - 1); + height = c->height; + for (i = 0; i < c->num_points; ++i) + { + x = (gfloat) i / (c->num_points - 1); + c->point[i].x = RADIUS + i; + c->point[i].y = + RADIUS + (height * (1.0 - pow (x, one_over_gamma)) + 0.5); + } + + if (old_type != GTK_CURVE_TYPE_FREE) + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); + + gtk_curve_draw (c, c->num_points, c->height); +} + +void +gtk_curve_set_range (GtkCurve *curve, + gfloat min_x, gfloat max_x, gfloat min_y, gfloat max_y) +{ + curve->min_x = min_x; + curve->max_x = max_x; + curve->min_y = min_y; + curve->max_y = max_y; + + gtk_curve_size_graph (curve); + gtk_curve_reset_vector (curve); +} + +void +gtk_curve_set_vector (GtkCurve *c, int veclen, gfloat vector[]) +{ + GtkCurveType old_type; + gfloat rx, dx, ry; + gint i, height; + + old_type = c->curve_type; + c->curve_type = GTK_CURVE_TYPE_FREE; + + if (c->point) + height = GTK_WIDGET (c)->allocation.height - RADIUS * 2; + else + { + height = (c->max_y - c->min_y); + if (height > gdk_screen_height () / 4) + height = gdk_screen_height () / 4; + + c->height = height; + c->num_points = veclen; + c->point = g_malloc (c->num_points * sizeof (c->point[0])); + } + rx = 0; + dx = (veclen - 1.0) / (c->num_points - 1.0); + + for (i = 0; i < c->num_points; ++i, rx += dx) + { + ry = vector[(int) (rx + 0.5)]; + if (ry > c->max_y) ry = c->max_y; + if (ry < c->min_y) ry = c->min_y; + c->point[i].x = RADIUS + i; + c->point[i].y = + RADIUS + height - project (ry, c->min_y, c->max_y, height); + } + if (old_type != GTK_CURVE_TYPE_FREE) + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); + + gtk_curve_draw (c, c->num_points, height); +} + +void +gtk_curve_get_vector (GtkCurve *c, int veclen, gfloat vector[]) +{ + gfloat rx, ry, dx, dy, min_x, delta_x, *mem, *xv, *yv, *y2v, prev; + gint dst, i, x, next, num_active_ctlpoints = 0, first_active = -1; + + min_x = c->min_x; + + if (c->curve_type != GTK_CURVE_TYPE_FREE) + { + /* count active points: */ + prev = min_x - 1.0; + for (i = num_active_ctlpoints = 0; i < c->num_ctlpoints; ++i) + if (c->ctlpoint[i][0] > prev) + { + if (first_active < 0) + first_active = i; + prev = c->ctlpoint[i][0]; + ++num_active_ctlpoints; + } + + /* handle degenerate case: */ + if (num_active_ctlpoints < 2) + { + if (num_active_ctlpoints > 0) + ry = c->ctlpoint[first_active][1]; + else + ry = c->min_y; + if (ry < c->min_y) ry = c->min_y; + if (ry > c->max_y) ry = c->max_y; + for (x = 0; x < veclen; ++x) + vector[x] = ry; + return; + } + } + + switch (c->curve_type) + { + case GTK_CURVE_TYPE_SPLINE: + mem = g_malloc (3 * num_active_ctlpoints * sizeof (gfloat)); + xv = mem; + yv = mem + num_active_ctlpoints; + y2v = mem + 2*num_active_ctlpoints; + + prev = min_x - 1.0; + for (i = dst = 0; i < c->num_ctlpoints; ++i) + if (c->ctlpoint[i][0] > prev) + { + prev = c->ctlpoint[i][0]; + xv[dst] = c->ctlpoint[i][0]; + yv[dst] = c->ctlpoint[i][1]; + ++dst; + } + + spline_solve (num_active_ctlpoints, xv, yv, y2v); + + rx = min_x; + dx = (c->max_x - min_x) / (veclen - 1); + for (x = 0; x < veclen; ++x, rx += dx) + { + ry = spline_eval (num_active_ctlpoints, xv, yv, y2v, rx); + if (ry < c->min_y) ry = c->min_y; + if (ry > c->max_y) ry = c->max_y; + vector[x] = ry; + } + + g_free (mem); + break; + + case GTK_CURVE_TYPE_LINEAR: + dx = (c->max_x - min_x) / (veclen - 1); + rx = min_x; + ry = c->min_y; + dy = 0.0; + i = first_active; + for (x = 0; x < veclen; ++x, rx += dx) + { + if (rx >= c->ctlpoint[i][0]) + { + if (rx > c->ctlpoint[i][0]) + ry = c->min_y; + dy = 0.0; + next = i + 1; + while (next < c->num_ctlpoints + && c->ctlpoint[next][0] <= c->ctlpoint[i][0]) + ++next; + if (next < c->num_ctlpoints) + { + delta_x = c->ctlpoint[next][0] - c->ctlpoint[i][0]; + dy = ((c->ctlpoint[next][1] - c->ctlpoint[i][1]) + / delta_x); + dy *= dx; + ry = c->ctlpoint[i][1]; + i = next; + } + } + vector[x] = ry; + ry += dy; + } + break; + + case GTK_CURVE_TYPE_FREE: + if (c->point) + { + rx = 0.0; + dx = c->num_points / (double) veclen; + for (x = 0; x < veclen; ++x, rx += dx) + vector[x] = unproject (RADIUS + c->height - c->point[(int) rx].y, + c->min_y, c->max_y, + c->height); + } + else + memset (vector, 0, veclen * sizeof (vector[0])); + break; + } +} + +GtkWidget* +gtk_curve_new (void) +{ + GtkCurve *curve; + gint old_mask; + + curve = gtk_type_new (gtk_curve_get_type ()); + curve->min_x = 0.0; + curve->max_x = 1.0; + curve->min_y = 0.0; + curve->max_y = 1.0; + + old_mask = gtk_widget_get_events (GTK_WIDGET (curve)); + gtk_widget_set_events (GTK_WIDGET (curve), old_mask | GRAPH_MASK); + gtk_signal_connect (GTK_OBJECT (curve), "event", + (GtkSignalFunc) gtk_curve_graph_events, curve); + gtk_curve_size_graph (curve); + + return GTK_WIDGET (curve); +} + +static void +gtk_curve_destroy (GtkObject *object) +{ + GtkCurve *curve; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_CURVE (object)); + + curve = GTK_CURVE (object); + if (curve->pixmap) + gdk_pixmap_destroy (curve->pixmap); + if (curve->point) + g_free (curve->point); + if (curve->ctlpoint) + g_free (curve->ctlpoint); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} diff --git a/gtk/gtkcurve.h b/gtk/gtkcurve.h new file mode 100644 index 0000000000..0e1568bc74 --- /dev/null +++ b/gtk/gtkcurve.h @@ -0,0 +1,96 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_CURVE_H__ +#define __GTK_CURVE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkdrawingarea.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CURVE(obj) GTK_CHECK_CAST (obj, gtk_curve_get_type (), GtkCurve) +#define GTK_CURVE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_curve_get_type, GtkCurveClass) +#define GTK_IS_CURVE(obj) GTK_CHECK_TYPE (obj, gtk_curve_get_type ()) + + +typedef struct _GtkCurve GtkCurve; +typedef struct _GtkCurveClass GtkCurveClass; + +typedef enum +{ + GTK_CURVE_TYPE_LINEAR, /* linear interpolation */ + GTK_CURVE_TYPE_SPLINE, /* spline interpolation */ + GTK_CURVE_TYPE_FREE /* free form curve */ +} GtkCurveType; + +struct _GtkCurve +{ + GtkDrawingArea graph; + + gint cursor_type; + gfloat min_x; + gfloat max_x; + gfloat min_y; + gfloat max_y; + GdkPixmap *pixmap; + GtkCurveType curve_type; + gint height; /* (cached) graph height in pixels */ + gint grab_point; /* point currently grabbed */ + gint last; + + /* (cached) curve points: */ + gint num_points; + GdkPoint *point; + + /* control points: */ + gint num_ctlpoints; /* number of control points */ + gfloat (*ctlpoint)[2]; /* array of control points */ +}; + +struct _GtkCurveClass +{ + GtkDrawingAreaClass parent_class; + + void (* curve_type_changed) (GtkCurve *curve); +}; + + +guint gtk_curve_get_type (void); +GtkWidget* gtk_curve_new (void); +void gtk_curve_reset (GtkCurve *curve); +void gtk_curve_set_gamma (GtkCurve *curve, gfloat gamma); +void gtk_curve_set_range (GtkCurve *curve, + gfloat min_x, gfloat max_x, + gfloat min_y, gfloat max_y); +void gtk_curve_get_vector (GtkCurve *curve, + int veclen, gfloat vector[]); +void gtk_curve_set_vector (GtkCurve *curve, + int veclen, gfloat vector[]); +void gtk_curve_set_curve_type (GtkCurve *curve, GtkCurveType type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CURVE_H__ */ diff --git a/gtk/gtkdata.c b/gtk/gtkdata.c new file mode 100644 index 0000000000..63add29f33 --- /dev/null +++ b/gtk/gtkdata.c @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkdata.h" +#include "gtksignal.h" + + +enum { + DISCONNECT, + LAST_SIGNAL +}; + + +static void gtk_data_class_init (GtkDataClass *klass); + + +static gint data_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_data_get_type () +{ + static guint data_type = 0; + + if (!data_type) + { + GtkTypeInfo data_info = + { + "GtkData", + sizeof (GtkData), + sizeof (GtkDataClass), + (GtkClassInitFunc) gtk_data_class_init, + (GtkObjectInitFunc) NULL, + (GtkArgFunc) NULL, + }; + + data_type = gtk_type_unique (gtk_object_get_type (), &data_info); + } + + return data_type; +} + +static void +gtk_data_class_init (GtkDataClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + data_signals[DISCONNECT] = + gtk_signal_new ("disconnect", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkDataClass, disconnect), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, data_signals, LAST_SIGNAL); +} diff --git a/gtk/gtkdata.h b/gtk/gtkdata.h new file mode 100644 index 0000000000..2e9d30b315 --- /dev/null +++ b/gtk/gtkdata.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_DATA_H__ +#define __GTK_DATA_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkobject.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_DATA(obj) GTK_CHECK_CAST (obj, gtk_data_get_type (), GtkData) +#define GTK_DATA_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_data_get_type (), GtkDataClass) +#define GTK_IS_DATA(obj) GTK_CHECK_TYPE (obj, gtk_data_get_type ()) + + +typedef struct _GtkData GtkData; +typedef struct _GtkDataClass GtkDataClass; + +struct _GtkData +{ + GtkObject object; +}; + +struct _GtkDataClass +{ + GtkObjectClass parent_class; + + void (* disconnect) (GtkData *data); +}; + + +guint gtk_data_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_DATA_H__ */ diff --git a/gtk/gtkdialog.c b/gtk/gtkdialog.c new file mode 100644 index 0000000000..55da2d1371 --- /dev/null +++ b/gtk/gtkdialog.c @@ -0,0 +1,80 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkbutton.h" +#include "gtkdialog.h" +#include "gtkhbox.h" +#include "gtkhseparator.h" +#include "gtkvbox.h" + + +static void gtk_dialog_class_init (GtkDialogClass *klass); +static void gtk_dialog_init (GtkDialog *dialog); + + +guint +gtk_dialog_get_type () +{ + static guint dialog_type = 0; + + if (!dialog_type) + { + GtkTypeInfo dialog_info = + { + "GtkDialog", + sizeof (GtkDialog), + sizeof (GtkDialogClass), + (GtkClassInitFunc) gtk_dialog_class_init, + (GtkObjectInitFunc) gtk_dialog_init, + (GtkArgFunc) NULL, + }; + + dialog_type = gtk_type_unique (gtk_window_get_type (), &dialog_info); + } + + return dialog_type; +} + +static void +gtk_dialog_class_init (GtkDialogClass *class) +{ +} + +static void +gtk_dialog_init (GtkDialog *dialog) +{ + GtkWidget *separator; + + dialog->vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox); + gtk_widget_show (dialog->vbox); + + dialog->action_area = gtk_hbox_new (TRUE, 5); + gtk_container_border_width (GTK_CONTAINER (dialog->action_area), 10); + gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area, FALSE, TRUE, 0); + gtk_widget_show (dialog->action_area); + + separator = gtk_hseparator_new (); + gtk_box_pack_end (GTK_BOX (dialog->vbox), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); +} + +GtkWidget* +gtk_dialog_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_dialog_get_type ())); +} diff --git a/gtk/gtkdialog.h b/gtk/gtkdialog.h new file mode 100644 index 0000000000..139699682b --- /dev/null +++ b/gtk/gtkdialog.h @@ -0,0 +1,64 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_DIALOG_H__ +#define __GTK_DIALOG_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwindow.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_DIALOG(obj) GTK_CHECK_CAST (obj, gtk_dialog_get_type (), GtkDialog) +#define GTK_DIALOG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dialog_get_type (), GtkDialogClass) +#define GTK_IS_DIALOG(obj) GTK_CHECK_TYPE (obj, gtk_dialog_get_type ()) + + +typedef struct _GtkDialog GtkDialog; +typedef struct _GtkDialogClass GtkDialogClass; +typedef struct _GtkDialogButton GtkDialogButton; + + +struct _GtkDialog +{ + GtkWindow window; + + GtkWidget *vbox; + GtkWidget *action_area; +}; + +struct _GtkDialogClass +{ + GtkWindowClass parent_class; +}; + + +guint gtk_dialog_get_type (void); +GtkWidget* gtk_dialog_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_DIALOG_H__ */ diff --git a/gtk/gtkdrawingarea.c b/gtk/gtkdrawingarea.c new file mode 100644 index 0000000000..3220446a5c --- /dev/null +++ b/gtk/gtkdrawingarea.c @@ -0,0 +1,146 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkdrawingarea.h" + + +static void gtk_drawing_area_class_init (GtkDrawingAreaClass *klass); +static void gtk_drawing_area_init (GtkDrawingArea *darea); +static void gtk_drawing_area_realize (GtkWidget *widget); +static void gtk_drawing_area_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_drawing_area_get_type () +{ + static guint drawing_area_type = 0; + + if (!drawing_area_type) + { + GtkTypeInfo drawing_area_info = + { + "GtkDrawingArea", + sizeof (GtkDrawingArea), + sizeof (GtkDrawingAreaClass), + (GtkClassInitFunc) gtk_drawing_area_class_init, + (GtkObjectInitFunc) gtk_drawing_area_init, + (GtkArgFunc) NULL, + }; + + drawing_area_type = gtk_type_unique (gtk_widget_get_type (), &drawing_area_info); + } + + return drawing_area_type; +} + +static void +gtk_drawing_area_class_init (GtkDrawingAreaClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_drawing_area_realize; + widget_class->size_allocate = gtk_drawing_area_size_allocate; +} + +static void +gtk_drawing_area_init (GtkDrawingArea *darea) +{ + GTK_WIDGET_SET_FLAGS (darea, GTK_BASIC); +} + + +GtkWidget* +gtk_drawing_area_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_drawing_area_get_type ())); +} + +void +gtk_drawing_area_size (GtkDrawingArea *darea, + gint width, + gint height) +{ + g_return_if_fail (darea != NULL); + g_return_if_fail (GTK_IS_DRAWING_AREA (darea)); + + GTK_WIDGET (darea)->requisition.width = width; + GTK_WIDGET (darea)->requisition.height = height; +} + +static void +gtk_drawing_area_realize (GtkWidget *widget) +{ + GtkDrawingArea *darea; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_DRAWING_AREA (widget)); + + darea = GTK_DRAWING_AREA (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, darea); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_drawing_area_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GdkEventConfigure event; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_DRAWING_AREA (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + event.type = GDK_CONFIGURE; + event.window = widget->window; + event.x = allocation->x; + event.y = allocation->y; + event.width = allocation->width; + event.height = allocation->height; + + gtk_widget_event (widget, (GdkEvent*) &event); + } +} diff --git a/gtk/gtkdrawingarea.h b/gtk/gtkdrawingarea.h new file mode 100644 index 0000000000..d11445b030 --- /dev/null +++ b/gtk/gtkdrawingarea.h @@ -0,0 +1,62 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_DRAWING_AREA_H__ +#define __GTK_DRAWING_AREA_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_DRAWING_AREA(obj) GTK_CHECK_CAST (obj, gtk_drawing_area_get_type (), GtkDrawingArea) +#define GTK_DRAWING_AREA_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_drawing_area_get_type (), GtkDrawingAreaClass) +#define GTK_IS_DRAWING_AREA(obj) GTK_CHECK_TYPE (obj, gtk_drawing_area_get_type ()) + + +typedef struct _GtkDrawingArea GtkDrawingArea; +typedef struct _GtkDrawingAreaClass GtkDrawingAreaClass; + +struct _GtkDrawingArea +{ + GtkWidget widget; +}; + +struct _GtkDrawingAreaClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_drawing_area_get_type (void); +GtkWidget* gtk_drawing_area_new (void); +void gtk_drawing_area_size (GtkDrawingArea *darea, + gint width, + gint height); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_DRAWING_AREA_H__ */ diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c new file mode 100644 index 0000000000..b9c25f63ac --- /dev/null +++ b/gtk/gtkentry.c @@ -0,0 +1,1678 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <ctype.h> +#include <string.h> +#include "gdk/gdkkeysyms.h" +#include "gtkentry.h" +#include "gtkmain.h" +#include "gtkselection.h" +#include "gtksignal.h" + +#define MIN_ENTRY_WIDTH 150 +#define DRAW_TIMEOUT 20 +#define INNER_BORDER 2 + + +enum { + INSERT_TEXT, + DELETE_TEXT, + CHANGED, + SET_TEXT, + ACTIVATE, + LAST_SIGNAL +}; + + +typedef void (*GtkTextFunction) (GtkEntry *entry); +typedef void (*GtkEntrySignal1) (GtkObject *object, + gpointer arg1, + gint arg2, + gpointer arg3, + gpointer data); +typedef void (*GtkEntrySignal2) (GtkObject *object, + gint arg1, + gint arg2, + gpointer data); + + +static void gtk_entry_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_entry_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + +static void gtk_entry_class_init (GtkEntryClass *klass); +static void gtk_entry_init (GtkEntry *entry); +static void gtk_entry_destroy (GtkObject *object); +static void gtk_entry_realize (GtkWidget *widget); +static void gtk_entry_unrealize (GtkWidget *widget); +static void gtk_entry_draw_focus (GtkWidget *widget); +static void gtk_entry_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_entry_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_entry_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_entry_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_entry_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_entry_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_entry_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_entry_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_entry_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_entry_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_entry_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +static void gtk_entry_selection_handler (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data); +static void gtk_entry_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data); +static void gtk_entry_draw_text (GtkEntry *entry); +static void gtk_entry_draw_cursor (GtkEntry *entry); +static void gtk_entry_queue_draw (GtkEntry *entry); +static gint gtk_entry_timer (gpointer data); +static gint gtk_entry_position (GtkEntry *entry, + gint x); + void gtk_entry_adjust_scroll (GtkEntry *entry); +static void gtk_entry_grow_text (GtkEntry *entry); +static void gtk_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos); +static void gtk_real_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_real_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos); + +static void gtk_move_forward_character (GtkEntry *entry); +static void gtk_move_backward_character (GtkEntry *entry); +static void gtk_move_forward_word (GtkEntry *entry); +static void gtk_move_backward_word (GtkEntry *entry); +static void gtk_move_beginning_of_line (GtkEntry *entry); +static void gtk_move_end_of_line (GtkEntry *entry); +static void gtk_delete_forward_character (GtkEntry *entry); +static void gtk_delete_backward_character (GtkEntry *entry); +static void gtk_delete_forward_word (GtkEntry *entry); +static void gtk_delete_backward_word (GtkEntry *entry); +static void gtk_delete_line (GtkEntry *entry); +static void gtk_delete_to_line_end (GtkEntry *entry); +static void gtk_delete_selection (GtkEntry *entry); +static void gtk_select_word (GtkEntry *entry); +static void gtk_select_line (GtkEntry *entry); +static void gtk_select_region (GtkEntry *entry, + gint start, + gint end); + + +static GtkWidgetClass *parent_class = NULL; +static gint entry_signals[LAST_SIGNAL] = { 0 }; + +static GtkTextFunction control_keys[26] = +{ + gtk_move_beginning_of_line, /* a */ + gtk_move_backward_character, /* b */ + NULL, /* c */ + gtk_delete_forward_character, /* d */ + gtk_move_end_of_line, /* e */ + gtk_move_forward_character, /* f */ + NULL, /* g */ + NULL, /* h */ + NULL, /* i */ + NULL, /* j */ + gtk_delete_to_line_end, /* k */ + NULL, /* l */ + NULL, /* m */ + NULL, /* n */ + NULL, /* o */ + NULL, /* p */ + NULL, /* q */ + NULL, /* r */ + NULL, /* s */ + NULL, /* t */ + gtk_delete_line, /* u */ + NULL, /* v */ + gtk_delete_backward_word, /* w */ + NULL, /* x */ + NULL, /* y */ + NULL, /* z */ +}; + +static GtkTextFunction alt_keys[26] = +{ + NULL, /* a */ + gtk_move_backward_word, /* b */ + NULL, /* c */ + gtk_delete_forward_word, /* d */ + NULL, /* e */ + gtk_move_forward_word, /* f */ + NULL, /* g */ + NULL, /* h */ + NULL, /* i */ + NULL, /* j */ + NULL, /* k */ + NULL, /* l */ + NULL, /* m */ + NULL, /* n */ + NULL, /* o */ + NULL, /* p */ + NULL, /* q */ + NULL, /* r */ + NULL, /* s */ + NULL, /* t */ + NULL, /* u */ + NULL, /* v */ + NULL, /* w */ + NULL, /* x */ + NULL, /* y */ + NULL, /* z */ +}; + + +guint +gtk_entry_get_type () +{ + static guint entry_type = 0; + + if (!entry_type) + { + GtkTypeInfo entry_info = + { + "GtkEntry", + sizeof (GtkEntry), + sizeof (GtkEntryClass), + (GtkClassInitFunc) gtk_entry_class_init, + (GtkObjectInitFunc) gtk_entry_init, + (GtkArgFunc) NULL, + }; + + entry_type = gtk_type_unique (gtk_widget_get_type (), &entry_info); + } + + return entry_type; +} + +static void +gtk_entry_class_init (GtkEntryClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + entry_signals[INSERT_TEXT] = + gtk_signal_new ("insert_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, insert_text), + gtk_entry_marshal_signal_1, + GTK_TYPE_NONE, 3, + GTK_TYPE_STRING, GTK_TYPE_INT, + GTK_TYPE_POINTER); + entry_signals[DELETE_TEXT] = + gtk_signal_new ("delete_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, delete_text), + gtk_entry_marshal_signal_2, + GTK_TYPE_NONE, 2, + GTK_TYPE_INT, GTK_TYPE_INT); + entry_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + entry_signals[SET_TEXT] = + gtk_signal_new ("set_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, set_text), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + entry_signals[ACTIVATE] = + gtk_signal_new ("activate", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, activate), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, entry_signals, LAST_SIGNAL); + + object_class->destroy = gtk_entry_destroy; + + widget_class->realize = gtk_entry_realize; + widget_class->unrealize = gtk_entry_unrealize; + widget_class->draw_focus = gtk_entry_draw_focus; + widget_class->size_request = gtk_entry_size_request; + widget_class->size_allocate = gtk_entry_size_allocate; + widget_class->draw = gtk_entry_draw; + widget_class->expose_event = gtk_entry_expose; + widget_class->button_press_event = gtk_entry_button_press; + widget_class->button_release_event = gtk_entry_button_release; + widget_class->motion_notify_event = gtk_entry_motion_notify; + widget_class->key_press_event = gtk_entry_key_press; + widget_class->focus_in_event = gtk_entry_focus_in; + widget_class->focus_out_event = gtk_entry_focus_out; + widget_class->selection_clear_event = gtk_entry_selection_clear; + widget_class->selection_received = gtk_entry_selection_received; + + class->insert_text = gtk_real_entry_insert_text; + class->delete_text = gtk_real_entry_delete_text; + class->changed = gtk_entry_adjust_scroll; + class->set_text = NULL; /* user defined handling */ + class->activate = NULL; /* user defined handling */ +} + +static void +gtk_entry_init (GtkEntry *entry) +{ + static GdkAtom text_atom = GDK_NONE; + + GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS); + + entry->text_area = NULL; + entry->text = NULL; + entry->text_size = 0; + entry->text_length = 0; + entry->current_pos = 0; + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + entry->scroll_offset = 0; + entry->have_selection = FALSE; + entry->timer = 0; + entry->visible = 1; + + gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, gtk_entry_selection_handler, + NULL, NULL); + + if (!text_atom) + text_atom = gdk_atom_intern ("TEXT", FALSE); + + gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY, + text_atom, + gtk_entry_selection_handler, + NULL, NULL); +} + +GtkWidget* +gtk_entry_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_entry_get_type ())); +} + +void +gtk_entry_set_text (GtkEntry *entry, + const gchar *text) +{ + gint tmp_pos; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + gtk_real_entry_delete_text (entry, 0, entry->text_length); + + tmp_pos = 0; + gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); + entry->current_pos = tmp_pos; + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + + if (GTK_WIDGET_DRAWABLE (entry)) + gtk_entry_draw_text (entry); + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); +} + +void +gtk_entry_append_text (GtkEntry *entry, + const gchar *text) +{ + gint tmp_pos; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + tmp_pos = entry->text_length; + gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); + entry->current_pos = tmp_pos; + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); +} + +void +gtk_entry_prepend_text (GtkEntry *entry, + const gchar *text) +{ + gint tmp_pos; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + tmp_pos = 0; + gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); + entry->current_pos = tmp_pos; + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); +} + +void +gtk_entry_set_position (GtkEntry *entry, + gint position) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if ((position == -1) || (position > entry->text_length)) + entry->current_pos = entry->text_length; + else + entry->current_pos = position; +} + +void +gtk_entry_set_visibility (GtkEntry *entry, + gint visible) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + entry->visible = visible; +} + +gchar* +gtk_entry_get_text (GtkEntry *entry) +{ + static char empty_str[2] = ""; + + g_return_val_if_fail (entry != NULL, NULL); + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + + if (!entry->text) + return empty_str; + return entry->text; +} + + +static void +gtk_entry_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkEntrySignal1 rfunc; + + rfunc = (GtkEntrySignal1) func; + + (* rfunc) (object, GTK_VALUE_STRING (args[0]), GTK_VALUE_INT (args[1]), + GTK_VALUE_POINTER (args[2]), func_data); +} + +static void +gtk_entry_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkEntrySignal2 rfunc; + + rfunc = (GtkEntrySignal2) func; + + (* rfunc) (object, GTK_VALUE_INT (args[0]), GTK_VALUE_INT (args[1]), + func_data); +} + +static void +gtk_entry_destroy (GtkObject *object) +{ + GtkEntry *entry; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_ENTRY (object)); + + entry = GTK_ENTRY (object); + + if (entry->have_selection) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); + + if (entry->timer) + gtk_timeout_remove (entry->timer); + + if (entry->text) + g_free (entry->text); + entry->text = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_entry_realize (GtkWidget *widget) +{ + GtkEntry *entry; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + entry = GTK_ENTRY (widget); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON3_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, entry); + + attributes.x = widget->style->klass->xthickness + INNER_BORDER; + attributes.y = widget->style->klass->ythickness + INNER_BORDER; + attributes.width = widget->allocation.width - attributes.x * 2; + attributes.height = widget->allocation.height - attributes.y * 2; + + entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (entry->text_area, entry); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_background (widget->window, &widget->style->white); + gdk_window_set_background (entry->text_area, &widget->style->white); + + gdk_window_show (entry->text_area); +} + +static void +gtk_entry_unrealize (GtkWidget *widget) +{ + GtkEntry *entry; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED); + entry = GTK_ENTRY (widget); + + gtk_style_detach (widget->style); + + if (entry->text_area) + { + gdk_window_set_user_data (entry->text_area, NULL); + gdk_window_destroy (entry->text_area); + } + if (widget->window) + { + gdk_window_set_user_data (widget->window, NULL); + gdk_window_destroy (widget->window); + } + + entry->text_area = NULL; + widget->window = NULL; +} + +static void +gtk_entry_draw_focus (GtkWidget *widget) +{ + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + x = 0; + y = 0; + gdk_window_get_size (widget->window, &width, &height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + else + { + gdk_draw_rectangle (widget->window, widget->style->white_gc, FALSE, + x + 2, y + 2, width - 5, height - 5); + } + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gdk_window_get_size (widget->window, &width, &height); + gdk_draw_rectangle (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, width - 1, height - 1); + } + + gtk_entry_draw_cursor (GTK_ENTRY (widget)); + } +} + +static void +gtk_entry_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + g_return_if_fail (requisition != NULL); + + requisition->width = MIN_ENTRY_WIDTH + (widget->style->klass->xthickness + INNER_BORDER) * 2; + requisition->height = (widget->style->font->ascent + + widget->style->font->descent + + (widget->style->klass->ythickness + INNER_BORDER) * 2); +} + +static void +gtk_entry_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkEntry *entry; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + entry = GTK_ENTRY (widget); + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, + allocation->y + (allocation->height - widget->requisition.height) / 2, + allocation->width, widget->requisition.height); + gdk_window_move_resize (entry->text_area, + widget->style->klass->xthickness + INNER_BORDER, + widget->style->klass->ythickness + INNER_BORDER, + allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2, + widget->requisition.height - (widget->style->klass->ythickness + INNER_BORDER) * 2); + + entry->scroll_offset = 0; + gtk_entry_adjust_scroll (entry); + } +} + +static void +gtk_entry_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_widget_draw_focus (widget); + gtk_entry_draw_text (GTK_ENTRY (widget)); + } +} + +static gint +gtk_entry_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + if (widget->window == event->window) + gtk_widget_draw_focus (widget); + else if (entry->text_area == event->window) + gtk_entry_draw_text (GTK_ENTRY (widget)); + + return FALSE; +} + +static gint +gtk_entry_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkEntry *entry; + gint tmp_pos; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if (event->button == 1) + { + switch (event->type) + { + case GDK_BUTTON_PRESS: + gtk_grab_add (widget); + + tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + gtk_select_region (entry, tmp_pos, tmp_pos); + entry->current_pos = entry->selection_start_pos; + gtk_entry_queue_draw (entry); + break; + + case GDK_2BUTTON_PRESS: + gtk_select_word (entry); + gtk_entry_queue_draw (entry); + break; + + case GDK_3BUTTON_PRESS: + gtk_select_line (entry); + gtk_entry_queue_draw (entry); + break; + + default: + break; + } + } + else if (event->type == GDK_BUTTON_PRESS) + { + if (event->button == 2) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->current_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, event->time); + } + else + { + gtk_grab_add (widget); + + tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + gtk_select_region (entry, tmp_pos, tmp_pos); + entry->have_selection = FALSE; + entry->current_pos = entry->selection_start_pos; + gtk_entry_queue_draw (entry); + } + } + + return FALSE; +} + +static gint +gtk_entry_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->button == 1) + { + entry = GTK_ENTRY (widget); + gtk_grab_remove (widget); + + entry->have_selection = FALSE; + if (entry->selection_start_pos != entry->selection_end_pos) + { + if (gtk_selection_owner_set (widget, + GDK_SELECTION_PRIMARY, + event->time)) + { + entry->have_selection = TRUE; + gtk_entry_queue_draw (entry); + } + } + else + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); + } + } + else if (event->button == 3) + { + gtk_grab_remove (widget); + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); + } + + return FALSE; +} + +static gint +gtk_entry_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkEntry *entry; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + x = event->x; + if (event->is_hint || (entry->text_area != event->window)) + gdk_window_get_pointer (entry->text_area, &x, NULL, NULL); + + entry->selection_end_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + entry->current_pos = entry->selection_end_pos; + gtk_entry_adjust_scroll (entry); + gtk_entry_queue_draw (entry); + + return FALSE; +} + +static gint +gtk_entry_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkEntry *entry; + gint return_val; + gint key; + gint tmp_pos; + gchar tmp; + gint extend_selection; + gint selection_pos; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + return_val = FALSE; + extend_selection = FALSE; + + if (entry->selection_start_pos == entry->selection_end_pos) + selection_pos = entry->current_pos; + else if (entry->selection_start_pos == entry->current_pos) + selection_pos = entry->selection_end_pos; + else + selection_pos = entry->selection_start_pos; + + switch (event->keyval) + { + case GDK_BackSpace: + return_val = TRUE; + if (entry->selection_start_pos != entry->selection_end_pos) + gtk_delete_selection (entry); + else if (event->state & GDK_CONTROL_MASK) + gtk_delete_backward_word (entry); + else + gtk_delete_backward_character (entry); + break; + case GDK_Clear: + return_val = TRUE; + gtk_delete_line (entry); + break; + case GDK_Insert: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + /* gtk_paste_clipboard(entry) -- NEEDS CLIPBOARD */ + } + else if (event->state & GDK_CONTROL_MASK) + { + /* gtk_copy_clipboard(entry) -- NEEDS CLIPBOARD */ + } + else + { + /* gtk_toggle_insert(entry) -- IMPLEMENT */ + } + break; + case GDK_Delete: + return_val = TRUE; + if (entry->selection_start_pos != entry->selection_end_pos) + gtk_delete_selection (entry); + else + { + if (event->state & GDK_CONTROL_MASK) + gtk_delete_line (entry); + else if (event->state & GDK_SHIFT_MASK) + /* gtk_cut_clipboard(entry) -- NEEDS CLIPBOARD */ ; + else + gtk_delete_forward_character (entry); + } + break; + case GDK_Home: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->current_pos; + entry->current_pos = entry->selection_end_pos = 0; + } + else + gtk_move_beginning_of_line (entry); + break; + case GDK_End: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->current_pos; + entry->current_pos = entry->selection_end_pos = entry->text_length; + } + else + gtk_move_end_of_line (entry); + break; + case GDK_Left: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->selection_end_pos = entry->current_pos; + if (entry->selection_end_pos > 0) + entry->current_pos = --entry->selection_end_pos; + } + else + gtk_move_backward_character (entry); + break; + case GDK_Right: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->selection_end_pos = entry->current_pos; + if (entry->selection_end_pos < entry->text_length) + entry->current_pos = ++entry->selection_end_pos; + } + else + gtk_move_forward_character (entry); + break; + case GDK_Return: + return_val = TRUE; + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[ACTIVATE]); + break; + default: + if ((event->keyval >= 0x20) && (event->keyval <= 0xFF)) + { + return_val = TRUE; + key = event->keyval; + + if (event->state & GDK_CONTROL_MASK) + { + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a']) + (* control_keys[key - 'a']) (entry); + } + else if (event->state & GDK_MOD1_MASK) + { + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a']) + (* alt_keys[key - 'a']) (entry); + } + else + { + tmp = (gchar) key; + gtk_delete_selection (entry); + + tmp_pos = entry->current_pos; + gtk_entry_insert_text (entry, &tmp, 1, &tmp_pos); + entry->current_pos = tmp_pos; + } + } + break; + } + + /* alex stuff */ + if (entry->selection_start_pos != entry->selection_end_pos) + { + if (gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time)) + { + entry->have_selection = TRUE; + gtk_entry_queue_draw (entry); + } + } + else + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); + } + /* end of alex stuff */ + + if (return_val) + { + gtk_entry_adjust_scroll (entry); + gtk_entry_queue_draw (entry); + } + + return return_val; +} + +static gint +gtk_entry_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_entry_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_entry_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + if (entry->have_selection) + { + entry->have_selection = FALSE; + gtk_entry_queue_draw (entry); + } + + return FALSE; +} + +static void +gtk_entry_selection_handler (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data) +{ + GtkEntry *entry; + gint selection_start_pos; + gint selection_end_pos; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + entry = GTK_ENTRY (widget); + + selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); + selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); + + gtk_selection_data_set (selection_data, + GDK_SELECTION_TYPE_STRING, + 8*sizeof(gchar), + &entry->text[selection_start_pos], + selection_end_pos - selection_start_pos); +} + +static void +gtk_entry_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data) +{ + GtkEntry *entry; + gint reselect; + gint tmp_pos; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + entry = GTK_ENTRY (widget); + + if (selection_data->length < 0) + return ; + + if (selection_data->target == GDK_TARGET_STRING) + { + reselect = FALSE; + if (entry->selection_start_pos != entry->selection_end_pos) + { + reselect = TRUE; + gtk_delete_selection (entry); + } + + tmp_pos = entry->current_pos; + + selection_data->data[selection_data->length] = 0; + gtk_entry_insert_text (entry, selection_data->data, + strlen (selection_data->data), &tmp_pos); + + if (reselect) + { + reselect = entry->have_selection; + gtk_select_region (entry, entry->current_pos, tmp_pos); + entry->have_selection = reselect; + } + + entry->current_pos = tmp_pos; + + gtk_entry_queue_draw (entry); + } +} + +static void +gtk_entry_draw_text (GtkEntry *entry) +{ + GtkWidget *widget; + GtkStateType selected_state; + gint selection_start_pos; + gint selection_end_pos; + gint selection_start_xoffset; + gint selection_end_xoffset; + gint width, height; + gint y; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (entry->timer) + { + gtk_timeout_remove (entry->timer); + entry->timer = 0; + } + + if (!entry->visible) + { + gtk_entry_draw_cursor (entry); + return; + } + + if (GTK_WIDGET_DRAWABLE (entry)) + { + widget = GTK_WIDGET (entry); + + gdk_window_clear (entry->text_area); + + if (entry->text) + { + gdk_window_get_size (entry->text_area, &width, &height); + y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2; + y += widget->style->font->ascent; + + if (entry->selection_start_pos != entry->selection_end_pos) + { + selected_state = GTK_STATE_SELECTED; + if (!entry->have_selection) + selected_state = GTK_STATE_ACTIVE; + + selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); + selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); + + selection_start_xoffset = gdk_text_width (widget->style->font, + entry->text, + selection_start_pos); + selection_end_xoffset = gdk_text_width (widget->style->font, + entry->text, + selection_end_pos); + + if (selection_start_pos > 0) + gdk_draw_text (entry->text_area, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + -entry->scroll_offset, y, + entry->text, selection_start_pos); + + gdk_draw_rectangle (entry->text_area, + widget->style->bg_gc[selected_state], + TRUE, + -entry->scroll_offset + selection_start_xoffset, + 0, + selection_end_xoffset - selection_start_xoffset, + -1); + + gdk_draw_text (entry->text_area, widget->style->font, + widget->style->fg_gc[selected_state], + -entry->scroll_offset + selection_start_xoffset, y, + entry->text + selection_start_pos, + selection_end_pos - selection_start_pos); + + if (selection_end_pos < entry->text_length) + gdk_draw_string (entry->text_area, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + -entry->scroll_offset + selection_end_xoffset, y, + entry->text + selection_end_pos); + } + else + { + GdkGCValues values; + + gdk_gc_get_values (widget->style->fg_gc[GTK_STATE_NORMAL], &values); + gdk_draw_string (entry->text_area, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + -entry->scroll_offset, y, + entry->text); + } + } + + gtk_entry_draw_cursor (entry); + } +} + +static void +gtk_entry_draw_cursor (GtkEntry *entry) +{ + GtkWidget *widget; + GdkGC *gc; + gint xoffset; + gint text_area_height; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (GTK_WIDGET_DRAWABLE (entry)) + { + widget = GTK_WIDGET (entry); + + if (entry->current_pos > 0 && entry->visible) + xoffset = gdk_text_width (widget->style->font, entry->text, entry->current_pos); + else + xoffset = 0; + xoffset -= entry->scroll_offset; + + if (GTK_WIDGET_HAS_FOCUS (widget) && + (entry->selection_start_pos == entry->selection_end_pos)) + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + else + gc = widget->style->white_gc; + + gdk_window_get_size (entry->text_area, &text_area_height, NULL); + gdk_draw_line (entry->text_area, gc, xoffset, 0, xoffset, text_area_height); + } +} + +static void +gtk_entry_queue_draw (GtkEntry *entry) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (!entry->timer) + entry->timer = gtk_timeout_add (DRAW_TIMEOUT, gtk_entry_timer, entry); +} + +static gint +gtk_entry_timer (gpointer data) +{ + GtkEntry *entry; + + g_return_val_if_fail (data != NULL, FALSE); + + entry = GTK_ENTRY (data); + entry->timer = 0; + gtk_entry_draw_text (entry); + + return FALSE; +} + +static gint +gtk_entry_position (GtkEntry *entry, + gint x) +{ + gint return_val; + gint char_width; + gint sum; + gint i; + + g_return_val_if_fail (entry != NULL, 0); + g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); + + i = 0; + sum = 0; + + if (x > sum) + { + for (; i < entry->text_length; i++) + { + char_width = gdk_char_width (GTK_WIDGET (entry)->style->font, entry->text[i]); + + if (x < (sum + char_width / 2)) + break; + sum += char_width; + } + } + + return_val = i; + + return return_val; +} + +void +gtk_entry_adjust_scroll (GtkEntry *entry) +{ + gint xoffset; + gint text_area_width; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (!entry->text_area) + return; + + gdk_window_get_size (entry->text_area, &text_area_width, NULL); + + if (entry->current_pos > 0) + xoffset = gdk_text_width (GTK_WIDGET (entry)->style->font, entry->text, entry->current_pos); + else + xoffset = 0; + xoffset -= entry->scroll_offset; + + if (xoffset < 0) + entry->scroll_offset += xoffset; + else if (xoffset > text_area_width) + entry->scroll_offset += (xoffset - text_area_width) + 1; +} + +static void +gtk_entry_grow_text (GtkEntry *entry) +{ + gint previous_size; + gint i; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + previous_size = entry->text_size; + if (!entry->text_size) + entry->text_size = 128; + else + entry->text_size *= 2; + entry->text = g_realloc (entry->text, entry->text_size); + + for (i = previous_size; i < entry->text_size; i++) + entry->text[i] = '\0'; +} + +static void +gtk_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + gchar buf[64]; + gchar *text; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (new_text_length <= 64) + text = buf; + else + text = g_new (gchar, new_text_length); + + strncpy (text, new_text, new_text_length); + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[INSERT_TEXT], + text, new_text_length, position); + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[CHANGED]); + + if (new_text_length > 64) + g_free (text); +} + +static void +gtk_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[DELETE_TEXT], + start_pos, end_pos); + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[CHANGED]); +} + +static void +gtk_real_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + gchar *text; + gint start_pos; + gint end_pos; + gint last_pos; + gint i; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + start_pos = *position; + end_pos = start_pos + new_text_length; + last_pos = new_text_length + entry->text_length; + + while (last_pos >= entry->text_size) + gtk_entry_grow_text (entry); + + text = entry->text; + for (i = last_pos - 1; i >= end_pos; i--) + text[i] = text[i- (end_pos - start_pos)]; + for (i = start_pos; i < end_pos; i++) + text[i] = new_text[i - start_pos]; + + entry->text_length += new_text_length; + *position = end_pos; +} + +static void +gtk_real_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos) +{ + gchar *text; + gint deletion_length; + gint i; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if ((start_pos < end_pos) && + (start_pos >= 0) && + (end_pos <= entry->text_length)) + { + text = entry->text; + deletion_length = end_pos - start_pos; + + for (i = end_pos; i < entry->text_length; i++) + text[i - deletion_length] = text[i]; + + for (i = entry->text_length - deletion_length; i < entry->text_length; i++) + text[i] = '\0'; + + entry->text_length -= deletion_length; + entry->current_pos = start_pos; + } +} + + +static void +gtk_move_forward_character (GtkEntry *entry) +{ + entry->current_pos += 1; + if (entry->current_pos > entry->text_length) + entry->current_pos = entry->text_length; + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_backward_character (GtkEntry *entry) +{ + entry->current_pos -= 1; + if (entry->current_pos < 0) + entry->current_pos = 0; + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_forward_word (GtkEntry *entry) +{ + gchar *text; + gint i; + + if (entry->text) + { + text = entry->text; + i = entry->current_pos; + + if (!((text[i] == '_') || isalnum (text[i]))) + for (; i < entry->text_length; i++) + if ((text[i] == '_') || isalnum (text[i])) + break; + + for (; i < entry->text_length; i++) + if (!((text[i] == '_') || isalnum (text[i]))) + break; + + entry->current_pos = i; + if (entry->current_pos > entry->text_length) + entry->current_pos = entry->text_length; + } + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_backward_word (GtkEntry *entry) +{ + gchar *text; + gint i; + + if (entry->text) + { + text = entry->text; + i = entry->current_pos - 1; + if (i < 0) /* Per */ + { + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + return; + } + + if (!((text[i] == '_') || isalnum (text[i]))) + for (; i >= 0; i--) + if ((text[i] == '_') || isalnum (text[i])) + break; + + for (; i >= 0; i--) + if (!((text[i] == '_') || isalnum (text[i]))) + { + i += 1; + break; + } + + entry->current_pos = i; + if (entry->current_pos < 0) + entry->current_pos = 0; + + if (text[entry->current_pos] == ' ') + entry->current_pos += 1; + } + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_beginning_of_line (GtkEntry *entry) +{ + entry->current_pos = 0; + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_end_of_line (GtkEntry *entry) +{ + entry->current_pos = entry->text_length; + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_forward_character (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_forward_character (entry); + gtk_entry_delete_text (entry, old_pos, entry->current_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_backward_character (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_backward_character (entry); + gtk_entry_delete_text (entry, entry->current_pos, old_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_forward_word (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_forward_word (entry); + gtk_entry_delete_text (entry, old_pos, entry->current_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_backward_word (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_backward_word (entry); + gtk_entry_delete_text (entry, entry->current_pos, old_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_line (GtkEntry *entry) +{ + gtk_entry_delete_text (entry, 0, entry->text_length); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_to_line_end (GtkEntry *entry) +{ + gtk_entry_delete_text (entry, entry->current_pos, entry->text_length); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_selection (GtkEntry *entry) +{ + if (entry->selection_start_pos != entry->selection_end_pos) + gtk_entry_delete_text (entry, + MIN (entry->selection_start_pos, entry->selection_end_pos), + MAX (entry->selection_start_pos, entry->selection_end_pos)); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + + if (entry->have_selection) + { + entry->have_selection = FALSE; + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); + } +} + +static void +gtk_select_word (GtkEntry *entry) +{ + gint start_pos; + gint end_pos; + + gtk_move_backward_word (entry); + start_pos = entry->current_pos; + + gtk_move_forward_word (entry); + end_pos = entry->current_pos; + + gtk_select_region (entry, start_pos, end_pos); +} + +static void +gtk_select_line (GtkEntry *entry) +{ + gtk_select_region (entry, 0, entry->text_length); + entry->current_pos = entry->selection_end_pos; +} + +static void +gtk_select_region (GtkEntry *entry, + gint start, + gint end) +{ + entry->have_selection = TRUE; + entry->selection_start_pos = start; + entry->selection_end_pos = end; +} diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h new file mode 100644 index 0000000000..c24bee6c87 --- /dev/null +++ b/gtk/gtkentry.h @@ -0,0 +1,94 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ENTRY_H__ +#define __GTK_ENTRY_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ENTRY(obj) GTK_CHECK_CAST (obj, gtk_entry_get_type (), GtkEntry) +#define GTK_ENTRY_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_entry_get_type (), GtkEntryClass) +#define GTK_IS_ENTRY(obj) GTK_CHECK_TYPE (obj, gtk_entry_get_type ()) + + +typedef struct _GtkEntry GtkEntry; +typedef struct _GtkEntryClass GtkEntryClass; + +struct _GtkEntry +{ + GtkWidget widget; + + GdkWindow *text_area; + gchar *text; + + guint16 text_size; + guint16 text_length; + gint16 current_pos; + gint16 selection_start_pos; + gint16 selection_end_pos; + gint16 scroll_offset; + guint have_selection : 1; + guint visible : 1; + guint32 timer; +}; + +struct _GtkEntryClass +{ + GtkWidgetClass parent_class; + + void (* insert_text) (GtkEntry *entry, + const gchar *text, + gint length, + gint *position); + void (* delete_text) (GtkEntry *entry, + gint start_pos, + gint end_pos); + void (* changed) (GtkEntry *entry); + void (* set_text) (GtkEntry *entry); + void (* activate) (GtkEntry *entry); +}; + + +guint gtk_entry_get_type (void); +GtkWidget* gtk_entry_new (void); +void gtk_entry_set_text (GtkEntry *entry, + const gchar *text); +void gtk_entry_append_text (GtkEntry *entry, + const gchar *text); +void gtk_entry_prepend_text (GtkEntry *entry, + const gchar *text); +void gtk_entry_set_position (GtkEntry *entry, + gint position); +gchar* gtk_entry_get_text (GtkEntry *entry); +void gtk_entry_set_visibility (GtkEntry *entry, + gint visible); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ENTRY_H__ */ diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h new file mode 100644 index 0000000000..b82d5e4974 --- /dev/null +++ b/gtk/gtkenums.h @@ -0,0 +1,191 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ENUMS_H__ +#define __GTK_ENUMS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Widget states */ +typedef enum +{ + GTK_STATE_NORMAL, + GTK_STATE_ACTIVE, + GTK_STATE_PRELIGHT, + GTK_STATE_SELECTED, + GTK_STATE_INSENSITIVE +} GtkStateType; + +/* Window types */ +typedef enum +{ + GTK_WINDOW_TOPLEVEL, + GTK_WINDOW_DIALOG, + GTK_WINDOW_POPUP +} GtkWindowType; + +/* Focus movement types */ +typedef enum +{ + GTK_DIR_TAB_FORWARD, + GTK_DIR_TAB_BACKWARD, + GTK_DIR_UP, + GTK_DIR_DOWN, + GTK_DIR_LEFT, + GTK_DIR_RIGHT +} GtkDirectionType; + +/* Shadow types */ +typedef enum +{ + GTK_SHADOW_NONE, + GTK_SHADOW_IN, + GTK_SHADOW_OUT, + GTK_SHADOW_ETCHED_IN, + GTK_SHADOW_ETCHED_OUT +} GtkShadowType; + +/* Arrow types */ +typedef enum +{ + GTK_ARROW_UP, + GTK_ARROW_DOWN, + GTK_ARROW_LEFT, + GTK_ARROW_RIGHT +} GtkArrowType; + +/* Packing types (for boxes) */ +typedef enum +{ + GTK_PACK_START, + GTK_PACK_END +} GtkPackType; + +/* Scrollbar policy types (for scrolled windows) */ +typedef enum +{ + GTK_POLICY_ALWAYS, + GTK_POLICY_AUTOMATIC +} GtkPolicyType; + +/* Data update types (for ranges) */ +typedef enum +{ + GTK_UPDATE_CONTINUOUS, + GTK_UPDATE_DISCONTINUOUS, + GTK_UPDATE_DELAYED +} GtkUpdateType; + +/* Attach options (for tables) */ +typedef enum +{ + GTK_EXPAND = 1 << 0, + GTK_SHRINK = 1 << 1, + GTK_FILL = 1 << 2 +} GtkAttachOptions; + +typedef enum +{ + GTK_RUN_FIRST = 0x1, + GTK_RUN_LAST = 0x2, + GTK_RUN_BOTH = 0x3, + GTK_RUN_MASK = 0xF, + GTK_RUN_NO_RECURSE = 0x10 +} GtkSignalRunType; + +typedef enum +{ + GTK_WIN_POS_NONE, + GTK_WIN_POS_CENTER, + GTK_WIN_POS_MOUSE +} GtkWindowPosition; + +typedef enum +{ + GTK_DIRECTION_LEFT, + GTK_DIRECTION_RIGHT +} GtkSubmenuDirection; + +typedef enum +{ + GTK_TOP_BOTTOM, + GTK_LEFT_RIGHT +} GtkSubmenuPlacement; + +typedef enum +{ + GTK_MENU_FACTORY_MENU, + GTK_MENU_FACTORY_MENU_BAR, + GTK_MENU_FACTORY_OPTION_MENU +} GtkMenuFactoryType; + +typedef enum +{ + GTK_PIXELS, + GTK_INCHES, + GTK_CENTIMETERS +} GtkMetricType; + +typedef enum +{ + GTK_SCROLL_NONE, + GTK_SCROLL_STEP_BACKWARD, + GTK_SCROLL_STEP_FORWARD, + GTK_SCROLL_PAGE_BACKWARD, + GTK_SCROLL_PAGE_FORWARD +} GtkScrollType; + +typedef enum +{ + GTK_TROUGH_NONE, + GTK_TROUGH_START, + GTK_TROUGH_END +} GtkTroughType; + +typedef enum +{ + GTK_POS_LEFT, + GTK_POS_RIGHT, + GTK_POS_TOP, + GTK_POS_BOTTOM +} GtkPositionType; + +typedef enum +{ + GTK_PREVIEW_COLOR, + GTK_PREVIEW_GRAYSCALE +} GtkPreviewType; + +/* justification for label and maybe other widgets (text?) */ +typedef enum +{ + GTK_JUSTIFY_LEFT, + GTK_JUSTIFY_RIGHT, + GTK_JUSTIFY_CENTER, + GTK_JUSTIFY_FILL +} GtkJustification; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ENUMS_H__ */ diff --git a/gtk/gtkeventbox.c b/gtk/gtkeventbox.c new file mode 100644 index 0000000000..44a0d7a9a7 --- /dev/null +++ b/gtk/gtkeventbox.c @@ -0,0 +1,226 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtksignal.h" +#include "gtkeventbox.h" + + +static void gtk_event_box_class_init (GtkEventBoxClass *klass); +static void gtk_event_box_init (GtkEventBox *event_box); +static void gtk_event_box_realize (GtkWidget *widget); +static void gtk_event_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_event_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_event_box_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_event_box_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_event_box_get_type () +{ + static guint event_box_type = 0; + + if (!event_box_type) + { + GtkTypeInfo event_box_info = + { + "GtkEventBox", + sizeof (GtkEventBox), + sizeof (GtkEventBoxClass), + (GtkClassInitFunc) gtk_event_box_class_init, + (GtkObjectInitFunc) gtk_event_box_init, + (GtkArgFunc) NULL, + }; + + event_box_type = gtk_type_unique (gtk_bin_get_type (), &event_box_info); + } + + return event_box_type; +} + +static void +gtk_event_box_class_init (GtkEventBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_event_box_realize; + widget_class->size_request = gtk_event_box_size_request; + widget_class->size_allocate = gtk_event_box_size_allocate; + widget_class->draw = gtk_event_box_draw; + widget_class->expose_event = gtk_event_box_expose; +} + +static void +gtk_event_box_init (GtkEventBox *event_box) +{ + GTK_WIDGET_UNSET_FLAGS (event_box, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (event_box, GTK_BASIC); +} + +GtkWidget* +gtk_event_box_new () +{ + return GTK_WIDGET ( gtk_type_new (gtk_event_box_get_type ())); +} + +static void +gtk_event_box_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_EXPOSURE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_event_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + g_return_if_fail (requisition != NULL); + + bin = GTK_BIN (widget); + + requisition->width = GTK_CONTAINER (widget)->border_width * 2; + requisition->height = GTK_CONTAINER (widget)->border_width * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_event_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + bin = GTK_BIN (widget); + + child_allocation.x = 0; + child_allocation.y = 0; + child_allocation.width = allocation->width - GTK_CONTAINER (widget)->border_width * 2; + child_allocation.height = allocation->height - GTK_CONTAINER (widget)->border_width * 2; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + GTK_CONTAINER (widget)->border_width, + allocation->y + GTK_CONTAINER (widget)->border_width, + child_allocation.width, + child_allocation.height); + } + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static void +gtk_event_box_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + if (bin->child) + { + if (gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } + } +} + +static gint +gtk_event_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_EVENT_BOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + diff --git a/gtk/gtkeventbox.h b/gtk/gtkeventbox.h new file mode 100644 index 0000000000..d90213dee3 --- /dev/null +++ b/gtk/gtkeventbox.h @@ -0,0 +1,57 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_EVENT_BOX_H__ +#define __GTK_EVENT_BOX_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbin.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_EVENT_BOX(obj) GTK_CHECK_CAST (obj, gtk_event_box_get_type (), GtkEventBox) +#define GTK_EVENT_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_event_box_get_type (), GtkEventBoxClass) +#define GTK_IS_EVENT_BOX(obj) GTK_CHECK_TYPE (obj, gtk_event_box_get_type ()) + + +typedef struct _GtkEventBox GtkEventBox; +typedef struct _GtkEventBoxClass GtkEventBoxClass; + +struct _GtkEventBox +{ + GtkBin bin; +}; + +struct _GtkEventBoxClass +{ + GtkBinClass parent_class; +}; + +guint gtk_event_box_get_type (void); +GtkWidget* gtk_event_box_new (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_EVENT_BOX_H__ */ diff --git a/gtk/gtkfilesel.c b/gtk/gtkfilesel.c new file mode 100644 index 0000000000..77f83a87a3 --- /dev/null +++ b/gtk/gtkfilesel.c @@ -0,0 +1,2161 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <dirent.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#include "fnmatch.h" + +#include "gdk/gdkkeysyms.h" +#include "gtkbutton.h" +#include "gtkentry.h" +#include "gtkfilesel.h" +#include "gtkhbox.h" +#include "gtklabel.h" +#include "gtklist.h" +#include "gtklistitem.h" +#include "gtkmain.h" +#include "gtkscrolledwindow.h" +#include "gtksignal.h" +#include "gtkvbox.h" + + +#define DIR_LIST_WIDTH 160 +#define DIR_LIST_HEIGHT 175 +#define FILE_LIST_WIDTH 160 +#define FILE_LIST_HEIGHT 175 + + +typedef struct _CompletionState CompletionState; +typedef struct _CompletionDir CompletionDir; +typedef struct _CompletionDirSent CompletionDirSent; +typedef struct _CompletionDirEntry CompletionDirEntry; +typedef struct _CompletionUserDir CompletionUserDir; +typedef struct _PossibleCompletion PossibleCompletion; + +/* Non-external file completion decls and structures */ + +/* A contant telling PRCS how many directories to cache. Its actually + * kept in a list, so the geometry isn't important. */ +#define CMPL_DIRECTORY_CACHE_SIZE 10 + +/* A constant used to determine whether a substring was an exact + * match by first_diff_index() + */ +#define PATTERN_MATCH -1 +/* The arguments used by all fnmatch() calls below + */ +#define FNMATCH_FLAGS (FNM_PATHNAME | FNM_PERIOD) + +#define CMPL_ERRNO_TOO_LONG ((1<<16)-1) + +/* This structure contains all the useful information about a directory + * for the purposes of filename completion. These structures are cached + * in the CompletionState struct. CompletionDir's are reference counted. + */ +struct _CompletionDirSent +{ + ino_t inode; + time_t mtime; + + gint entry_count; + gchar *name_buffer; /* memory segment containing names of all entries */ + + struct _CompletionDirEntry *entries; +}; + +struct _CompletionDir +{ + CompletionDirSent *sent; + + gchar *fullname; + gint fullname_len; + + struct _CompletionDir *cmpl_parent; + gint cmpl_index; + gchar *cmpl_text; +}; + +/* This structure contains pairs of directory entry names with a flag saying + * whether or not they are a valid directory. NOTE: This information is used + * to provide the caller with information about whether to update its completions + * or try to open a file. Since directories are cached by the directory mtime, + * a symlink which points to an invalid file (which will not be a directory), + * will not be reevaluated if that file is created, unless the containing + * directory is touched. I consider this case to be worth ignoring (josh). + */ +struct _CompletionDirEntry +{ + gint is_dir; + gchar *entry_name; +}; + +struct _CompletionUserDir +{ + gchar *login; + gchar *homedir; +}; + +struct _PossibleCompletion +{ + /* accessible fields, all are accessed externally by functions + * declared above + */ + gchar *text; + gint is_a_completion; + gint is_directory; + + /* Private fields + */ + gint text_alloc; +}; + +struct _CompletionState +{ + gint last_valid_char; + gchar *updated_text; + gint updated_text_len; + gint updated_text_alloc; + gint re_complete; + + gchar *user_dir_name_buffer; + gint user_directories_len; + gchar *user_home_dir; + + gchar *last_completion_text; + + gint user_completion_index; /* if >= 0, currently completing ~user */ + + struct _CompletionDir *completion_dir; /* directory completing from */ + struct _CompletionDir *active_completion_dir; + + struct _PossibleCompletion the_completion; + + struct _CompletionDir *reference_dir; /* initial directory */ + + GList* directory_storage; + GList* directory_sent_storage; + + struct _CompletionUserDir *user_directories; +}; + + +/* File completion functions which would be external, were they used + * outside of this file. + */ + +static CompletionState* cmpl_init_state (void); +static void cmpl_free_state (CompletionState *cmpl_state); +static gint cmpl_state_okay (CompletionState* cmpl_state); +static gchar* cmpl_strerror (gint); + +static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete, + gchar **remaining_text, + CompletionState *cmpl_state); + +/* Returns a name for consideration, possibly a completion, this name + * will be invalid after the next call to cmpl_next_completion. + */ +static char* cmpl_this_completion (PossibleCompletion*); + +/* True if this completion matches the given text. Otherwise, this + * output can be used to have a list of non-completions. + */ +static gint cmpl_is_a_completion (PossibleCompletion*); + +/* True if the completion is a directory + */ +static gint cmpl_is_directory (PossibleCompletion*); + +/* Obtains the next completion, or NULL + */ +static PossibleCompletion* cmpl_next_completion (CompletionState*); + +/* Updating completions: the return value of cmpl_updated_text() will + * be text_to_complete completed as much as possible after the most + * recent call to cmpl_completion_matches. For the present + * application, this is the suggested replacement for the user's input + * string. You must CALL THIS AFTER ALL cmpl_text_completions have + * been received. + */ +static gchar* cmpl_updated_text (CompletionState* cmpl_state); + +/* After updating, to see if the completion was a directory, call + * this. If it was, you should consider re-calling completion_matches. + */ +static gint cmpl_updated_dir (CompletionState* cmpl_state); + +/* Current location: if using file completion, return the current + * directory, from which file completion begins. More specifically, + * the cwd concatenated with all exact completions up to the last + * directory delimiter('/'). + */ +static gchar* cmpl_reference_position (CompletionState* cmpl_state); + +/* backing up: if cmpl_completion_matches returns NULL, you may query + * the index of the last completable character into cmpl_updated_text. + */ +static gint cmpl_last_valid_char (CompletionState* cmpl_state); + +/* When the user selects a non-directory, call cmpl_completion_fullname + * to get the full name of the selected file. + */ +static gchar* cmpl_completion_fullname (gchar*, CompletionState* cmpl_state); + + +/* Directory operations. */ +static CompletionDir* open_ref_dir (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static CompletionDir* open_dir (gchar* dir_name, + CompletionState* cmpl_state); +static CompletionDir* open_user_dir (gchar* text_to_complete, + CompletionState *cmpl_state); +static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, + CompletionState *cmpl_state); +static CompletionDirSent* open_new_dir (gchar* dir_name, struct stat* sbuf); +static gint correct_dir_fullname (CompletionDir* cmpl_dir); +static gint correct_parent (CompletionDir* cmpl_dir, + struct stat *sbuf); +static gchar* find_parent_dir_fullname (gchar* dirname); +static CompletionDir* attach_dir (CompletionDirSent* sent, + gchar* dir_name, + CompletionState *cmpl_state); +static void free_dir_sent (CompletionDirSent* sent); +static void free_dir (CompletionDir *dir); +static void prune_memory_usage(CompletionState *cmpl_state); + +/* Completion operations */ +static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state); +static PossibleCompletion* attempt_file_completion(CompletionState *cmpl_state); +static CompletionDir* find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static PossibleCompletion* append_completion_text(gchar* text, + CompletionState* cmpl_state); +static gint get_pwdb(CompletionState* cmpl_state); +static gint first_diff_index(gchar* pat, gchar* text); +static gint compare_user_dir(const void* a, const void* b); +static gint compare_cmpl_dir(const void* a, const void* b); +static void update_cmpl(PossibleCompletion* poss, + CompletionState* cmpl_state); + +static void gtk_file_selection_class_init (GtkFileSelectionClass *klass); +static void gtk_file_selection_init (GtkFileSelection *filesel); +static void gtk_file_selection_destroy (GtkObject *object); +static gint gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); +static gint gtk_file_selection_file_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); +static gint gtk_file_selection_dir_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); +static void gtk_file_selection_file_list_changed (GtkList *gtklist, + gpointer func_data); +static void gtk_file_selection_dir_list_changed (GtkList *gtklist, + gpointer func_data); +static void gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete); +static void gtk_file_selection_abort (GtkFileSelection *fs); +static void gtk_file_selection_free_filename (GtkWidget *widget, + gpointer client_data); + + +static GtkWindowClass *parent_class = NULL; + +static gchar *list_changed_key = "_gtk_selection_changed_handler_key"; + +/* Saves errno when something cmpl does fails. */ +static gint cmpl_errno; + + +guint +gtk_file_selection_get_type () +{ + static guint file_selection_type = 0; + + if (!file_selection_type) + { + GtkTypeInfo filesel_info = + { + "GtkFileSelection", + sizeof (GtkFileSelection), + sizeof (GtkFileSelectionClass), + (GtkClassInitFunc) gtk_file_selection_class_init, + (GtkObjectInitFunc) gtk_file_selection_init, + (GtkArgFunc) NULL, + }; + + file_selection_type = gtk_type_unique (gtk_window_get_type (), &filesel_info); + } + + return file_selection_type; +} + +static void +gtk_file_selection_class_init (GtkFileSelectionClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + parent_class = gtk_type_class (gtk_window_get_type ()); + + object_class->destroy = gtk_file_selection_destroy; +} + +static void +gtk_file_selection_init (GtkFileSelection *filesel) +{ + GtkWidget *dir_vbox; + GtkWidget *file_vbox; + GtkWidget *entry_vbox; + GtkWidget *listbox; + GtkWidget *label; + GtkWidget *list_hbox; + GtkWidget *action_area; + gint key; + + filesel->cmpl_state = cmpl_init_state (); + + /* The dialog-sized vertical box */ + filesel->main_vbox = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (filesel), 10); + gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox); + gtk_widget_show (filesel->main_vbox); + + /* The horizontal box containing the directory and file listboxes */ + list_hbox = gtk_hbox_new (TRUE, 5); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), list_hbox, TRUE, TRUE, 0); + gtk_widget_show (list_hbox); + + + /* The directories listbox */ + dir_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (list_hbox), dir_vbox, TRUE, TRUE, 0); + gtk_widget_show (dir_vbox); + + label = gtk_label_new ("Directories"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (dir_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + listbox = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (listbox), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (dir_vbox), listbox, TRUE, TRUE, 0); + gtk_widget_set_usize (listbox, DIR_LIST_WIDTH, DIR_LIST_HEIGHT); + gtk_widget_show (listbox); + + filesel->dir_list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (filesel->dir_list), GTK_SELECTION_BROWSE); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "button_press_event", + (GtkSignalFunc) gtk_file_selection_dir_button, filesel); + key = gtk_signal_connect (GTK_OBJECT (filesel->dir_list), + "selection_changed", + (GtkSignalFunc) gtk_file_selection_dir_list_changed, + filesel); + gtk_object_set_data (GTK_OBJECT (filesel->dir_list), list_changed_key, (gpointer) key); + gtk_container_add (GTK_CONTAINER (listbox), filesel->dir_list); + gtk_widget_show (filesel->dir_list); + + + /* The files listbox */ + file_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (list_hbox), file_vbox, TRUE, TRUE, 0); + gtk_widget_show (file_vbox); + + label = gtk_label_new ("Files"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (file_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + listbox = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (listbox), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (file_vbox), listbox, TRUE, TRUE, 0); + gtk_widget_set_usize (listbox, FILE_LIST_WIDTH, FILE_LIST_HEIGHT); + gtk_widget_show (listbox); + + filesel->file_list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (filesel->file_list), GTK_SELECTION_BROWSE); + gtk_signal_connect (GTK_OBJECT (filesel->file_list), "button_press_event", + (GtkSignalFunc) gtk_file_selection_file_button, filesel); + key = gtk_signal_connect (GTK_OBJECT (filesel->file_list), + "selection_changed", + (GtkSignalFunc) gtk_file_selection_file_list_changed, + filesel); + gtk_object_set_data (GTK_OBJECT (filesel->file_list), list_changed_key, (gpointer) key); + gtk_container_add (GTK_CONTAINER (listbox), filesel->file_list); + gtk_widget_show (filesel->file_list); + + + /* The action area */ + action_area = gtk_hbox_new (TRUE, 10); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), action_area, FALSE, FALSE, 0); + gtk_widget_show (action_area); + + /* The OK button */ + filesel->ok_button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), filesel->ok_button, TRUE, TRUE, 0); + gtk_widget_grab_default (filesel->ok_button); + gtk_widget_show (filesel->ok_button); + + /* The Cancel button */ + filesel->cancel_button = gtk_button_new_with_label ("Cancel"); + GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), filesel->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (filesel->cancel_button); + + /* The Help button */ + filesel->help_button = gtk_button_new_with_label ("Help"); + GTK_WIDGET_SET_FLAGS (filesel->help_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), filesel->help_button, TRUE, TRUE, 0); + gtk_widget_show (filesel->help_button); + + + /* The selection entry widget */ + entry_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 0); + gtk_widget_show (entry_vbox); + + filesel->selection_text = label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + filesel->selection_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event", + (GtkSignalFunc) gtk_file_selection_key_press, filesel); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event", + (GtkSignalFunc) gtk_widget_grab_default, + GTK_OBJECT (filesel->ok_button)); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate", + (GtkSignalFunc) gtk_button_clicked, + GTK_OBJECT (filesel->ok_button)); + gtk_box_pack_start (GTK_BOX (entry_vbox), filesel->selection_entry, TRUE, TRUE, 0); + gtk_widget_show (filesel->selection_entry); + + if (!cmpl_state_okay (filesel->cmpl_state)) + { + gchar err_buf[256]; + + sprintf (err_buf, "Directory unreadable: %s", cmpl_strerror (cmpl_errno)); + + gtk_label_set (GTK_LABEL (filesel->selection_text), err_buf); + } + else + { + gtk_file_selection_populate (filesel, "", FALSE); + } + + gtk_widget_grab_focus (filesel->selection_entry); +} + +GtkWidget* +gtk_file_selection_new (const gchar *title) +{ + GtkFileSelection *filesel; + + filesel = gtk_type_new (gtk_file_selection_get_type ()); + gtk_window_set_title (GTK_WINDOW (filesel), title); + + return GTK_WIDGET (filesel); +} + +void +gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename) +{ + char buf[MAXPATHLEN]; + const char *name, *last_slash; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (filename != NULL); + + last_slash = strrchr (filename, '/'); + + if (!last_slash) + { + buf[0] = 0; + name = filename; + } + else + { + gint len = MIN (MAXPATHLEN - 1, last_slash - filename + 1); + + strncpy (buf, filename, len); + buf[len] = 0; + + name = last_slash + 1; + } + + gtk_file_selection_populate (filesel, buf, FALSE); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name); +} + +gchar* +gtk_file_selection_get_filename (GtkFileSelection *filesel) +{ + static char nothing[2] = ""; + char *text; + char *filename; + + g_return_val_if_fail (filesel != NULL, nothing); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing); + + text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); + if (text) + { + filename = cmpl_completion_fullname (text, filesel->cmpl_state); + return filename; + } + + return nothing; +} + +static void +gtk_file_selection_destroy (GtkObject *object) +{ + GtkFileSelection *filesel; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (object)); + + filesel = GTK_FILE_SELECTION (object); + + cmpl_free_state (filesel->cmpl_state); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static gint +gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + GtkFileSelection *fs; + char *text; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->keyval == GDK_Tab) + { + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + + fs = GTK_FILE_SELECTION (user_data); + text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + gtk_file_selection_populate (fs, text, TRUE); + + return TRUE; + } + + return FALSE; +} + +static gint +gtk_file_selection_file_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + GtkFileSelection *fs; + GtkWidget *event_widget; + gchar *filename; + gboolean handled; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fs = GTK_FILE_SELECTION (user_data); + g_return_val_if_fail (fs != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs), FALSE); + + event_widget = gtk_get_event_widget ((GdkEvent*) event); + handled = FALSE; + if (GTK_IS_LIST_ITEM (event_widget)) + { + switch (event->type) + { + case GDK_BUTTON_PRESS: + filename = gtk_object_get_user_data (GTK_OBJECT (event_widget)); + gtk_widget_grab_focus (fs->selection_entry); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + handled = TRUE; + break; + + case GDK_2BUTTON_PRESS: + gtk_button_clicked (GTK_BUTTON (fs->ok_button)); + handled = TRUE; + break; + + default: + break; + } + } + + return handled; +} + +static void +gtk_file_selection_file_list_changed (GtkList *list, + gpointer func_data) +{ + GtkFileSelection *fs; + + g_return_if_fail (func_data != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (func_data)); + + fs = GTK_FILE_SELECTION (func_data); + + /* only act on an appropriate selection + */ + if (list->selection && list->selection->data) + { + GtkListItem *item; + + item = list->selection->data; + + if (GTK_IS_LIST_ITEM (item)) + { + gchar *filename; + + filename = gtk_object_get_user_data (GTK_OBJECT (item)); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + } + } +} + +static gint +gtk_file_selection_dir_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + GtkFileSelection *fs; + GtkWidget *event_widget; + gchar *filename; + gboolean handled; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fs = GTK_FILE_SELECTION (user_data); + g_return_val_if_fail (fs != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs), FALSE); + + event_widget = gtk_get_event_widget ((GdkEvent*) event); + handled = FALSE; + if (GTK_IS_LIST_ITEM (event_widget)) + { + gint key; + + filename = gtk_object_get_user_data (GTK_OBJECT (event_widget)); + + key = (gint) gtk_object_get_data (GTK_OBJECT (widget), list_changed_key); + + switch (event->type) + { + case GDK_BUTTON_PRESS: + + gtk_signal_handler_block (GTK_OBJECT (widget), key); + gtk_widget_activate (GTK_WIDGET (event_widget)); + gtk_signal_handler_unblock (GTK_OBJECT (widget), key); + + gtk_widget_grab_focus (fs->selection_entry); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + handled = TRUE; + break; + + case GDK_2BUTTON_PRESS: + gtk_file_selection_populate (fs, filename, FALSE); + handled = TRUE; + break; + + default: + break; + } + } + + return handled; +} + +static void +gtk_file_selection_dir_list_changed (GtkList *list, + gpointer func_data) +{ + GtkFileSelection *fs; + + g_return_if_fail (func_data != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (func_data)); + + fs = GTK_FILE_SELECTION (func_data); + + /* only act on an appropriate selection + */ + if (list->selection && list->selection->data) + { + GtkListItem *item; + + item = list->selection->data; + + if (GTK_IS_LIST_ITEM (item)) + { + gchar *filename; + + filename = gtk_object_get_user_data (GTK_OBJECT (item)); + + if (filename) + gtk_file_selection_populate (fs, filename, FALSE); + } + } +} + +static void +gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete) +{ + CompletionState *cmpl_state; + PossibleCompletion* poss; + GList *dir_list = NULL; + GList *file_list = NULL; + GtkWidget *label; + gchar* filename; + gchar* rem_path = rel_path; + gchar* sel_text; + gint did_recurse = FALSE; + gint possible_count = 0; + gint selection_index = -1; + gint dir_changed_key; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + dir_changed_key = (gint) gtk_object_get_data (GTK_OBJECT (fs->dir_list), list_changed_key); + gtk_signal_handler_block (GTK_OBJECT (fs->dir_list), dir_changed_key); + + cmpl_state = (CompletionState*) fs->cmpl_state; + poss = cmpl_completion_matches (rel_path, &rem_path, cmpl_state); + + if (!cmpl_state_okay (cmpl_state)) + { + /* Something went wrong. */ + gtk_file_selection_abort (fs); + gtk_signal_handler_unblock (GTK_OBJECT (fs->dir_list), dir_changed_key); + return; + } + + g_assert (cmpl_state->reference_dir); + + /* Set the dir_list and file_list to be GLists of strdup'd + * filenames, including ./ and ../ */ + dir_list = g_list_prepend (dir_list, g_strdup("./")); + dir_list = g_list_prepend (dir_list, g_strdup("../")); + + while (poss) + { + if (cmpl_is_a_completion (poss)) + { + possible_count += 1; + + filename = g_strdup (cmpl_this_completion (poss)); + + if (cmpl_is_directory (poss)) + { + if (strcmp (filename, "./") != 0 && + strcmp (filename, "../") != 0) + dir_list = g_list_prepend (dir_list, filename); + } + else + file_list = g_list_prepend (file_list, filename); + } + + poss = cmpl_next_completion (cmpl_state); + } + + /* File lists are set. */ + + g_assert (cmpl_state->reference_dir); + + if (try_complete) + { + /* User is trying to complete filenames, so advance the user's input + * string to the updated_text, which is the common leading substring + * of all possible completions, and if its a directory attempt + * attempt completions in it. */ + + if (cmpl_updated_text (cmpl_state)[0]) + { + if (cmpl_updated_dir (cmpl_state)) + { + gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state)); + + did_recurse = TRUE; + + gtk_file_selection_populate (fs, dir_name, TRUE); + + g_free (dir_name); + } + else + { + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), + cmpl_updated_text (cmpl_state)); + } + } + else + { + selection_index = cmpl_last_valid_char (cmpl_state) - + (strlen (rel_path) - strlen (rem_path)); + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path); + } + } + else + { + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), ""); + } + + if (!did_recurse) + { + GList *file_label_list = NULL; + GList *dir_label_list = NULL; + + /* This reverses the lists. */ + while (file_list) + { + label = gtk_list_item_new_with_label (file_list->data); + gtk_object_set_user_data (GTK_OBJECT (label), file_list->data); + gtk_widget_show (label); + + file_label_list = g_list_prepend (file_label_list, label); + file_list = file_list->next; + } + + while (dir_list) + { + label = gtk_list_item_new_with_label (dir_list->data); + gtk_object_set_user_data (GTK_OBJECT (label), dir_list->data); + gtk_widget_show (label); + + dir_label_list = g_list_prepend (dir_label_list, label); + dir_list = dir_list->next; + } + + gtk_container_disable_resize (GTK_CONTAINER (fs)); + + if (fs->selection_entry) + gtk_entry_set_position (GTK_ENTRY (fs->selection_entry), selection_index); + + if (fs->selection_entry) + { + sel_text = g_new (char, strlen (cmpl_reference_position (cmpl_state)) + + sizeof ("Selection: ")); + strcpy (sel_text, "Selection: "); + strcat (sel_text, cmpl_reference_position (cmpl_state)); + + gtk_label_set (GTK_LABEL (fs->selection_text), sel_text); + g_free (sel_text); + } + + if (fs->dir_list) + { + gtk_container_foreach (GTK_CONTAINER (fs->dir_list), + gtk_file_selection_free_filename, NULL); + gtk_list_clear_items (GTK_LIST (fs->dir_list), 0, -1); + + if (dir_label_list) + gtk_list_append_items (GTK_LIST (fs->dir_list), dir_label_list); + } + if (fs->file_list) + { + gtk_container_foreach (GTK_CONTAINER (fs->file_list), + gtk_file_selection_free_filename, NULL); + gtk_list_clear_items (GTK_LIST (fs->file_list), 0, -1); + + if (file_label_list) + gtk_list_append_items (GTK_LIST (fs->file_list), file_label_list); + } + + gtk_container_enable_resize (GTK_CONTAINER (fs)); + } + else + { + GList *dir_list0 = dir_list; + GList *file_list0 = file_list; + + while (dir_list) + { + GList *tmp = dir_list; + dir_list = dir_list->next; + + if (tmp) + g_free (tmp->data); + } + + while (file_list) + { + GList *tmp = file_list; + file_list = file_list->next; + + if (tmp) + g_free (tmp->data); + } + + g_list_free (dir_list0); + g_list_free (file_list0); + } + + gtk_signal_handler_unblock (GTK_OBJECT (fs->dir_list), dir_changed_key); +} + +static void +gtk_file_selection_abort (GtkFileSelection *fs) +{ + gchar err_buf[256]; + + sprintf (err_buf, "Directory unreadable: %s", cmpl_strerror (cmpl_errno)); + + /* BEEP gdk_beep(); */ + + if (fs->selection_entry) + gtk_label_set (GTK_LABEL (fs->selection_text), err_buf); +} + +static void +gtk_file_selection_free_filename (GtkWidget *widget, + gpointer client_data) +{ + g_return_if_fail (widget != NULL); + + g_free (gtk_object_get_user_data (GTK_OBJECT (widget))); + gtk_object_set_user_data (GTK_OBJECT (widget), NULL); +} + + + +/**********************************************************************/ +/* External Interface */ +/**********************************************************************/ + +/* The four completion state selectors + */ +static gchar* +cmpl_updated_text (CompletionState* cmpl_state) +{ + return cmpl_state->updated_text; +} + +static gint +cmpl_updated_dir (CompletionState* cmpl_state) +{ + return cmpl_state->re_complete; +} + +static gchar* +cmpl_reference_position (CompletionState* cmpl_state) +{ + return cmpl_state->reference_dir->fullname; +} + +static gint +cmpl_last_valid_char (CompletionState* cmpl_state) +{ + return cmpl_state->last_valid_char; +} + +static gchar* +cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state) +{ + if (text[0] == '/') + { + strcpy (cmpl_state->updated_text, text); + } + else if (text[0] == '~') + { + CompletionDir* dir; + char* slash; + + dir = open_user_dir (text, cmpl_state); + + if (!dir) + { + /* spencer says just return ~something, so + * for now just do it. */ + strcpy (cmpl_state->updated_text, text); + } + else + { + + strcpy (cmpl_state->updated_text, dir->fullname); + + slash = strchr (text, '/'); + + if (slash) + strcat (cmpl_state->updated_text, slash); + } + } + else + { + strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname); + strcat (cmpl_state->updated_text, "/"); + strcat (cmpl_state->updated_text, text); + } + + return cmpl_state->updated_text; +} + +/* The three completion selectors + */ +static gchar* +cmpl_this_completion (PossibleCompletion* pc) +{ + return pc->text; +} + +static gint +cmpl_is_directory (PossibleCompletion* pc) +{ + return pc->is_directory; +} + +static gint +cmpl_is_a_completion (PossibleCompletion* pc) +{ + return pc->is_a_completion; +} + +/**********************************************************************/ +/* Construction, deletion */ +/**********************************************************************/ + +static CompletionState* +cmpl_init_state (void) +{ + gchar getcwd_buf[2*MAXPATHLEN]; + CompletionState *new_state; + + new_state = g_new (CompletionState, 1); + + if (!getcwd (getcwd_buf, MAXPATHLEN)) + { + cmpl_errno = errno; + return NULL; + } + + new_state->reference_dir = NULL; + new_state->completion_dir = NULL; + new_state->active_completion_dir = NULL; + + if ((new_state->user_home_dir = getenv("HOME")) != NULL) + { + /* if this fails, get_pwdb will fill it in. */ + new_state->user_home_dir = g_strdup(new_state->user_home_dir); + } + + new_state->directory_storage = NULL; + new_state->directory_sent_storage = NULL; + new_state->last_valid_char = 0; + new_state->updated_text = g_new (gchar, MAXPATHLEN); + new_state->updated_text_alloc = MAXPATHLEN; + new_state->the_completion.text = g_new (gchar, MAXPATHLEN); + new_state->the_completion.text_alloc = MAXPATHLEN; + new_state->user_dir_name_buffer = NULL; + new_state->user_directories = NULL; + + new_state->reference_dir = open_dir (getcwd_buf, new_state); + + if (!new_state->reference_dir) + return NULL; + + return new_state; +} + +static void +cmpl_free_dir_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_dir_sent_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir_sent (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_state (CompletionState* cmpl_state) +{ + cmpl_free_dir_list(cmpl_state->directory_storage); + cmpl_free_dir_sent_list(cmpl_state->directory_sent_storage); + + if (cmpl_state->user_dir_name_buffer) + g_free (cmpl_state->user_dir_name_buffer); + if (cmpl_state->user_directories) + g_free (cmpl_state->user_directories); + if (cmpl_state->the_completion.text) + g_free (cmpl_state->the_completion.text); + if (cmpl_state->updated_text) + g_free (cmpl_state->updated_text); + + g_free (cmpl_state); +} + +static void +free_dir(CompletionDir* dir) +{ + g_free(dir->fullname); + g_free(dir); +} + +static void +free_dir_sent(CompletionDirSent* sent) +{ + g_free(sent->name_buffer); + g_free(sent->entries); + g_free(sent); +} + +static void +prune_memory_usage(CompletionState *cmpl_state) +{ + GList* cdsl = cmpl_state->directory_sent_storage; + GList* cdl = cmpl_state->directory_storage; + GList* cdl0 = cdl; + gint len = 0; + + for(; cdsl && len < CMPL_DIRECTORY_CACHE_SIZE; len += 1) + cdsl = cdsl->next; + + if (cdsl) { + cmpl_free_dir_sent_list(cdsl->next); + cdsl->next = NULL; + } + + while (cdl) { + if (cdl->data == cmpl_state->reference_dir) + cmpl_state->directory_storage = g_list_prepend(NULL, cdl->data); + else + free_dir (cdl->data); + cdl = cdl->next; + } + + g_list_free(cdl0); +} + +/**********************************************************************/ +/* The main entrances. */ +/**********************************************************************/ + +static PossibleCompletion* +cmpl_completion_matches (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + PossibleCompletion *poss; + + prune_memory_usage(cmpl_state); + + g_assert(text_to_complete); + + cmpl_state->user_completion_index = -1; + cmpl_state->last_completion_text = text_to_complete; + cmpl_state->the_completion.text[0] = 0; + cmpl_state->last_valid_char = 0; + cmpl_state->updated_text_len = -1; + cmpl_state->updated_text[0] = 0; + cmpl_state->re_complete = FALSE; + + first_slash = strchr(text_to_complete, '/'); + + if(text_to_complete[0] == '~' && !first_slash) + { + /* Text starts with ~ and there is no slash, show all the + * home directory completions. + */ + poss = attempt_homedir_completion(text_to_complete, cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; + } + + cmpl_state->reference_dir = + open_ref_dir(text_to_complete, remaining_text, cmpl_state); + + if(!cmpl_state->reference_dir) + return NULL; + + cmpl_state->completion_dir = + find_completion_dir(*remaining_text, remaining_text, cmpl_state); + + cmpl_state->last_valid_char = *remaining_text - text_to_complete; + + if(!cmpl_state->completion_dir) + return NULL; + + cmpl_state->completion_dir->cmpl_index = -1; + cmpl_state->completion_dir->cmpl_parent = NULL; + cmpl_state->completion_dir->cmpl_text = *remaining_text; + + cmpl_state->active_completion_dir = cmpl_state->completion_dir; + + cmpl_state->reference_dir = cmpl_state->completion_dir; + + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +static PossibleCompletion* +cmpl_next_completion (CompletionState* cmpl_state) +{ + PossibleCompletion* poss = NULL; + + cmpl_state->the_completion.text[0] = 0; + + if(cmpl_state->user_completion_index >= 0) + poss = attempt_homedir_completion(cmpl_state->last_completion_text, cmpl_state); + else + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +/**********************************************************************/ +/* Directory Operations */ +/**********************************************************************/ + +/* Open the directory where completion will begin from, if possible. */ +static CompletionDir* +open_ref_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + CompletionDir *new_dir; + + first_slash = strchr(text_to_complete, '/'); + + if (text_to_complete[0] == '/' || !cmpl_state->reference_dir) + { + new_dir = open_dir("/", cmpl_state); + + if(new_dir) + *remaining_text = text_to_complete + 1; + } + else if (text_to_complete[0] == '~') + { + new_dir = open_user_dir(text_to_complete, cmpl_state); + + if(new_dir) + { + if(first_slash) + *remaining_text = first_slash + 1; + else + *remaining_text = text_to_complete + strlen(text_to_complete); + } + else + { + return NULL; + } + } + else + { + *remaining_text = text_to_complete; + + new_dir = open_dir(cmpl_state->reference_dir->fullname, cmpl_state); + } + + if(new_dir) + { + new_dir->cmpl_index = -1; + new_dir->cmpl_parent = NULL; + } + + return new_dir; +} + +/* open a directory by user name */ +static CompletionDir* +open_user_dir(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gchar *first_slash; + gint cmp_len; + + g_assert(text_to_complete && text_to_complete[0] == '~'); + + first_slash = strchr(text_to_complete, '/'); + + if (first_slash) + cmp_len = first_slash - text_to_complete - 1; + else + cmp_len = strlen(text_to_complete + 1); + + if(!cmp_len) + { + /* ~/ */ + if (!cmpl_state->user_home_dir && + !get_pwdb(cmpl_state)) + return NULL; + return open_dir(cmpl_state->user_home_dir, cmpl_state); + } + else + { + /* ~user/ */ + char* copy = g_new(char, cmp_len + 1); + struct passwd *pwd; + strncpy(copy, text_to_complete + 1, cmp_len); + copy[cmp_len] = 0; + pwd = getpwnam(copy); + g_free(copy); + if (!pwd) + { + cmpl_errno = errno; + return NULL; + } + + return open_dir(pwd->pw_dir, cmpl_state); + } +} + +/* open a directory relative the the current relative directory */ +static CompletionDir* +open_relative_dir(gchar* dir_name, + CompletionDir* dir, + CompletionState *cmpl_state) +{ + gchar path_buf[2*MAXPATHLEN]; + + if(dir->fullname_len + strlen(dir_name) + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir->fullname); + + if(dir->fullname_len > 1) + { + path_buf[dir->fullname_len] = '/'; + strcpy(path_buf + dir->fullname_len + 1, dir_name); + } + else + { + strcpy(path_buf + dir->fullname_len, dir_name); + } + + return open_dir(path_buf, cmpl_state); +} + +/* after the cache lookup fails, really open a new directory */ +static CompletionDirSent* +open_new_dir(gchar* dir_name, struct stat* sbuf) +{ + CompletionDirSent* sent; + DIR* directory; + gchar *buffer_ptr; + struct dirent *dirent_ptr; + gint buffer_size = 0; + gint entry_count = 0; + gint i; + struct stat ent_sbuf; + char path_buf[MAXPATHLEN*2]; + gint path_buf_len; + + sent = g_new(CompletionDirSent, 1); + sent->mtime = sbuf->st_mtime; + sent->inode = sbuf->st_ino; + + path_buf_len = strlen(dir_name); + + if (path_buf_len > MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir_name); + + directory = opendir(dir_name); + + if(!directory) + { + cmpl_errno = errno; + return NULL; + } + + while((dirent_ptr = readdir(directory)) != NULL) + { + int entry_len = strlen(dirent_ptr->d_name); + buffer_size += entry_len + 1; + entry_count += 1; + + if(path_buf_len + entry_len + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + closedir(directory); + return NULL; + } + } + + sent->name_buffer = g_new(gchar, buffer_size); + sent->entries = g_new(CompletionDirEntry, entry_count); + sent->entry_count = entry_count; + + buffer_ptr = sent->name_buffer; + + rewinddir(directory); + + for(i = 0; i < entry_count; i += 1) + { + dirent_ptr = readdir(directory); + + if(!dirent_ptr) + { + cmpl_errno = errno; + closedir(directory); + return NULL; + } + + strcpy(buffer_ptr, dirent_ptr->d_name); + sent->entries[i].entry_name = buffer_ptr; + buffer_ptr += strlen(dirent_ptr->d_name); + *buffer_ptr = 0; + buffer_ptr += 1; + + path_buf[path_buf_len] = '/'; + strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name); + + if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) + sent->entries[i].is_dir = 1; + else + /* stat may fail, and we don't mind, since it could be a + * dangling symlink. */ + sent->entries[i].is_dir = 0; + } + + qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir); + + closedir(directory); + + return sent; +} + +/* open a directory by absolute pathname */ +static CompletionDir* +open_dir(gchar* dir_name, CompletionState* cmpl_state) +{ + struct stat sbuf; + CompletionDirSent *sent; + GList* cdsl; + + if(stat(dir_name, &sbuf) < 0) + { + cmpl_errno = errno; + return NULL; + } + + cdsl = cmpl_state->directory_sent_storage; + + while (cdsl) + { + sent = cdsl->data; + + if(sent->inode == sbuf.st_ino && + sent->mtime == sbuf.st_mtime) + return attach_dir(sent, dir_name, cmpl_state); + + cdsl = cdsl->next; + } + + sent = open_new_dir(dir_name, &sbuf); + + if (sent) { + cmpl_state->directory_sent_storage = + g_list_prepend(cmpl_state->directory_sent_storage, sent); + + return attach_dir(sent, dir_name, cmpl_state); + } + + return NULL; +} + +static CompletionDir* +attach_dir(CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state) +{ + CompletionDir* new_dir; + + new_dir = g_new(CompletionDir, 1); + + cmpl_state->directory_storage = + g_list_prepend(cmpl_state->directory_storage, new_dir); + + new_dir->sent = sent; + new_dir->fullname = g_strdup(dir_name); + new_dir->fullname_len = strlen(dir_name); + + return new_dir; +} + +static gint +correct_dir_fullname(CompletionDir* cmpl_dir) +{ + gint length = strlen(cmpl_dir->fullname); + struct stat sbuf; + + if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0) + cmpl_dir->fullname[length - 2] = 0; + else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0) + cmpl_dir->fullname[length - 3] = 0; + else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0) + { + if(length == 3) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 3] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0) + { + if(length == 4) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 4] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + + cmpl_dir->fullname_len = strlen(cmpl_dir->fullname); + + return TRUE; +} + +static gint +correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) +{ + struct stat parbuf; + gchar *last_slash; + gchar *new_name; + gchar c = 0; + + last_slash = strrchr(cmpl_dir->fullname, '/'); + + g_assert(last_slash); + + if(last_slash != cmpl_dir->fullname) + last_slash[0] = 0; + else + { + c = last_slash[1]; + last_slash[1] = 0; + } + + if (stat(cmpl_dir->fullname, &parbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) + /* it wasn't a link */ + return TRUE; + + if(c) + last_slash[1] = c; + else + last_slash[0] = '/'; + + /* it was a link, have to figure it out the hard way */ + + new_name = find_parent_dir_fullname(cmpl_dir->fullname); + + if (!new_name) + return FALSE; + + g_free(cmpl_dir->fullname); + + cmpl_dir->fullname = new_name; + + return TRUE; +} + +static gchar* +find_parent_dir_fullname(gchar* dirname) +{ + gchar buffer[MAXPATHLEN]; + gchar buffer2[MAXPATHLEN]; + + if(!getcwd(buffer, MAXPATHLEN)) + { + cmpl_errno = errno; + return NULL; + } + + if(chdir(dirname) != 0 || chdir("..") != 0) + { + cmpl_errno = errno; + return NULL; + } + + if(!getcwd(buffer2, MAXPATHLEN)) + { + chdir(buffer); + cmpl_errno = errno; + + return NULL; + } + + if(chdir(buffer) != 0) + { + cmpl_errno = errno; + return NULL; + } + + return g_strdup(buffer2); +} + +/**********************************************************************/ +/* Completion Operations */ +/**********************************************************************/ + +static PossibleCompletion* +attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gint index, length; + + if (!cmpl_state->user_dir_name_buffer && + !get_pwdb(cmpl_state)) + return NULL; + length = strlen(text_to_complete) - 1; + + cmpl_state->user_completion_index += 1; + + while(cmpl_state->user_completion_index < cmpl_state->user_directories_len) + { + index = first_diff_index(text_to_complete + 1, + cmpl_state->user_directories + [cmpl_state->user_completion_index].login); + + switch(index) + { + case PATTERN_MATCH: + break; + default: + if(cmpl_state->last_valid_char < (index + 1)) + cmpl_state->last_valid_char = index + 1; + cmpl_state->user_completion_index += 1; + continue; + } + + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + append_completion_text("~", cmpl_state); + + append_completion_text(cmpl_state-> + user_directories[cmpl_state->user_completion_index].login, + cmpl_state); + + return append_completion_text("/", cmpl_state); + } + + if(text_to_complete[1] || + cmpl_state->user_completion_index > cmpl_state->user_directories_len) + { + cmpl_state->user_completion_index = -1; + return NULL; + } + else + { + cmpl_state->user_completion_index += 1; + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + return append_completion_text("~/", cmpl_state); + } +} + +/* returns the index (>= 0) of the first differing character, + * PATTERN_MATCH if the completion matches */ +static gint +first_diff_index(gchar* pat, gchar* text) +{ + gint diff = 0; + + while(*pat && *text && *text == *pat) + { + pat += 1; + text += 1; + diff += 1; + } + + if(*pat) + return diff; + + return PATTERN_MATCH; +} + +static PossibleCompletion* +append_completion_text(gchar* text, CompletionState* cmpl_state) +{ + gint len, i = 1; + + if(!cmpl_state->the_completion.text) + return NULL; + + len = strlen(text) + strlen(cmpl_state->the_completion.text) + 1; + + if(cmpl_state->the_completion.text_alloc > len) + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } + + while(i < len) { i <<= 1; } + + cmpl_state->the_completion.text_alloc = i; + + cmpl_state->the_completion.text = (gchar*)g_realloc(cmpl_state->the_completion.text, i); + + if(!cmpl_state->the_completion.text) + return NULL; + else + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } +} + +static CompletionDir* +find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash = strchr(text_to_complete, '/'); + CompletionDir* dir = cmpl_state->reference_dir; + *remaining_text = text_to_complete; + + while(first_slash) + { + gint len = first_slash - *remaining_text; + gint found = 0; + gint found_index = -1; + gint i; + gchar* pat_buf = g_new (gchar, len + 1); + + strncpy(pat_buf, *remaining_text, len); + pat_buf[len] = 0; + + for(i = 0; i < dir->sent->entry_count; i += 1) + { + if(dir->sent->entries[i].is_dir && + fnmatch(pat_buf, dir->sent->entries[i].entry_name, + FNMATCH_FLAGS)!= FNM_NOMATCH) + { + if(found) + { + g_free (pat_buf); + return dir; + } + else + { + found = 1; + found_index = i; + } + } + } + + if(found) + { + CompletionDir* next = open_relative_dir(dir->sent->entries[found_index].entry_name, + dir, cmpl_state); + + if(!next) + { + g_free (pat_buf); + return NULL; + } + + next->cmpl_parent = dir; + + dir = next; + + if(!correct_dir_fullname(dir)) + { + g_free(pat_buf); + return NULL; + } + + *remaining_text = first_slash + 1; + first_slash = strchr(*remaining_text, '/'); + } + else + { + g_free (pat_buf); + return NULL; + } + + g_free (pat_buf); + } + + return dir; +} + +static void +update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state) +{ + gint cmpl_len; + + if(!poss || !cmpl_is_a_completion(poss)) + return; + + cmpl_len = strlen(cmpl_this_completion(poss)); + + if(cmpl_state->updated_text_alloc < cmpl_len + 1) + { + cmpl_state->updated_text = + (gchar*)g_realloc(cmpl_state->updated_text, + cmpl_state->updated_text_alloc); + cmpl_state->updated_text_alloc = 2*cmpl_len; + } + + if(cmpl_state->updated_text_len < 0) + { + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + cmpl_state->updated_text_len = cmpl_len; + cmpl_state->re_complete = cmpl_is_directory(poss); + } + else if(cmpl_state->updated_text_len == 0) + { + cmpl_state->re_complete = FALSE; + } + else + { + gint first_diff = + first_diff_index(cmpl_state->updated_text, + cmpl_this_completion(poss)); + + cmpl_state->re_complete = FALSE; + + if(first_diff == PATTERN_MATCH) + return; + + if(first_diff > cmpl_state->updated_text_len) + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + + cmpl_state->updated_text_len = first_diff; + cmpl_state->updated_text[first_diff] = 0; + } +} + +static PossibleCompletion* +attempt_file_completion(CompletionState *cmpl_state) +{ + gchar *pat_buf, *first_slash; + CompletionDir *dir = cmpl_state->active_completion_dir; + + dir->cmpl_index += 1; + + if(dir->cmpl_index == dir->sent->entry_count) + { + if(dir->cmpl_parent == NULL) + { + cmpl_state->active_completion_dir = NULL; + + return NULL; + } + else + { + cmpl_state->active_completion_dir = dir->cmpl_parent; + + return attempt_file_completion(cmpl_state); + } + } + + g_assert(dir->cmpl_text); + + first_slash = strchr(dir->cmpl_text, '/'); + + if(first_slash) + { + gint len = first_slash - dir->cmpl_text; + + pat_buf = g_new (gchar, len + 1); + strncpy(pat_buf, dir->cmpl_text, len); + pat_buf[len] = 0; + } + else + { + gint len = strlen(dir->cmpl_text); + + pat_buf = g_new (gchar, len + 2); + strcpy(pat_buf, dir->cmpl_text); + strcpy(pat_buf + len, "*"); + } + + if(first_slash) + { + if(dir->sent->entries[dir->cmpl_index].is_dir) + { + if(fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH) + { + CompletionDir* new_dir; + + new_dir = open_relative_dir(dir->sent->entries[dir->cmpl_index].entry_name, + dir, cmpl_state); + + if(!new_dir) + { + g_free (pat_buf); + return NULL; + } + + new_dir->cmpl_parent = dir; + + new_dir->cmpl_index = -1; + new_dir->cmpl_text = first_slash + 1; + + cmpl_state->active_completion_dir = new_dir; + + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + if(dir->cmpl_parent != NULL) + { + append_completion_text(dir->fullname + + strlen(cmpl_state->completion_dir->fullname) + 1, + cmpl_state); + append_completion_text("/", cmpl_state); + } + + append_completion_text(dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state); + + cmpl_state->the_completion.is_a_completion = + (fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH); + + cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir; + if(dir->sent->entries[dir->cmpl_index].is_dir) + append_completion_text("/", cmpl_state); + + g_free (pat_buf); + return &cmpl_state->the_completion; + } +} + + +static gint +get_pwdb(CompletionState* cmpl_state) +{ + struct passwd *pwd_ptr; + gchar* buf_ptr, *home_dir = NULL; + gint len = 0, i, count = 0; + + if(cmpl_state->user_dir_name_buffer) + return TRUE; + setpwent (); + + while ((pwd_ptr = getpwent()) != NULL) + { + len += strlen(pwd_ptr->pw_name); + len += strlen(pwd_ptr->pw_dir); + len += 2; + count += 1; + } + + if (!cmpl_state->user_home_dir) + { + /* the loser doesn't have $HOME set */ + setpwent (); + + pwd_ptr = getpwuid(getuid()); + if(!pwd_ptr) + { + cmpl_errno = errno; + goto error; + } + home_dir = pwd_ptr->pw_dir; + + len += strlen(home_dir); + len += 1; + } + + setpwent (); + + cmpl_state->user_dir_name_buffer = g_new(gchar, len); + cmpl_state->user_directories = g_new(CompletionUserDir, count); + cmpl_state->user_directories_len = count; + + buf_ptr = cmpl_state->user_dir_name_buffer; + + if (!cmpl_state->user_home_dir) + { + strcpy(buf_ptr, home_dir); + cmpl_state->user_home_dir = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + } + + for(i = 0; i < count; i += 1) + { + pwd_ptr = getpwent(); + if(!pwd_ptr) + { + cmpl_errno = errno; + goto error; + } + + strcpy(buf_ptr, pwd_ptr->pw_name); + cmpl_state->user_directories[i].login = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + strcpy(buf_ptr, pwd_ptr->pw_dir); + cmpl_state->user_directories[i].homedir = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + } + + qsort(cmpl_state->user_directories, + cmpl_state->user_directories_len, + sizeof(CompletionUserDir), + compare_user_dir); + + endpwent(); + + return TRUE; + +error: + + if(cmpl_state->user_dir_name_buffer) + g_free(cmpl_state->user_dir_name_buffer); + if(cmpl_state->user_directories) + g_free(cmpl_state->user_directories); + + cmpl_state->user_dir_name_buffer = NULL; + cmpl_state->user_directories = NULL; + + return FALSE; +} + +static gint +compare_user_dir(const void* a, const void* b) +{ + return strcmp((((CompletionUserDir*)a))->login, + (((CompletionUserDir*)b))->login); +} + +static gint +compare_cmpl_dir(const void* a, const void* b) +{ + return strcmp((((CompletionDirEntry*)a))->entry_name, + (((CompletionDirEntry*)b))->entry_name); +} + +static gint +cmpl_state_okay(CompletionState* cmpl_state) +{ + return cmpl_state && cmpl_state->reference_dir; +} + +static gchar* +cmpl_strerror(gint err) +{ + if(err == CMPL_ERRNO_TOO_LONG) + return "Name too long"; + else + return g_strerror (err); +} diff --git a/gtk/gtkfilesel.h b/gtk/gtkfilesel.h new file mode 100644 index 0000000000..1248ac6a9a --- /dev/null +++ b/gtk/gtkfilesel.h @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_FILESEL_H__ +#define __GTK_FILESEL_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwindow.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_FILE_SELECTION(obj) GTK_CHECK_CAST (obj, gtk_file_selection_get_type (), GtkFileSelection) +#define GTK_FILE_SELECTION_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_file_selection_get_type (), GtkFileSelectionClass) +#define GTK_IS_FILE_SELECTION(obj) GTK_CHECK_TYPE (obj, gtk_file_selection_get_type ()) + + +typedef struct _GtkFileSelection GtkFileSelection; +typedef struct _GtkFileSelectionClass GtkFileSelectionClass; + +struct _GtkFileSelection +{ + GtkWindow window; + + GtkWidget *dir_list; + GtkWidget *file_list; + GtkWidget *selection_entry; + GtkWidget *selection_text; + GtkWidget *main_vbox; + GtkWidget *ok_button; + GtkWidget *cancel_button; + GtkWidget *help_button; + + gpointer cmpl_state; +}; + +struct _GtkFileSelectionClass +{ + GtkWindowClass parent_class; +}; + + +guint gtk_file_selection_get_type (void); +GtkWidget* gtk_file_selection_new (const gchar *title); +void gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename); +gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FILESEL_H__ */ diff --git a/gtk/gtkfixed.c b/gtk/gtkfixed.c new file mode 100644 index 0000000000..59eba1f46f --- /dev/null +++ b/gtk/gtkfixed.c @@ -0,0 +1,525 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkfixed.h" + + +static void gtk_fixed_class_init (GtkFixedClass *klass); +static void gtk_fixed_init (GtkFixed *fixed); +static void gtk_fixed_destroy (GtkObject *object); +static void gtk_fixed_map (GtkWidget *widget); +static void gtk_fixed_unmap (GtkWidget *widget); +static void gtk_fixed_realize (GtkWidget *widget); +static void gtk_fixed_unrealize (GtkWidget *widget); +static void gtk_fixed_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_fixed_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_fixed_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_fixed_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_fixed_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_fixed_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_fixed_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_fixed_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_fixed_get_type () +{ + static guint fixed_type = 0; + + if (!fixed_type) + { + GtkTypeInfo fixed_info = + { + "GtkFixed", + sizeof (GtkFixed), + sizeof (GtkFixedClass), + (GtkClassInitFunc) gtk_fixed_class_init, + (GtkObjectInitFunc) gtk_fixed_init, + (GtkArgFunc) NULL, + }; + + fixed_type = gtk_type_unique (gtk_container_get_type (), &fixed_info); + } + + return fixed_type; +} + +static void +gtk_fixed_class_init (GtkFixedClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_fixed_destroy; + + widget_class->map = gtk_fixed_map; + widget_class->unmap = gtk_fixed_unmap; + widget_class->realize = gtk_fixed_realize; + widget_class->unrealize = gtk_fixed_unrealize; + widget_class->size_request = gtk_fixed_size_request; + widget_class->size_allocate = gtk_fixed_size_allocate; + widget_class->draw = gtk_fixed_draw; + widget_class->expose_event = gtk_fixed_expose; + + container_class->add = gtk_fixed_add; + container_class->remove = gtk_fixed_remove; + container_class->foreach = gtk_fixed_foreach; +} + +static void +gtk_fixed_init (GtkFixed *fixed) +{ + GTK_WIDGET_UNSET_FLAGS (fixed, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (fixed, GTK_BASIC); + + fixed->children = NULL; +} + +GtkWidget* +gtk_fixed_new () +{ + GtkFixed *fixed; + + fixed = gtk_type_new (gtk_fixed_get_type ()); + return GTK_WIDGET (fixed); +} + +void +gtk_fixed_put (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y) +{ + GtkFixedChild *child_info; + + g_return_if_fail (fixed != NULL); + g_return_if_fail (GTK_IS_FIXED (fixed)); + g_return_if_fail (widget != NULL); + + child_info = g_new (GtkFixedChild, 1); + child_info->widget = widget; + child_info->x = x; + child_info->y = y; + + gtk_widget_set_parent (widget, GTK_WIDGET (fixed)); + + fixed->children = g_list_append (fixed->children, child_info); + + if (GTK_WIDGET_REALIZED (fixed) && !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (fixed) && !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (fixed)) + gtk_widget_queue_resize (GTK_WIDGET (fixed)); +} + +void +gtk_fixed_move (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y) +{ + GtkFixedChild *child; + GList *children; + + g_return_if_fail (fixed != NULL); + g_return_if_fail (GTK_IS_FIXED (fixed)); + g_return_if_fail (widget != NULL); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (child->widget == widget) + { + child->x = x; + child->y = y; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (fixed)) + gtk_widget_queue_resize (GTK_WIDGET (fixed)); + + break; + } + } +} + +static void +gtk_fixed_destroy (GtkObject *object) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FIXED (object)); + + fixed = GTK_FIXED (object); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + child->widget->parent = NULL; + gtk_object_unref (GTK_OBJECT (child->widget)); + gtk_widget_destroy (child->widget); + g_free (child); + } + + g_list_free (fixed->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_fixed_map (GtkWidget *widget) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + fixed = GTK_FIXED (widget); + + gdk_window_show (widget->window); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); + } +} + +static void +gtk_fixed_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); +} + +static void +gtk_fixed_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, + attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_fixed_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + widget->window = NULL; +} + +static void +gtk_fixed_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + g_return_if_fail (requisition != NULL); + + fixed = GTK_FIXED (widget); + requisition->width = 0; + requisition->height = 0; + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + gtk_widget_size_request (child->widget, &child->widget->requisition); + + requisition->height = MAX (requisition->height, + child->y + + child->widget->requisition.height); + requisition->width = MAX (requisition->width, + child->x + + child->widget->requisition.width); + } + } + + requisition->height += GTK_CONTAINER (fixed)->border_width * 2; + requisition->width += GTK_CONTAINER (fixed)->border_width * 2; +} + +static void +gtk_fixed_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GtkAllocation child_allocation; + GList *children; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED(widget)); + g_return_if_fail (allocation != NULL); + + fixed = GTK_FIXED (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, + allocation->y, + allocation->width, + allocation->height); + + border_width = GTK_CONTAINER (fixed)->border_width; + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + child_allocation.x = child->x + border_width; + child_allocation.y = child->y + border_width; + child_allocation.width = child->widget->requisition.width; + child_allocation.height = child->widget->requisition.height; + gtk_widget_size_allocate (child->widget, &child_allocation); + } + } +} + +static void +gtk_fixed_paint (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + gdk_window_clear_area (widget->window, + area->x, area->y, + area->width, area->height); +} + +static void +gtk_fixed_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + fixed = GTK_FIXED (widget); + gtk_fixed_paint (widget, area); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); + } + } +} + +static gint +gtk_fixed_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FIXED (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + fixed = GTK_FIXED (widget); + + child_event = *event; + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, + &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static void +gtk_fixed_add (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_FIXED (container)); + g_return_if_fail (widget != NULL); + + gtk_fixed_put (GTK_FIXED (container), widget, 0, 0); +} + +static void +gtk_fixed_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_FIXED (container)); + g_return_if_fail (widget != NULL); + + fixed = GTK_FIXED (container); + + children = fixed->children; + while (children) + { + child = children->data; + + if (child->widget == widget) + { + gtk_widget_unparent (widget); + + fixed->children = g_list_remove_link (fixed->children, children); + g_list_free (children); + g_free (child); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + children = children->next; + } +} + +static void +gtk_fixed_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_FIXED (container)); + g_return_if_fail (callback != NULL); + + fixed = GTK_FIXED (container); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child->widget, callback_data); + } +} diff --git a/gtk/gtkfixed.h b/gtk/gtkfixed.h new file mode 100644 index 0000000000..ee9c131a00 --- /dev/null +++ b/gtk/gtkfixed.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_FIXED_H__ +#define __GTK_FIXED_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_FIXED(obj) GTK_CHECK_CAST (obj, gtk_fixed_get_type (), GtkFixed) +#define GTK_FIXED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_fixed_get_type (), GtkFixedClass) +#define GTK_IS_FIXED(obj) GTK_CHECK_TYPE (obj, gtk_fixed_get_type ()) + + +typedef struct _GtkFixed GtkFixed; +typedef struct _GtkFixedClass GtkFixedClass; +typedef struct _GtkFixedChild GtkFixedChild; + +struct _GtkFixed +{ + GtkContainer container; + + GList *children; +}; + +struct _GtkFixedClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkFixedChild +{ + GtkWidget *widget; + gint16 x; + gint16 y; +}; + + +guint gtk_fixed_get_type (void); +GtkWidget* gtk_fixed_new (); +void gtk_fixed_put (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y); +void gtk_fixed_move (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FIXED_H__ */ diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c new file mode 100644 index 0000000000..fe78897432 --- /dev/null +++ b/gtk/gtkframe.c @@ -0,0 +1,419 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkframe.h" + + +static void gtk_frame_class_init (GtkFrameClass *klass); +static void gtk_frame_init (GtkFrame *frame); +static void gtk_frame_destroy (GtkObject *object); +static void gtk_frame_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_frame_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_frame_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_frame_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +static GtkBinClass *parent_class = NULL; + + +guint +gtk_frame_get_type () +{ + static guint frame_type = 0; + + if (!frame_type) + { + GtkTypeInfo frame_info = + { + "GtkFrame", + sizeof (GtkFrame), + sizeof (GtkFrameClass), + (GtkClassInitFunc) gtk_frame_class_init, + (GtkObjectInitFunc) gtk_frame_init, + (GtkArgFunc) NULL, + }; + + frame_type = gtk_type_unique (gtk_bin_get_type (), &frame_info); + } + + return frame_type; +} + +static void +gtk_frame_class_init (GtkFrameClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_bin_get_type ()); + + object_class->destroy = gtk_frame_destroy; + + widget_class->draw = gtk_frame_draw; + widget_class->expose_event = gtk_frame_expose; + widget_class->size_request = gtk_frame_size_request; + widget_class->size_allocate = gtk_frame_size_allocate; +} + +static void +gtk_frame_init (GtkFrame *frame) +{ + GTK_WIDGET_SET_FLAGS (frame, GTK_BASIC); + + frame->label = NULL; + frame->shadow_type = GTK_SHADOW_ETCHED_IN; + frame->label_width = 0; + frame->label_height = 0; + frame->label_xalign = 0.0; + frame->label_yalign = 0.5; +} + +GtkWidget* +gtk_frame_new (const gchar *label) +{ + GtkFrame *frame; + + frame = gtk_type_new (gtk_frame_get_type ()); + + gtk_frame_set_label (frame, label); + + return GTK_WIDGET (frame); +} + +void +gtk_frame_set_label (GtkFrame *frame, + const gchar *label) +{ + g_return_if_fail (frame != NULL); + g_return_if_fail (GTK_IS_FRAME (frame)); + + if ((label && frame->label && (strcmp (frame->label, label) == 0)) || + (!label && !frame->label)) + return; + + if (frame->label) + g_free (frame->label); + frame->label = NULL; + + if (label) + { + frame->label = g_strdup (label); + frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7; + frame->label_height = (GTK_WIDGET (frame)->style->font->ascent + + GTK_WIDGET (frame)->style->font->descent + 1); + } + else + { + frame->label_width = 0; + frame->label_height = 0; + } + + if (GTK_WIDGET_DRAWABLE (frame)) + { + GtkWidget *widget; + + /* clear the old label area + */ + widget = GTK_WIDGET (frame); + gdk_window_clear_area (widget->window, + widget->allocation.x + GTK_CONTAINER (frame)->border_width, + widget->allocation.y + GTK_CONTAINER (frame)->border_width, + widget->allocation.width - GTK_CONTAINER (frame)->border_width, + widget->allocation.y + frame->label_height); + + gtk_widget_queue_resize (GTK_WIDGET (frame)); + } +} + +void +gtk_frame_set_label_align (GtkFrame *frame, + gfloat xalign, + gfloat yalign) +{ + g_return_if_fail (frame != NULL); + g_return_if_fail (GTK_IS_FRAME (frame)); + + xalign = CLAMP (xalign, 0.0, 1.0); + yalign = CLAMP (yalign, 0.0, 1.0); + + if ((xalign != frame->label_xalign) || (yalign != frame->label_yalign)) + { + frame->label_xalign = xalign; + frame->label_yalign = yalign; + + if (GTK_WIDGET_VISIBLE (frame)) + { + GtkWidget *widget; + + /* clear the old label area + */ + widget = GTK_WIDGET (frame); + gdk_window_clear_area (widget->window, + widget->allocation.x + GTK_CONTAINER (frame)->border_width, + widget->allocation.y + GTK_CONTAINER (frame)->border_width, + widget->allocation.width - GTK_CONTAINER (frame)->border_width, + widget->allocation.y + frame->label_height); + + gtk_widget_size_allocate (GTK_WIDGET (frame), &(GTK_WIDGET (frame)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (frame)); + } + } +} + +void +gtk_frame_set_shadow_type (GtkFrame *frame, + GtkShadowType type) +{ + g_return_if_fail (frame != NULL); + g_return_if_fail (GTK_IS_FRAME (frame)); + + if ((GtkShadowType) frame->shadow_type != type) + { + frame->shadow_type = type; + + if (GTK_WIDGET_MAPPED (frame)) + { + gdk_window_clear_area (GTK_WIDGET (frame)->window, + GTK_WIDGET (frame)->allocation.x, + GTK_WIDGET (frame)->allocation.y, + GTK_WIDGET (frame)->allocation.width, + GTK_WIDGET (frame)->allocation.height); + gtk_widget_size_allocate (GTK_WIDGET (frame), &(GTK_WIDGET (frame)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (frame)); + } + } +} + + +static void +gtk_frame_destroy (GtkObject *object) +{ + GtkFrame *frame; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FRAME (object)); + + frame = GTK_FRAME (object); + + if (frame->label) + g_free (frame->label); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_frame_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkFrame *frame; + GtkStateType state; + gint height_extra; + gint label_area_width; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + frame = GTK_FRAME (widget); + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + height_extra = frame->label_height - widget->style->klass->xthickness; + height_extra = MAX (height_extra, 0); + + x = GTK_CONTAINER (frame)->border_width; + y = GTK_CONTAINER (frame)->border_width; + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, frame->shadow_type, + widget->allocation.x + x, + widget->allocation.y + y + height_extra / 2, + widget->allocation.width - x * 2, + widget->allocation.height - y * 2 - height_extra / 2); + + if (frame->label) + { + label_area_width = (widget->allocation.width - + GTK_CONTAINER (frame)->border_width * 2 - + widget->style->klass->xthickness * 2); + + x = ((label_area_width - frame->label_width) * frame->label_xalign + + GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness); + y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent); + + gdk_window_clear_area (widget->window, + widget->allocation.x + x + 2, + widget->allocation.y + GTK_CONTAINER (frame)->border_width, + frame->label_width - 4, + frame->label_height); + gtk_draw_string (widget->style, widget->window, state, + widget->allocation.x + x + 3, + widget->allocation.y + y, + frame->label); + } + } +} + +static void +gtk_frame_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_frame_paint (widget, area); + + if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } +} + +static gint +gtk_frame_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FRAME (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_frame_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_frame_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkFrame *frame; + GtkBin *bin; + gint tmp_height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (requisition != NULL); + + frame = GTK_FRAME (widget); + bin = GTK_BIN (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness) * 2; + + tmp_height = frame->label_height - GTK_WIDGET (widget)->style->klass->ythickness; + tmp_height = MAX (tmp_height, 0); + + requisition->height = tmp_height + (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->ythickness) * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += MAX (bin->child->requisition.width, frame->label_width); + requisition->height += bin->child->requisition.height; + } + else + { + requisition->width += frame->label_width; + } +} + +static void +gtk_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkFrame *frame; + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (allocation != NULL); + + frame = GTK_FRAME (widget); + bin = GTK_BIN (widget); + + if (GTK_WIDGET_MAPPED (widget) && + ((widget->allocation.x != allocation->x) || + (widget->allocation.y != allocation->y) || + (widget->allocation.width != allocation->width) || + (widget->allocation.height != allocation->height)) && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->allocation = *allocation; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + child_allocation.x = (GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->xthickness); + child_allocation.width = MAX(0, allocation->width - child_allocation.x * 2); + + child_allocation.y = (GTK_CONTAINER (frame)->border_width + + MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness)); + child_allocation.height = MAX (0, (allocation->height - child_allocation.y - + GTK_CONTAINER (frame)->border_width - + GTK_WIDGET (frame)->style->klass->ythickness)); + + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} diff --git a/gtk/gtkframe.h b/gtk/gtkframe.h new file mode 100644 index 0000000000..3fe17a3cbd --- /dev/null +++ b/gtk/gtkframe.h @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_FRAME_H__ +#define __GTK_FRAME_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbin.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_FRAME(obj) GTK_CHECK_CAST (obj, gtk_frame_get_type (), GtkFrame) +#define GTK_FRAME_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_frame_get_type (), GtkFrameClass) +#define GTK_IS_FRAME(obj) GTK_CHECK_TYPE (obj, gtk_frame_get_type ()) + + +typedef struct _GtkFrame GtkFrame; +typedef struct _GtkFrameClass GtkFrameClass; + +struct _GtkFrame +{ + GtkBin bin; + + gchar *label; + gint16 shadow_type; + gint16 label_width; + gint16 label_height; + gfloat label_xalign; + gfloat label_yalign; +}; + +struct _GtkFrameClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_frame_get_type (void); +GtkWidget* gtk_frame_new (const gchar *label); +void gtk_frame_set_label (GtkFrame *frame, + const gchar *label); +void gtk_frame_set_label_align (GtkFrame *frame, + gfloat xalign, + gfloat yalign); +void gtk_frame_set_shadow_type (GtkFrame *frame, + GtkShadowType type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FRAME_H__ */ diff --git a/gtk/gtkgamma.c b/gtk/gtkgamma.c new file mode 100644 index 0000000000..1d7abc6fba --- /dev/null +++ b/gtk/gtkgamma.c @@ -0,0 +1,464 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1997 David Mosberger + * + * 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 <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "gtkgamma.h" +#include "gtkcurve.h" +#include "gtkdialog.h" +#include "gtkdrawingarea.h" +#include "gtkentry.h" +#include "gtkhbox.h" +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtkpixmap.h" +#include "gtkradiobutton.h" +#include "gtksignal.h" +#include "gtktable.h" +#include "gtkvbox.h" +#include "gtkwindow.h" + +static GtkVBoxClass *parent_class = NULL; + + +/* forward declarations: */ +static void gtk_gamma_curve_class_init (GtkGammaCurveClass *class); +static void gtk_gamma_curve_init (GtkGammaCurve *curve); +static void gtk_gamma_curve_destroy (GtkObject *object); + +enum + { + LINEAR = 0, + SPLINE, + FREE, + GAMMA, + RESET, + NUM_XPMS + }; + +static char *xpm[][27] = + { + /* spline: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 4 1", + /* colors */ + ". c None", + "B c #000000", + "+ c #BC2D2D", + "r c #FF0000", + /* pixels */ + "..............BB", + ".........rrrrrrB", + ".......rr.......", + ".....B+.........", + "....BBB.........", + "....+B..........", + "....r...........", + "...r............", + "...r............", + "..r.............", + "..r.............", + ".r..............", + ".r..............", + ".r..............", + "B+..............", + "BB.............." + }, + /* linear: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 5 1", + /* colors */ + ". c None", /* transparent */ + "B c #000000", + "' c #7F7F7F", + "+ c #824141", + "r c #FF0000", + /* pixels */ + "..............BB", + "..............+B", + "..............r.", + ".............r..", + ".............r..", + "....'B'.....r...", + "....BBB.....r...", + "....+B+....r....", + "....r.r....r....", + "...r...r..r.....", + "...r...r..r.....", + "..r.....rB+.....", + "..r.....BBB.....", + ".r......'B'.....", + "B+..............", + "BB.............." + }, + /* free: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 2 1", + /* colors */ + ". c None", + "r c #FF0000", + /* pixels */ + "................", + "................", + "......r.........", + "......r.........", + ".......r........", + ".......r........", + ".......r........", + "........r.......", + "........r.......", + "........r.......", + ".....r...r.rrrrr", + "....r....r......", + "...r.....r......", + "..r.......r.....", + ".r........r.....", + "r..............." + }, + /* gamma: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 10 1", + /* colors */ + ". c None", + "B c #000000", + "& c #171717", + "# c #2F2F2F", + "X c #464646", + "= c #5E5E5E", + "/ c #757575", + "+ c #8C8C8C", + "- c #A4A4A4", + "` c #BBBBBB", + /* pixels */ + "................", + "................", + "................", + "....B=..+B+.....", + "....X&`./&-.....", + "...../+.XX......", + "......B.B+......", + "......X.X.......", + "......X&+.......", + "......-B........", + "....../=........", + "......#B........", + "......BB........", + "......B#........", + "................", + "................" + }, + /* reset: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 4 1", + /* colors */ + ". c None", + "B c #000000", + "+ c #824141", + "r c #FF0000", + /* pixels */ + "..............BB", + "..............+B", + ".............r..", + "............r...", + "...........r....", + "..........r.....", + ".........r......", + "........r.......", + ".......r........", + "......r.........", + ".....r..........", + "....r...........", + "...r............", + "..r.............", + "B+..............", + "BB.............." + } + }; + +guint +gtk_gamma_curve_get_type (void) +{ + static guint gamma_curve_type = 0; + + if (!gamma_curve_type) + { + GtkTypeInfo gamma_curve_info = + { + "GtkGammaCurve", + sizeof (GtkGammaCurve), + sizeof (GtkGammaCurveClass), + (GtkClassInitFunc) gtk_gamma_curve_class_init, + (GtkObjectInitFunc) gtk_gamma_curve_init, + (GtkArgFunc) NULL, + }; + + gamma_curve_type = + gtk_type_unique (gtk_vbox_get_type (), &gamma_curve_info); + } + return gamma_curve_type; +} + +static void +gtk_gamma_curve_class_init (GtkGammaCurveClass *class) +{ + GtkObjectClass *object_class; + + parent_class = gtk_type_class (gtk_vbox_get_type ()); + + object_class = (GtkObjectClass *) class; + object_class->destroy = gtk_gamma_curve_destroy; +} + +static void +gtk_gamma_curve_init (GtkGammaCurve *curve) +{ + curve->gamma = 1.0; +} + +static void +button_realize_callback (GtkWidget *w) +{ + GtkWidget *pixmap; + GdkBitmap *mask; + GdkPixmap *pm; + int i; + + i = (long) gtk_object_get_data (GTK_OBJECT (w), "_GtkGammaCurveIndex"); + pm = gdk_pixmap_create_from_xpm_d (w->window, &mask, + &w->style->bg[GTK_STATE_NORMAL], xpm[i]); + + pixmap = gtk_pixmap_new (pm, mask); + gtk_container_add (GTK_CONTAINER (w), pixmap); + gtk_widget_show (pixmap); + + gdk_pixmap_destroy (pm); + gdk_pixmap_destroy (mask); /* a bitmap is really just a special pixmap */ +} + +static void +button_toggled_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + GtkCurveType type; + int active, i; + + if (!GTK_TOGGLE_BUTTON (w)->active) + return; + + active = (long) gtk_object_get_data (GTK_OBJECT (w), "_GtkGammaCurveIndex"); + + for (i = 0; i < 3; ++i) + if ((i != active) && GTK_TOGGLE_BUTTON (c->button[i])->active) + break; + + if (i < 3) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (c->button[i]), FALSE); + + switch (active) + { + case 0: type = GTK_CURVE_TYPE_SPLINE; break; + case 1: type = GTK_CURVE_TYPE_LINEAR; break; + default: type = GTK_CURVE_TYPE_FREE; break; + } + gtk_curve_set_curve_type (GTK_CURVE (c->curve), type); +} + +static void +gamma_cancel_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + + gtk_widget_destroy (c->gamma_dialog); + c->gamma_dialog = 0; +} + +static void +gamma_ok_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + gchar *start, *end; + gfloat v; + + start = gtk_entry_get_text (GTK_ENTRY (c->gamma_text)); + if (start) + { + v = strtod (start, &end); + if (end > start && v > 0.0) + c->gamma = v; + } + gtk_curve_set_gamma (GTK_CURVE (c->curve), c->gamma); + gamma_cancel_callback (w, data); +} + +static void +button_clicked_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + int active; + + active = (long) gtk_object_get_data (GTK_OBJECT (w), "_GtkGammaCurveIndex"); + if (active == 3) + /* set gamma */ + if (c->gamma_dialog) + return; + else + { + GtkWidget *vbox, *hbox, *label, *button; + gchar buf[64]; + + c->gamma_dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (c->gamma_dialog), "Gamma"); + vbox = GTK_DIALOG (c->gamma_dialog)->vbox; + + hbox = gtk_hbox_new (/* homogeneous */ FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 2); + gtk_widget_show (hbox); + + label = gtk_label_new ("Gamma value"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2); + gtk_widget_show (label); + + sprintf (buf, "%g", c->gamma); + c->gamma_text = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (c->gamma_text), buf); + gtk_box_pack_start (GTK_BOX (hbox), c->gamma_text, TRUE, TRUE, 2); + gtk_widget_show (c->gamma_text); + + /* fill in action area: */ + hbox = GTK_DIALOG (c->gamma_dialog)->action_area; + + button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gamma_ok_callback, c); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Cancel"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gamma_cancel_callback, c); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_widget_show (c->gamma_dialog); + } + else + /* reset */ + gtk_curve_reset (GTK_CURVE (c->curve)); +} + +static void +curve_type_changed_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + GtkCurveType new_type; + int active; + + new_type = GTK_CURVE (w)->curve_type; + switch (new_type) + { + case GTK_CURVE_TYPE_SPLINE: active = 0; break; + case GTK_CURVE_TYPE_LINEAR: active = 1; break; + default: active = 2; break; + } + if (!GTK_TOGGLE_BUTTON (c->button[active])->active) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (c->button[active]), TRUE); +} + +GtkWidget* +gtk_gamma_curve_new (void) +{ + GtkGammaCurve *c; + GtkWidget *vbox; + int i; + + c = gtk_type_new (gtk_gamma_curve_get_type ()); + + c->table = gtk_table_new (1, 2, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (c->table), 3); + gtk_container_add (GTK_CONTAINER (c), c->table); + + c->curve = gtk_curve_new (); + gtk_signal_connect (GTK_OBJECT (c->curve), "curve_type_changed", + (GtkSignalFunc) curve_type_changed_callback, c); + gtk_table_attach_defaults (GTK_TABLE (c->table), c->curve, 0, 1, 0, 1); + + vbox = gtk_vbox_new (/* homogeneous */ FALSE, /* spacing */ 3); + gtk_table_attach (GTK_TABLE (c->table), vbox, 1, 2, 0, 1, 0, 0, 0, 0); + + /* toggle buttons: */ + for (i = 0; i < 3; ++i) + { + c->button[i] = gtk_toggle_button_new (); + gtk_object_set_data (GTK_OBJECT (c->button[i]), "_GtkGammaCurveIndex", + (gpointer) (long) i); + gtk_container_add (GTK_CONTAINER (vbox), c->button[i]); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "realize", + (GtkSignalFunc) button_realize_callback, 0); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "toggled", + (GtkSignalFunc) button_toggled_callback, c); + gtk_widget_show (c->button[i]); + } + + /* push buttons: */ + for (i = 3; i < 5; ++i) + { + c->button[i] = gtk_button_new (); + gtk_object_set_data (GTK_OBJECT (c->button[i]), "_GtkGammaCurveIndex", + (gpointer) (long) i); + gtk_container_add (GTK_CONTAINER (vbox), c->button[i]); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "realize", + (GtkSignalFunc) button_realize_callback, 0); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "clicked", + (GtkSignalFunc) button_clicked_callback, c); + gtk_widget_show (c->button[i]); + } + + gtk_widget_show (vbox); + gtk_widget_show (c->table); + gtk_widget_show (c->curve); + + return GTK_WIDGET (c); +} + +static void +gtk_gamma_curve_destroy (GtkObject *object) +{ + GtkGammaCurve *c; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_GAMMA_CURVE (object)); + + c = GTK_GAMMA_CURVE (object); + + if (c->gamma_dialog) + { + gtk_widget_destroy (c->gamma_dialog); + c->gamma_dialog = 0; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} diff --git a/gtk/gtkgamma.h b/gtk/gtkgamma.h new file mode 100644 index 0000000000..872a7bd438 --- /dev/null +++ b/gtk/gtkgamma.h @@ -0,0 +1,71 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1997 David Mosberger + * + * 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. + */ +#ifndef __GTK_GAMMA_CURVE_H__ +#define __GTK_GAMMA_CURVE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkvbox.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_GAMMA_CURVE(obj) \ + GTK_CHECK_CAST (obj, gtk_gamma_curve_get_type (), GtkGammaCurve) +#define GTK_GAMMA_CURVE_CLASS(klass) \ + GTK_CHECK_CLASS_CAST (klass, gtk_gamma_curve_get_type, GtkGammaCurveClass) +#define GTK_IS_GAMMA_CURVE(obj) \ + GTK_CHECK_TYPE (obj, gtk_gamma_curve_get_type ()) + + +typedef struct _GtkGammaCurve GtkGammaCurve; +typedef struct _GtkGammaCurveClass GtkGammaCurveClass; + + +struct _GtkGammaCurve +{ + GtkVBox vbox; + + GtkWidget *table; + GtkWidget *curve; + GtkWidget *button[5]; /* spline, linear, free, gamma, reset */ + + gfloat gamma; + GtkWidget *gamma_dialog; + GtkWidget *gamma_text; +}; + +struct _GtkGammaCurveClass +{ + GtkVBoxClass parent_class; +}; + + +guint gtk_gamma_curve_get_type (void); +GtkWidget* gtk_gamma_curve_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_GAMMA_CURVE_H__ */ diff --git a/gtk/gtkgc.c b/gtk/gtkgc.c new file mode 100644 index 0000000000..c9da069844 --- /dev/null +++ b/gtk/gtkgc.c @@ -0,0 +1,382 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkgc.h" + + +typedef struct _GtkGCKey GtkGCKey; +typedef struct _GtkGCDrawable GtkGCDrawable; + +struct _GtkGCKey +{ + gint depth; + GdkColormap *colormap; + GdkGCValues values; + GdkGCValuesMask mask; +}; + +struct _GtkGCDrawable +{ + gint depth; + GdkPixmap *drawable; +}; + + +static void gtk_gc_init (void); +static GtkGCKey* gtk_gc_key_dup (GtkGCKey *key); +static void gtk_gc_key_destroy (GtkGCKey *key); +static gpointer gtk_gc_new (gpointer key); +static void gtk_gc_destroy (gpointer value); +static guint gtk_gc_key_hash (gpointer key); +static guint gtk_gc_value_hash (gpointer value); +static gint gtk_gc_key_compare (gpointer a, + gpointer b); +static guint gtk_gc_drawable_hash (GtkGCDrawable *d); +static gint gtk_gc_drawable_compare (GtkGCDrawable *a, + GtkGCDrawable *b); + + +static gint initialize = TRUE; +static GCache *gc_cache = NULL; +static GHashTable *gc_drawable_ht = NULL; + +static GMemChunk *key_mem_chunk = NULL; + + +GdkGC* +gtk_gc_get (gint depth, + GdkColormap *colormap, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GtkGCKey key; + GdkGC *gc; + + if (initialize) + gtk_gc_init (); + + key.depth = depth; + key.colormap = colormap; + key.values = *values; + key.mask = values_mask; + + gc = g_cache_insert (gc_cache, &key); + + return gc; +} + +void +gtk_gc_release (GdkGC *gc) +{ + if (initialize) + gtk_gc_init (); + + g_cache_remove (gc_cache, gc); +} + + +static void +gtk_gc_init () +{ + initialize = FALSE; + + gc_cache = g_cache_new ((GCacheNewFunc) gtk_gc_new, + (GCacheDestroyFunc) gtk_gc_destroy, + (GCacheDupFunc) gtk_gc_key_dup, + (GCacheDestroyFunc) gtk_gc_key_destroy, + (GHashFunc) gtk_gc_key_hash, + (GHashFunc) gtk_gc_value_hash, + (GCompareFunc) gtk_gc_key_compare); + + gc_drawable_ht = g_hash_table_new ((GHashFunc) gtk_gc_drawable_hash, + (GCompareFunc) gtk_gc_drawable_compare); +} + +static GtkGCKey* +gtk_gc_key_dup (GtkGCKey *key) +{ + GtkGCKey *new_key; + + if (!key_mem_chunk) + key_mem_chunk = g_mem_chunk_new ("key mem chunk", sizeof (GtkGCKey), + 1024, G_ALLOC_AND_FREE); + + new_key = g_chunk_new (GtkGCKey, key_mem_chunk); + + *new_key = *key; + + return new_key; +} + +static void +gtk_gc_key_destroy (GtkGCKey *key) +{ + g_mem_chunk_free (key_mem_chunk, key); +} + +static gpointer +gtk_gc_new (gpointer key) +{ + GtkGCKey *keyval; + GtkGCDrawable *drawable; + GdkGC *gc; + + keyval = key; + + drawable = g_hash_table_lookup (gc_drawable_ht, &keyval->depth); + if (!drawable) + { + drawable = g_new (GtkGCDrawable, 1); + drawable->depth = keyval->depth; + drawable->drawable = gdk_pixmap_new (NULL, 1, 1, drawable->depth); + + g_hash_table_insert (gc_drawable_ht, &drawable->depth, drawable); + } + + gc = gdk_gc_new_with_values (drawable->drawable, &keyval->values, keyval->mask); + + return (gpointer) gc; +} + +static void +gtk_gc_destroy (gpointer value) +{ + gdk_gc_destroy ((GdkGC*) value); +} + +static guint +gtk_gc_key_hash (gpointer key) +{ + GtkGCKey *keyval; + guint hash_val; + + keyval = key; + hash_val = 0; + + if (keyval->mask & GDK_GC_FOREGROUND) + { + hash_val += keyval->values.foreground.pixel; + } + if (keyval->mask & GDK_GC_BACKGROUND) + { + hash_val += keyval->values.background.pixel; + } + if (keyval->mask & GDK_GC_FONT) + { + hash_val += gdk_font_id (keyval->values.font); + } + if (keyval->mask & GDK_GC_FUNCTION) + { + hash_val += (gint) keyval->values.function; + } + if (keyval->mask & GDK_GC_FILL) + { + hash_val += (gint) keyval->values.fill; + } + if (keyval->mask & GDK_GC_TILE) + { + hash_val += (glong) keyval->values.tile; + } + if (keyval->mask & GDK_GC_STIPPLE) + { + hash_val += (glong) keyval->values.stipple; + } + if (keyval->mask & GDK_GC_CLIP_MASK) + { + hash_val += (glong) keyval->values.clip_mask; + } + if (keyval->mask & GDK_GC_SUBWINDOW) + { + hash_val += (gint) keyval->values.subwindow_mode; + } + if (keyval->mask & GDK_GC_TS_X_ORIGIN) + { + hash_val += (gint) keyval->values.ts_x_origin; + } + if (keyval->mask & GDK_GC_TS_Y_ORIGIN) + { + hash_val += (gint) keyval->values.ts_y_origin; + } + if (keyval->mask & GDK_GC_CLIP_X_ORIGIN) + { + hash_val += (gint) keyval->values.clip_x_origin; + } + if (keyval->mask & GDK_GC_CLIP_Y_ORIGIN) + { + hash_val += (gint) keyval->values.clip_y_origin; + } + if (keyval->mask & GDK_GC_EXPOSURES) + { + hash_val += (gint) keyval->values.graphics_exposures; + } + if (keyval->mask & GDK_GC_LINE_WIDTH) + { + hash_val += (gint) keyval->values.line_width; + } + if (keyval->mask & GDK_GC_LINE_STYLE) + { + hash_val += (gint) keyval->values.line_style; + } + if (keyval->mask & GDK_GC_CAP_STYLE) + { + hash_val += (gint) keyval->values.cap_style; + } + if (keyval->mask & GDK_GC_JOIN_STYLE) + { + hash_val += (gint) keyval->values.join_style; + } + + return hash_val; +} + +static guint +gtk_gc_value_hash (gpointer value) +{ + return (gulong) value; +} + +static gint +gtk_gc_key_compare (gpointer a, + gpointer b) +{ + GtkGCKey *akey; + GtkGCKey *bkey; + GdkGCValues *avalues; + GdkGCValues *bvalues; + + akey = a; + bkey = b; + + avalues = &akey->values; + bvalues = &bkey->values; + + if (akey->mask != bkey->mask) + return FALSE; + + if (akey->depth != bkey->depth) + return FALSE; + + if (akey->colormap != bkey->colormap) + return FALSE; + + if (akey->mask & GDK_GC_FOREGROUND) + { + if (avalues->foreground.pixel != bvalues->foreground.pixel) + return FALSE; + } + if (akey->mask & GDK_GC_BACKGROUND) + { + if (avalues->background.pixel != bvalues->background.pixel) + return FALSE; + } + if (akey->mask & GDK_GC_FONT) + { + if (!gdk_font_equal (avalues->font, bvalues->font)) + return FALSE; + } + if (akey->mask & GDK_GC_FUNCTION) + { + if (avalues->function != bvalues->function) + return FALSE; + } + if (akey->mask & GDK_GC_FILL) + { + if (avalues->fill != bvalues->fill) + return FALSE; + } + if (akey->mask & GDK_GC_TILE) + { + if (avalues->tile != bvalues->tile) + return FALSE; + } + if (akey->mask & GDK_GC_STIPPLE) + { + if (avalues->stipple != bvalues->stipple) + return FALSE; + } + if (akey->mask & GDK_GC_CLIP_MASK) + { + if (avalues->clip_mask != bvalues->clip_mask) + return FALSE; + } + if (akey->mask & GDK_GC_SUBWINDOW) + { + if (avalues->subwindow_mode != bvalues->subwindow_mode) + return FALSE; + } + if (akey->mask & GDK_GC_TS_X_ORIGIN) + { + if (avalues->ts_x_origin != bvalues->ts_x_origin) + return FALSE; + } + if (akey->mask & GDK_GC_TS_Y_ORIGIN) + { + if (avalues->ts_y_origin != bvalues->ts_y_origin) + return FALSE; + } + if (akey->mask & GDK_GC_CLIP_X_ORIGIN) + { + if (avalues->clip_x_origin != bvalues->clip_x_origin) + return FALSE; + } + if (akey->mask & GDK_GC_CLIP_Y_ORIGIN) + { + if (avalues->clip_y_origin != bvalues->clip_y_origin) + return FALSE; + } + if (akey->mask & GDK_GC_EXPOSURES) + { + if (avalues->graphics_exposures != bvalues->graphics_exposures) + return FALSE; + } + if (akey->mask & GDK_GC_LINE_WIDTH) + { + if (avalues->line_width != bvalues->line_width) + return FALSE; + } + if (akey->mask & GDK_GC_LINE_STYLE) + { + if (avalues->line_style != bvalues->line_style) + return FALSE; + } + if (akey->mask & GDK_GC_CAP_STYLE) + { + if (avalues->cap_style != bvalues->cap_style) + return FALSE; + } + if (akey->mask & GDK_GC_JOIN_STYLE) + { + if (avalues->join_style != bvalues->join_style) + return FALSE; + } + + return TRUE; +} + + +static guint +gtk_gc_drawable_hash (GtkGCDrawable *d) +{ + return d->depth; +} + +static gint +gtk_gc_drawable_compare (GtkGCDrawable *a, + GtkGCDrawable *b) +{ + return (a->depth == b->depth); +} diff --git a/gtk/gtkgc.h b/gtk/gtkgc.h new file mode 100644 index 0000000000..ff4ecc466c --- /dev/null +++ b/gtk/gtkgc.h @@ -0,0 +1,42 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_GC_H__ +#define __GTK_GC_H__ + + +#include <gdk/gdk.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +GdkGC* gtk_gc_get (gint depth, + GdkColormap *colormap, + GdkGCValues *values, + GdkGCValuesMask values_mask); +void gtk_gc_release (GdkGC *gc); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_GC_H__ */ diff --git a/gtk/gtkhbbox.c b/gtk/gtkhbbox.c new file mode 100644 index 0000000000..9d86c010e0 --- /dev/null +++ b/gtk/gtkhbbox.c @@ -0,0 +1,269 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkhbbox.h" + + +static void gtk_hbutton_box_class_init (GtkHButtonBoxClass *klass); +static void gtk_hbutton_box_init (GtkHButtonBox *box); +static void gtk_hbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static gint default_spacing = 30; +static gint default_layout_style = GTK_BUTTONBOX_EDGE; + +guint +gtk_hbutton_box_get_type () +{ + static guint hbutton_box_type = 0; + + if (!hbutton_box_type) + { + GtkTypeInfo hbutton_box_info = + { + "GtkHButtonBox", + sizeof (GtkHButtonBox), + sizeof (GtkHButtonBoxClass), + (GtkClassInitFunc) gtk_hbutton_box_class_init, + (GtkObjectInitFunc) gtk_hbutton_box_init, + (GtkArgFunc) NULL, + }; + + hbutton_box_type = gtk_type_unique (gtk_button_box_get_type (), &hbutton_box_info); + } + + return hbutton_box_type; +} + +static void +gtk_hbutton_box_class_init (GtkHButtonBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_hbutton_box_size_request; + widget_class->size_allocate = gtk_hbutton_box_size_allocate; +} + +static void +gtk_hbutton_box_init (GtkHButtonBox *hbutton_box) +{ + /* button_box_init has done everything allready */ +} + +GtkWidget* +gtk_hbutton_box_new () +{ + GtkHButtonBox *hbutton_box; + + hbutton_box = gtk_type_new (gtk_hbutton_box_get_type ()); + + return GTK_WIDGET (hbutton_box); +} + + +/* set default value for spacing */ + +void gtk_hbutton_box_set_spacing_default (gint spacing) +{ + default_spacing = spacing; +} + + +/* set default value for layout style */ + +void gtk_hbutton_box_set_layout_default (gint layout) +{ + default_layout_style = layout; +} + +/* get default value for spacing */ + +gint gtk_hbutton_box_get_spacing_default (void) +{ + return default_spacing; +} + + +/* get default value for layout style */ + +gint gtk_hbutton_box_get_layout_default (void) +{ + return default_layout_style; +} + + + +static void +gtk_hbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkButtonBox *bbox; + gint nvis_children; + gint child_width; + gint child_height; + gint spacing; + gint layout; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBUTTON_BOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + bbox = GTK_BUTTON_BOX (widget); + + spacing = bbox->spacing != GTK_BUTTONBOX_DEFAULT + ? bbox->spacing : default_spacing; + layout = bbox->layout_style != GTK_BUTTONBOX_DEFAULT + ? bbox->layout_style : default_layout_style; + + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + + if (nvis_children == 0) + { + requisition->width = 0; + requisition->height = 0; + } + else + { + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + requisition->width = + nvis_children*child_width + ((nvis_children+1)*spacing); + break; + case GTK_BUTTONBOX_EDGE: + case GTK_BUTTONBOX_START: + case GTK_BUTTONBOX_END: + requisition->width = nvis_children*child_width + ((nvis_children-1)*spacing); + break; + default: + g_assert_not_reached(); + break; + } + + requisition->height = child_height; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + + + +static void +gtk_hbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkButtonBox *box; + GtkHButtonBox *hbox; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint child_width; + gint child_height; + gint x = 0; + gint y = 0; + gint width; + gint childspace; + gint childspacing = 0; + gint layout; + gint spacing; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBUTTON_BOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BUTTON_BOX (widget); + hbox = GTK_HBUTTON_BOX (widget); + spacing = box->spacing != GTK_BUTTONBOX_DEFAULT + ? box->spacing : default_spacing; + layout = box->layout_style != GTK_BUTTONBOX_DEFAULT + ? box->layout_style : default_layout_style; + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + widget->allocation = *allocation; + width = allocation->width - GTK_CONTAINER (box)->border_width*2; + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + childspacing = (width - (nvis_children*child_width)) / (nvis_children+1); + x = allocation->x + GTK_CONTAINER (box)->border_width + childspacing; + break; + case GTK_BUTTONBOX_EDGE: + if (nvis_children >= 2) + { + childspacing = + (width - (nvis_children*child_width)) / (nvis_children-1); + x = allocation->x + GTK_CONTAINER (box)->border_width; + } + else + { + /* one or zero children, just center */ + childspacing = width; + x = allocation->x + (allocation->width - child_width) / 2; + } + break; + case GTK_BUTTONBOX_START: + childspacing = spacing; + x = allocation->x + GTK_CONTAINER (box)->border_width; + break; + case GTK_BUTTONBOX_END: + childspacing = spacing; + x = allocation->x + allocation->width - child_width * nvis_children + - spacing *(nvis_children-1) + - GTK_CONTAINER (box)->border_width; + break; + default: + g_assert_not_reached(); + break; + } + + + y = allocation->y + (allocation->height - child_height) / 2; + childspace = child_width + childspacing; + + children = GTK_BOX (box)->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + child_allocation.width = child_width; + child_allocation.height = child_height; + child_allocation.x = x; + child_allocation.y = y; + gtk_widget_size_allocate (child->widget, &child_allocation); + x += childspace; + } + } +} + diff --git a/gtk/gtkhbbox.h b/gtk/gtkhbbox.h new file mode 100644 index 0000000000..c61c138b9d --- /dev/null +++ b/gtk/gtkhbbox.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_HBUTTON_BOX_H__ +#define __GTK_HBUTTON_BOX_H__ + + +#include "gtk/gtkbbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HBUTTON_BOX(obj) GTK_CHECK_CAST (obj, gtk_hbutton_box_get_type (), GtkHButtonBox) +#define GTK_HBUTTON_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hbutton_box_get_type (), GtkHButtonBoxClass) +#define GTK_IS_HBUTTON_BOX(obj) GTK_CHECK_TYPE (obj, gtk_hbutton_box_get_type ()) + + +typedef struct _GtkHButtonBox GtkHButtonBox; +typedef struct _GtkHButtonBoxClass GtkHButtonBoxClass; + +struct _GtkHButtonBox +{ + GtkButtonBox button_box; +}; + +struct _GtkHButtonBoxClass +{ + GtkButtonBoxClass parent_class; +}; + + +guint gtk_hbutton_box_get_type (void); +GtkWidget *gtk_hbutton_box_new (void); + +/* buttons can be added by gtk_container_add() */ + +gint gtk_hbutton_box_get_spacing_default (void); +gint gtk_hbutton_box_get_layout_default (void); + +void gtk_hbutton_box_set_spacing_default (gint spacing); +void gtk_hbutton_box_set_layout_default (gint layout); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HBUTTON_BOX_H__ */ diff --git a/gtk/gtkhbox.c b/gtk/gtkhbox.c new file mode 100644 index 0000000000..4cdc926cd9 --- /dev/null +++ b/gtk/gtkhbox.c @@ -0,0 +1,306 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkhbox.h" + + +static void gtk_hbox_class_init (GtkHBoxClass *klass); +static void gtk_hbox_init (GtkHBox *box); +static void gtk_hbox_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_hbox_get_type () +{ + static guint hbox_type = 0; + + if (!hbox_type) + { + GtkTypeInfo hbox_info = + { + "GtkHBox", + sizeof (GtkHBox), + sizeof (GtkHBoxClass), + (GtkClassInitFunc) gtk_hbox_class_init, + (GtkObjectInitFunc) gtk_hbox_init, + (GtkArgFunc) NULL, + }; + + hbox_type = gtk_type_unique (gtk_box_get_type (), &hbox_info); + } + + return hbox_type; +} + +static void +gtk_hbox_class_init (GtkHBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_hbox_size_request; + widget_class->size_allocate = gtk_hbox_size_allocate; +} + +static void +gtk_hbox_init (GtkHBox *hbox) +{ +} + +GtkWidget* +gtk_hbox_new (gint homogeneous, + gint spacing) +{ + GtkHBox *hbox; + + hbox = gtk_type_new (gtk_hbox_get_type ()); + + GTK_BOX (hbox)->spacing = spacing; + GTK_BOX (hbox)->homogeneous = homogeneous ? TRUE : FALSE; + + return GTK_WIDGET (hbox); +} + + +static void +gtk_hbox_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + gint nvis_children; + gint width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + requisition->width = 0; + requisition->height = 0; + nvis_children = 0; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + gtk_widget_size_request (child->widget, &child->widget->requisition); + + if (box->homogeneous) + { + width = child->widget->requisition.width + child->padding * 2; + requisition->width = MAX (requisition->width, width); + } + else + { + requisition->width += child->widget->requisition.width + child->padding * 2; + } + + requisition->height = MAX (requisition->height, child->widget->requisition.height); + + nvis_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + requisition->width *= nvis_children; + requisition->width += (nvis_children - 1) * box->spacing; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + +static void +gtk_hbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint nexpand_children; + gint child_width; + gint width; + gint extra; + gint x; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BOX (widget); + widget->allocation = *allocation; + + nvis_children = 0; + nexpand_children = 0; + children = box->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + nvis_children += 1; + if (child->expand) + nexpand_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + { + width = (allocation->width - + GTK_CONTAINER (box)->border_width * 2 - + (nvis_children - 1) * box->spacing); + extra = width / nvis_children; + } + else if (nexpand_children > 0) + { + width = allocation->width - widget->requisition.width; + extra = width / nexpand_children; + } + else + { + width = 0; + extra = 0; + } + + x = allocation->x + GTK_CONTAINER (box)->border_width; + child_allocation.y = allocation->y + GTK_CONTAINER (box)->border_width; + child_allocation.height = allocation->height - GTK_CONTAINER (box)->border_width * 2; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_width = width; + else + child_width = extra; + + nvis_children -= 1; + width -= extra; + } + else + { + child_width = child->widget->requisition.width + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_width += width; + else + child_width += extra; + + nexpand_children -= 1; + width -= extra; + } + } + + if (child->fill) + { + child_allocation.width = child_width - child->padding * 2; + child_allocation.x = x + child->padding; + } + else + { + child_allocation.width = child->widget->requisition.width; + child_allocation.x = x + (child_width - child_allocation.width) / 2; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + x += child_width + box->spacing; + } + } + + x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_width = width; + else + child_width = extra; + + nvis_children -= 1; + width -= extra; + } + else + { + child_width = child->widget->requisition.width + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_width += width; + else + child_width += extra; + + nexpand_children -= 1; + width -= extra; + } + } + + if (child->fill) + { + child_allocation.width = child_width - child->padding * 2; + child_allocation.x = x + child->padding - child_width; + } + else + { + child_allocation.width = child->widget->requisition.width; + child_allocation.x = x + (child_width - child_allocation.width) / 2 - child_width; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + x -= (child_width + box->spacing); + } + } + } +} diff --git a/gtk/gtkhbox.h b/gtk/gtkhbox.h new file mode 100644 index 0000000000..7dfbb3dffb --- /dev/null +++ b/gtk/gtkhbox.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_HBOX_H__ +#define __GTK_HBOX_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbox.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HBOX(obj) GTK_CHECK_CAST (obj, gtk_hbox_get_type (), GtkHBox) +#define GTK_HBOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hbox_get_type (), GtkHBoxClass) +#define GTK_IS_HBOX(obj) GTK_CHECK_TYPE (obj, gtk_hbox_get_type ()) + + +typedef struct _GtkHBox GtkHBox; +typedef struct _GtkHBoxClass GtkHBoxClass; + +struct _GtkHBox +{ + GtkBox box; +}; + +struct _GtkHBoxClass +{ + GtkBoxClass parent_class; +}; + + +guint gtk_hbox_get_type (void); +GtkWidget* gtk_hbox_new (gint homogeneous, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HBOX_H__ */ diff --git a/gtk/gtkhpaned.c b/gtk/gtkhpaned.c new file mode 100644 index 0000000000..23c50961e8 --- /dev/null +++ b/gtk/gtkhpaned.c @@ -0,0 +1,355 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkhpaned.h" +#include "gtkmain.h" +#include "gtksignal.h" + +static void gtk_hpaned_class_init (GtkHPanedClass *klass); +static void gtk_hpaned_init (GtkHPaned *hpaned); +static void gtk_hpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_hpaned_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_hpaned_xor_line (GtkPaned *paned); +static gint gtk_hpaned_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_hpaned_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_hpaned_motion (GtkWidget *widget, + GdkEventMotion *event); + +guint +gtk_hpaned_get_type () +{ + static guint hpaned_type = 0; + + if (!hpaned_type) + { + GtkTypeInfo hpaned_info = + { + "GtkHPaned", + sizeof (GtkHPaned), + sizeof (GtkHPanedClass), + (GtkClassInitFunc) gtk_hpaned_class_init, + (GtkObjectInitFunc) gtk_hpaned_init, + (GtkArgFunc) NULL, + }; + + hpaned_type = gtk_type_unique (gtk_paned_get_type (), &hpaned_info); + } + + return hpaned_type; +} + +static void +gtk_hpaned_class_init (GtkHPanedClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_hpaned_size_request; + widget_class->size_allocate = gtk_hpaned_size_allocate; + widget_class->draw = gtk_hpaned_draw; + widget_class->button_press_event = gtk_hpaned_button_press; + widget_class->button_release_event = gtk_hpaned_button_release; + widget_class->motion_notify_event = gtk_hpaned_motion; +} + +static void +gtk_hpaned_init (GtkHPaned *hpaned) +{ +} + +GtkWidget* +gtk_hpaned_new () +{ + GtkHPaned *hpaned; + + hpaned = gtk_type_new (gtk_hpaned_get_type ()); + + return GTK_WIDGET (hpaned); +} + +static void +gtk_hpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HPANED (widget)); + g_return_if_fail (requisition != NULL); + + paned = GTK_PANED (widget); + requisition->width = 0; + requisition->height = 0; + + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + { + gtk_widget_size_request (paned->child1, &paned->child1->requisition); + + requisition->height = paned->child1->requisition.height; + requisition->width = paned->child1->requisition.width; + } + + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + { + gtk_widget_size_request (paned->child2, &paned->child2->requisition); + + requisition->height = MAX(requisition->height, + paned->child2->requisition.height); + requisition->width += paned->child2->requisition.width; + } + + requisition->width += GTK_CONTAINER (paned)->border_width * 2 + paned->gutter_size; + requisition->height += GTK_CONTAINER (paned)->border_width * 2; +} + +static void +gtk_hpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkPaned *paned; + GtkAllocation child1_allocation; + GtkAllocation child2_allocation; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HPANED (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (!paned->position_set) + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + paned->child1_size = paned->child1->requisition.width; + else + paned->child1_size = 0; + } + + /* Move the handle first so we don't get extra expose events */ + + paned->handle_xpos = allocation->x + paned->child1_size + border_width + paned->gutter_size / 2 - paned->handle_size / 2; + paned->handle_ypos = allocation->y + allocation->height - border_width - 2*paned->handle_size; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move (paned->handle, paned->handle_xpos, paned->handle_ypos); + gdk_window_raise (paned->handle); + } + + if (GTK_WIDGET_MAPPED (widget)) + { + gdk_window_clear_area (widget->window, + paned->groove_rectangle.x, + paned->groove_rectangle.y, + paned->groove_rectangle.width, + paned->groove_rectangle.height); + } + + child1_allocation.height = child2_allocation.height = allocation->height - border_width * 2; + child1_allocation.width = paned->child1_size; + child1_allocation.x = allocation->x + border_width; + child1_allocation.y = child2_allocation.y = allocation->y + border_width; + + paned->groove_rectangle.x = child1_allocation.x + + child1_allocation.width + paned->gutter_size / 2 - 1; + paned->groove_rectangle.y = allocation->y; + paned->groove_rectangle.width = 2; + paned->groove_rectangle.height = allocation->height; + + child2_allocation.x = paned->groove_rectangle.x + paned->gutter_size / 2 + 1; + child2_allocation.width = allocation->x + allocation->width + - child2_allocation.x - border_width; + + /* Now allocate the childen, making sure, when resizing not to + * overlap the windows */ + if (GTK_WIDGET_MAPPED(widget) && + paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) && + paned->child1->allocation.width < child1_allocation.width) + { + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + gtk_widget_size_allocate (paned->child1, &child1_allocation); + } + else + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + gtk_widget_size_allocate (paned->child1, &child1_allocation); + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + } +} + +static void +gtk_hpaned_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkPaned *paned; + GdkRectangle child_area; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (paned->child1 && + gtk_widget_intersect (paned->child1, area, &child_area)) + gtk_widget_draw (paned->child1, &child_area); + if (paned->child2 && + gtk_widget_intersect (paned->child2, area, &child_area)) + gtk_widget_draw (paned->child2, &child_area); + + gdk_draw_line (widget->window, + widget->style->dark_gc[widget->state], + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2 - 1, + widget->allocation.y, + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2 - 1, + widget->allocation.y + widget->allocation.height - 1); + gdk_draw_line (widget->window, + widget->style->light_gc[widget->state], + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2, + widget->allocation.y, + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2, + widget->allocation.y + widget->allocation.height - 1); + } +} + +static void +gtk_hpaned_xor_line (GtkPaned *paned) +{ + GtkWidget *widget; + GdkGCValues values; + guint16 xpos; + + widget = GTK_WIDGET(paned); + + if (!paned->xor_gc) + { + values.foreground = widget->style->white; + values.function = GDK_XOR; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + paned->xor_gc = gdk_gc_new_with_values (widget->window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_FUNCTION | + GDK_GC_SUBWINDOW); + } + + xpos = widget->allocation.x + paned->child1_size + + GTK_CONTAINER(paned)->border_width + paned->gutter_size / 2; + + gdk_draw_line (widget->window, paned->xor_gc, + xpos, + widget->allocation.y, + xpos, + widget->allocation.y + widget->allocation.height - 1); +} + +static gint +gtk_hpaned_button_press (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL,FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget),FALSE); + + paned = GTK_PANED (widget); + + if (!paned->in_drag && + (event->window == paned->handle) && (event->button == 1)) + { + paned->in_drag = TRUE; + /* We need a server grab here, not gtk_grab_add(), since + * we don't want to pass events on to the widget's children */ + gdk_pointer_grab (paned->handle, FALSE, + GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON1_MOTION_MASK + | GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time); + paned->child1_size += event->x - paned->handle_size / 2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.width - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_hpaned_xor_line (paned); + } + + return TRUE; +} + +static gint +gtk_hpaned_button_release (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL,FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget),FALSE); + + paned = GTK_PANED (widget); + + if (paned->in_drag && (event->button == 1)) + { + gtk_hpaned_xor_line (paned); + paned->in_drag = FALSE; + paned->position_set = TRUE; + gdk_pointer_ungrab (event->time); + gtk_widget_queue_resize (GTK_WIDGET (paned)); + } + + return TRUE; +} + +static gint +gtk_hpaned_motion (GtkWidget *widget, GdkEventMotion *event) +{ + GtkPaned *paned; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + + if (event->is_hint || event->window != widget->window) + gtk_widget_get_pointer(widget, &x, NULL); + else + x = event->x; + + paned = GTK_PANED (widget); + + if (paned->in_drag) + { + gtk_hpaned_xor_line (paned); + paned->child1_size = x - GTK_CONTAINER (paned)->border_width - paned->gutter_size / 2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.width - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_hpaned_xor_line (paned); + } + + return TRUE; +} diff --git a/gtk/gtkhpaned.h b/gtk/gtkhpaned.h new file mode 100644 index 0000000000..0a352e7999 --- /dev/null +++ b/gtk/gtkhpaned.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_HPANED_H__ +#define __GTK_HPANED_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkpaned.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HPANED(obj) GTK_CHECK_CAST (obj, gtk_hpaned_get_type (), GtkHPaned) +#define GTK_HPANED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hpaned_get_type (), GtkHPanedClass) +#define GTK_IS_HPANED(obj) GTK_CHECK_TYPE (obj, gtk_hpaned_get_type ()) + + +typedef struct _GtkHPaned GtkHPaned; +typedef struct _GtkHPanedClass GtkHPanedClass; + +struct _GtkHPaned +{ + GtkPaned paned; +}; + +struct _GtkHPanedClass +{ + GtkPanedClass parent_class; +}; + + +guint gtk_hpaned_get_type (void); +GtkWidget* gtk_hpaned_new (); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HPANED_H__ */ diff --git a/gtk/gtkhruler.c b/gtk/gtkhruler.c new file mode 100644 index 0000000000..ab6e69199e --- /dev/null +++ b/gtk/gtkhruler.c @@ -0,0 +1,277 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <math.h> +#include <stdio.h> +#include <string.h> +#include "gtkhruler.h" + + +#define RULER_HEIGHT 14 +#define MINIMUM_INCR 5 +#define MAXIMUM_SUBDIVIDE 5 +#define MAXIMUM_SCALES 10 + +#define ROUND(x) ((int) ((x) + 0.5)) + + +static void gtk_hruler_class_init (GtkHRulerClass *klass); +static void gtk_hruler_init (GtkHRuler *hruler); +static gint gtk_hruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_hruler_draw_ticks (GtkRuler *ruler); +static void gtk_hruler_draw_pos (GtkRuler *ruler); + + +guint +gtk_hruler_get_type () +{ + static guint hruler_type = 0; + + if (!hruler_type) + { + GtkTypeInfo hruler_info = + { + "GtkHRuler", + sizeof (GtkHRuler), + sizeof (GtkHRulerClass), + (GtkClassInitFunc) gtk_hruler_class_init, + (GtkObjectInitFunc) gtk_hruler_init, + (GtkArgFunc) NULL, + }; + + hruler_type = gtk_type_unique (gtk_ruler_get_type (), &hruler_info); + } + + return hruler_type; +} + +static void +gtk_hruler_class_init (GtkHRulerClass *klass) +{ + GtkWidgetClass *widget_class; + GtkRulerClass *ruler_class; + + widget_class = (GtkWidgetClass*) klass; + ruler_class = (GtkRulerClass*) klass; + + widget_class->motion_notify_event = gtk_hruler_motion_notify; + + ruler_class->draw_ticks = gtk_hruler_draw_ticks; + ruler_class->draw_pos = gtk_hruler_draw_pos; +} + +static void +gtk_hruler_init (GtkHRuler *hruler) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (hruler); + widget->requisition.width = widget->style->klass->xthickness * 2 + 1; + widget->requisition.height = widget->style->klass->ythickness * 2 + RULER_HEIGHT; +} + + +GtkWidget* +gtk_hruler_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_hruler_get_type ())); +} + +static gint +gtk_hruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkRuler *ruler; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_HRULER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + ruler = GTK_RULER (widget); + + if (event->is_hint) + gdk_window_get_pointer (widget->window, &x, NULL, NULL); + else + x = event->x; + + ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * x) / widget->allocation.width; + + /* Make sure the ruler has been allocated already */ + if (ruler->backing_store != NULL) + gtk_ruler_draw_pos (ruler); + + return FALSE; +} + +static void +gtk_hruler_draw_ticks (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + gint i; + gint width, height; + gint xthickness; + gint ythickness; + gint length; + gfloat subd_incr; + gfloat step_incr; + gfloat increment; + gfloat start, end, cur; + gchar unit_str[12]; + gint text_height; + gint digit_height; + gint pos; + gint scale; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_HRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + digit_height = widget->style->font->ascent; + + width = widget->allocation.width; + height = widget->allocation.height - ythickness * 2; + gdk_draw_line (ruler->backing_store, gc, + xthickness, + height + ythickness, + widget->allocation.width - xthickness, + height + ythickness); + + if ((ruler->upper - ruler->lower) == 0) + return; + + increment = (gfloat) width * ruler->metric->pixels_per_unit / (ruler->upper - ruler->lower); + + /* determine the scale + * use the maximum extents of the ruler to determine the largest possible + * number to be displayed. calculate the height in pixels of this displayed + * text as for the vertical ruler case. use this height to find a scale + * which leaves sufficient room for drawing the ruler. + */ + scale = ceil (ruler->max_size / ruler->metric->pixels_per_unit); + sprintf (unit_str, "%d", scale); + text_height = strlen (unit_str) * digit_height + 1; + + for (scale = 0; scale < MAXIMUM_SCALES; scale++) + if (ruler->metric->ruler_scale[scale] * increment > 2 * text_height) + break; + + if (scale == MAXIMUM_SCALES) + scale = MAXIMUM_SCALES - 1; + + for (i = 0; i < MAXIMUM_SUBDIVIDE; i++) + { + subd_incr = (gfloat) ruler->metric->ruler_scale[scale] / (gfloat) ruler->metric->subdivide[i]; + step_incr = subd_incr * increment; + if (step_incr <= MINIMUM_INCR) + break; + + start = floor ((ruler->lower / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + end = ceil ((ruler->upper / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + + length = height / (i + 1) - 1; + if (i > 0) + length -= 2; + + cur = start; + while (cur <= end) + { + pos = ROUND ((cur - (ruler->lower / ruler->metric->pixels_per_unit)) * increment); + + gdk_draw_line (ruler->backing_store, gc, + pos, height + ythickness, pos, + height - length + ythickness); + if (i == 0) + { + sprintf (unit_str, "%d", (int) cur); + gdk_draw_string (ruler->backing_store, widget->style->font, gc, + pos + 2, + ythickness + digit_height - 1, + unit_str); + } + + cur += subd_incr; + } + } + } +} + +static void +gtk_hruler_draw_pos (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + int i; + gint x, y; + gint width, height; + gint bs_width, bs_height; + gint xthickness; + gint ythickness; + gfloat increment; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_HRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + width = widget->allocation.width; + height = widget->allocation.height - ythickness * 2; + + bs_width = height / 2; + bs_width |= 1; /* make sure it's odd */ + bs_height = bs_width / 2 + 1; + + if ((bs_width > 0) && (bs_height > 0)) + { + /* If a backing store exists, restore the ruler */ + if (ruler->backing_store && ruler->non_gr_exp_gc) + gdk_draw_pixmap (ruler->widget.window, + ruler->non_gr_exp_gc, + ruler->backing_store, + ruler->xsrc, ruler->ysrc, + ruler->xsrc, ruler->ysrc, + bs_width, bs_height); + + increment = (gfloat) width / (ruler->upper - ruler->lower); + + x = ROUND ((ruler->position - ruler->lower) * increment) + (xthickness - bs_width) / 2 - 1; + y = (height + bs_height) / 2 + ythickness; + + for (i = 0; i < bs_height; i++) + gdk_draw_line (widget->window, gc, + x + i, y + i, + x + bs_width - 1 - i, y + i); + + + ruler->xsrc = x; + ruler->ysrc = y; + } + } +} diff --git a/gtk/gtkhruler.h b/gtk/gtkhruler.h new file mode 100644 index 0000000000..c4bc744364 --- /dev/null +++ b/gtk/gtkhruler.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_HRULER_H__ +#define __GTK_HRULER_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkruler.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HRULER(obj) GTK_CHECK_CAST (obj, gtk_hruler_get_type (), GtkHRuler) +#define GTK_HRULER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hruler_get_type (), GtkHRulerClass) +#define GTK_IS_HRULER(obj) GTK_CHECK_TYPE (obj, gtk_hruler_get_type ()) + + +typedef struct _GtkHRuler GtkHRuler; +typedef struct _GtkHRulerClass GtkHRulerClass; + +struct _GtkHRuler +{ + GtkRuler ruler; +}; + +struct _GtkHRulerClass +{ + GtkRulerClass parent_class; +}; + + +guint gtk_hruler_get_type (void); +GtkWidget* gtk_hruler_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HRULER_H__ */ diff --git a/gtk/gtkhscale.c b/gtk/gtkhscale.c new file mode 100644 index 0000000000..3bebd30fca --- /dev/null +++ b/gtk/gtkhscale.c @@ -0,0 +1,436 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include "gtkhscale.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define SCALE_CLASS(w) GTK_SCALE_CLASS (GTK_OBJECT (w)->klass) +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_hscale_class_init (GtkHScaleClass *klass); +static void gtk_hscale_init (GtkHScale *hscale); +static void gtk_hscale_realize (GtkWidget *widget); +static void gtk_hscale_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_hscale_pos_trough (GtkHScale *hscale, + gint *x, + gint *y, + gint *w, + gint *h); +static void gtk_hscale_draw_slider (GtkRange *range); +static void gtk_hscale_draw_value (GtkScale *scale); +static gint gtk_hscale_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + +guint +gtk_hscale_get_type () +{ + static guint hscale_type = 0; + + if (!hscale_type) + { + GtkTypeInfo hscale_info = + { + "GtkHScale", + sizeof (GtkHScale), + sizeof (GtkHScaleClass), + (GtkClassInitFunc) gtk_hscale_class_init, + (GtkObjectInitFunc) gtk_hscale_init, + (GtkArgFunc) NULL, + }; + + hscale_type = gtk_type_unique (gtk_scale_get_type (), &hscale_info); + } + + return hscale_type; +} + +static void +gtk_hscale_class_init (GtkHScaleClass *class) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + GtkScaleClass *scale_class; + + widget_class = (GtkWidgetClass*) class; + range_class = (GtkRangeClass*) class; + scale_class = (GtkScaleClass*) class; + + widget_class->realize = gtk_hscale_realize; + widget_class->size_request = gtk_hscale_size_request; + widget_class->size_allocate = gtk_hscale_size_allocate; + + range_class->slider_update = gtk_range_default_hslider_update; + range_class->trough_click = gtk_range_default_htrough_click; + range_class->motion = gtk_range_default_hmotion; + range_class->draw_slider = gtk_hscale_draw_slider; + range_class->trough_keys = gtk_hscale_trough_keys; + + scale_class->draw_value = gtk_hscale_draw_value; +} + +static void +gtk_hscale_init (GtkHScale *hscale) +{ +} + +GtkWidget* +gtk_hscale_new (GtkAdjustment *adjustment) +{ + GtkHScale *hscale; + + hscale = gtk_type_new (gtk_hscale_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (hscale), adjustment); + + return GTK_WIDGET (hscale); +} + + +static void +gtk_hscale_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + gint x, y, w, h; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCALE (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + + gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &w, &h); + attributes.x = x; + attributes.y = y; + attributes.width = w; + attributes.height = h; + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + range->trough = gdk_window_new (widget->window, &attributes, attributes_mask); + + attributes.width = SCALE_CLASS (range)->slider_length; + attributes.height = RANGE_CLASS (range)->slider_width; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (widget->window, widget); + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + + gtk_range_slider_update (GTK_RANGE (widget)); + + gdk_window_show (range->slider); + gdk_window_show (range->trough); +} + +static void +gtk_hscale_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkScale *scale; + gint value_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCALE (widget)); + g_return_if_fail (requisition != NULL); + + scale = GTK_SCALE (widget); + + requisition->width = (SCALE_CLASS (scale)->slider_length + + widget->style->klass->xthickness) * 2; + requisition->height = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->ythickness * 2); + + if (scale->draw_value) + { + value_width = gtk_scale_value_width (scale); + + if ((scale->value_pos == GTK_POS_LEFT) || + (scale->value_pos == GTK_POS_RIGHT)) + { + requisition->width += value_width + SCALE_CLASS (scale)->value_spacing; + if (requisition->height < (widget->style->font->ascent + widget->style->font->descent)) + requisition->height = widget->style->font->ascent + widget->style->font->descent; + } + else if ((scale->value_pos == GTK_POS_TOP) || + (scale->value_pos == GTK_POS_BOTTOM)) + { + if (requisition->width < value_width) + requisition->width = value_width; + requisition->height += widget->style->font->ascent + widget->style->font->descent; + } + } +} + +static void +gtk_hscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + GtkScale *scale; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCALE (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + scale = GTK_SCALE (widget); + + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height); + + gdk_window_move_resize (range->trough, x, y, width, height); + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_hscale_pos_trough (GtkHScale *hscale, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GtkWidget *widget; + GtkScale *scale; + + g_return_if_fail (hscale != NULL); + g_return_if_fail (GTK_IS_HSCALE (hscale)); + g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL)); + + widget = GTK_WIDGET (hscale); + scale = GTK_SCALE (hscale); + + *w = widget->allocation.width; + *h = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->ythickness * 2); + + if (scale->draw_value) + { + *x = 0; + *y = 0; + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + *x += gtk_scale_value_width (scale) + SCALE_CLASS (scale)->value_spacing; + *y = (widget->allocation.height - *h) / 2; + *w -= *x; + break; + case GTK_POS_RIGHT: + *w -= gtk_scale_value_width (scale) + SCALE_CLASS (scale)->value_spacing; + *y = (widget->allocation.height - *h) / 2; + break; + case GTK_POS_TOP: + *y = (widget->style->font->ascent + widget->style->font->descent + + (widget->allocation.height - widget->requisition.height) / 2); + break; + case GTK_POS_BOTTOM: + *y = (widget->allocation.height - widget->requisition.height) / 2; + break; + } + } + else + { + *x = 0; + *y = (widget->allocation.height - *h) / 2; + } + *x += 1; + *w -= 2; +} + +static void +gtk_hscale_draw_slider (GtkRange *range) +{ + GtkStateType state_type; + gint width, height; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCALE (range)); + + if (range->slider) + { + if ((range->in_child == RANGE_CLASS (range)->slider) || + (range->click_child == RANGE_CLASS (range)->slider)) + state_type = GTK_STATE_PRELIGHT; + else + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type); + gdk_window_clear (range->slider); + + gdk_window_get_size (range->slider, &width, &height); + gtk_draw_vline (GTK_WIDGET (range)->style, range->slider, + state_type, 1, height - 2, width / 2); + + gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider, + state_type, GTK_SHADOW_OUT, + 0, 0, -1, -1); + } +} + +static void +gtk_hscale_draw_value (GtkScale *scale) +{ + GtkStateType state_type; + gchar buffer[16]; + gint text_width; + gint width, height; + gint x, y; + + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_HSCALE (scale)); + + if (scale->draw_value) + { + gdk_window_get_size (GTK_WIDGET (scale)->window, &width, &height); + gdk_window_clear_area (GTK_WIDGET (scale)->window, 1, 1, width - 2, height - 2); + + sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value); + text_width = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height); + + x -= SCALE_CLASS (scale)->value_spacing + text_width; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_RIGHT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height); + + x += width + SCALE_CLASS (scale)->value_spacing; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_TOP: + gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y -= GTK_WIDGET (scale)->style->font->descent; + break; + case GTK_POS_BOTTOM: + gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y += height + GTK_WIDGET (scale)->style->font->ascent; + break; + } + + state_type = GTK_STATE_NORMAL; + if (!GTK_WIDGET_IS_SENSITIVE (scale)) + state_type = GTK_STATE_INSENSITIVE; + + gtk_draw_string (GTK_WIDGET (scale)->style, + GTK_WIDGET (scale)->window, + state_type, x, y, buffer); + } +} + +static gint +gtk_hscale_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Left: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *scroll = GTK_SCROLL_PAGE_BACKWARD; + else + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Right: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *scroll = GTK_SCROLL_PAGE_FORWARD; + else + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Home: + return_val = TRUE; + *pos = GTK_TROUGH_START; + break; + case GDK_End: + return_val = TRUE; + *pos = GTK_TROUGH_END; + break; + } + return return_val; +} diff --git a/gtk/gtkhscale.h b/gtk/gtkhscale.h new file mode 100644 index 0000000000..61ae4fdb31 --- /dev/null +++ b/gtk/gtkhscale.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_HSCALE_H__ +#define __GTK_HSCALE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkscale.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HSCALE(obj) GTK_CHECK_CAST (obj, gtk_hscale_get_type (), GtkHScale) +#define GTK_HSCALE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hscale_get_type (), GtkHScaleClass) +#define GTK_IS_HSCALE(obj) GTK_CHECK_TYPE (obj, gtk_hscale_get_type ()) + + +typedef struct _GtkHScale GtkHScale; +typedef struct _GtkHScaleClass GtkHScaleClass; + +struct _GtkHScale +{ + GtkScale scale; +}; + +struct _GtkHScaleClass +{ + GtkScaleClass parent_class; +}; + + +guint gtk_hscale_get_type (void); +GtkWidget* gtk_hscale_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HSCALE_H__ */ diff --git a/gtk/gtkhscrollbar.c b/gtk/gtkhscrollbar.c new file mode 100644 index 0000000000..9b757d406f --- /dev/null +++ b/gtk/gtkhscrollbar.c @@ -0,0 +1,383 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkhscrollbar.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define EPSILON 0.01 + +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_hscrollbar_class_init (GtkHScrollbarClass *klass); +static void gtk_hscrollbar_init (GtkHScrollbar *hscrollbar); +static void gtk_hscrollbar_realize (GtkWidget *widget); +static void gtk_hscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_hscrollbar_draw_step_forw (GtkRange *range); +static void gtk_hscrollbar_draw_step_back (GtkRange *range); +static void gtk_hscrollbar_slider_update (GtkRange *range); +static void gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar); +static gint gtk_hscrollbar_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + + +guint +gtk_hscrollbar_get_type () +{ + static guint hscrollbar_type = 0; + + if (!hscrollbar_type) + { + GtkTypeInfo hscrollbar_info = + { + "GtkHScrollbar", + sizeof (GtkHScrollbar), + sizeof (GtkHScrollbarClass), + (GtkClassInitFunc) gtk_hscrollbar_class_init, + (GtkObjectInitFunc) gtk_hscrollbar_init, + (GtkArgFunc) NULL, + }; + + hscrollbar_type = gtk_type_unique (gtk_scrollbar_get_type (), &hscrollbar_info); + } + + return hscrollbar_type; +} + +static void +gtk_hscrollbar_class_init (GtkHScrollbarClass *class) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + + widget_class = (GtkWidgetClass*) class; + range_class = (GtkRangeClass*) class; + + widget_class->realize = gtk_hscrollbar_realize; + widget_class->size_allocate = gtk_hscrollbar_size_allocate; + + range_class->draw_step_forw = gtk_hscrollbar_draw_step_forw; + range_class->draw_step_back = gtk_hscrollbar_draw_step_back; + range_class->slider_update = gtk_hscrollbar_slider_update; + range_class->trough_click = gtk_range_default_htrough_click; + range_class->trough_keys = gtk_hscrollbar_trough_keys; + range_class->motion = gtk_range_default_hmotion; +} + +static void +gtk_hscrollbar_init (GtkHScrollbar *hscrollbar) +{ + GtkWidget *widget; + GtkRequisition *requisition; + + widget = GTK_WIDGET (hscrollbar); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + requisition = &widget->requisition; + + requisition->width = (RANGE_CLASS (widget)->min_slider_size + + RANGE_CLASS (widget)->stepper_size + + RANGE_CLASS (widget)->stepper_slider_spacing + + widget->style->klass->xthickness) * 2; + requisition->height = (RANGE_CLASS (widget)->slider_width + + widget->style->klass->ythickness * 2); +} + +GtkWidget* +gtk_hscrollbar_new (GtkAdjustment *adjustment) +{ + GtkHScrollbar *hscrollbar; + + hscrollbar = gtk_type_new (gtk_hscrollbar_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (hscrollbar), adjustment); + + return GTK_WIDGET (hscrollbar); +} + + +static void +gtk_hscrollbar_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y + (widget->allocation.height - widget->requisition.height) / 2; + attributes.width = widget->allocation.width; + attributes.height = widget->requisition.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + range->trough = widget->window; + + attributes.x = widget->style->klass->xthickness; + attributes.y = widget->style->klass->ythickness; + attributes.width = RANGE_CLASS (widget)->stepper_size; + attributes.height = RANGE_CLASS (widget)->stepper_size; + + range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.x = (widget->allocation.width - + widget->style->klass->xthickness - + RANGE_CLASS (widget)->stepper_size); + + range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.x = 0; + attributes.y = widget->style->klass->ythickness; + attributes.width = RANGE_CLASS (widget)->min_slider_size; + attributes.height = RANGE_CLASS (widget)->slider_width; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (widget)); + gtk_range_slider_update (GTK_RANGE (widget)); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + gdk_window_set_user_data (range->step_forw, widget); + gdk_window_set_user_data (range->step_back, widget); + + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE); + + gdk_window_show (range->slider); + gdk_window_show (range->step_forw); + gdk_window_show (range->step_back); +} + +static void +gtk_hscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + + gdk_window_move_resize (range->trough, + allocation->x, + allocation->y + (allocation->height - widget->requisition.height) / 2, + allocation->width, widget->requisition.height); + gdk_window_move_resize (range->step_back, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + RANGE_CLASS (widget)->stepper_size, + widget->requisition.height - widget->style->klass->ythickness * 2); + gdk_window_move_resize (range->step_forw, + allocation->width - widget->style->klass->xthickness - + RANGE_CLASS (widget)->stepper_size, + widget->style->klass->ythickness, + RANGE_CLASS (widget)->stepper_size, + widget->requisition.height - widget->style->klass->ythickness * 2); + gdk_window_resize (range->slider, + RANGE_CLASS (widget)->min_slider_size, + widget->requisition.height - widget->style->klass->ythickness * 2); + + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_hscrollbar_draw_step_forw (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_forw) + { + if (range->click_child == RANGE_CLASS (range)->step_forw) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_forw) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_forw, + state_type, shadow_type, GTK_ARROW_RIGHT, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_hscrollbar_draw_step_back (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_back) + { + if (range->click_child == RANGE_CLASS (range)->step_back) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_back) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_back, + state_type, shadow_type, GTK_ARROW_LEFT, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_hscrollbar_slider_update (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (range)); + + gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (range)); + gtk_range_default_hslider_update (range); +} + +static void +gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar) +{ + GtkRange *range; + gint step_back_x; + gint step_back_width; + gint step_forw_x; + gint slider_width; + gint slider_height; + gint left, right; + gint width; + + g_return_if_fail (hscrollbar != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (hscrollbar)); + + if (GTK_WIDGET_REALIZED (hscrollbar)) + { + range = GTK_RANGE (hscrollbar); + + gdk_window_get_size (range->step_back, &step_back_width, NULL); + gdk_window_get_position (range->step_back, &step_back_x, NULL); + gdk_window_get_position (range->step_forw, &step_forw_x, NULL); + + left = (step_back_x + + step_back_width + + RANGE_CLASS (hscrollbar)->stepper_slider_spacing); + right = step_forw_x - RANGE_CLASS (hscrollbar)->stepper_slider_spacing; + width = right - left; + + if ((range->adjustment->page_size > 0) && + (range->adjustment->lower != range->adjustment->upper)) + { + if (range->adjustment->page_size > + (range->adjustment->upper - range->adjustment->lower)) + range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower; + + width = (width * range->adjustment->page_size / + (range->adjustment->upper - range->adjustment->lower)); + + if (width < RANGE_CLASS (hscrollbar)->min_slider_size) + width = RANGE_CLASS (hscrollbar)->min_slider_size; + } + + gdk_window_get_size (range->slider, &slider_width, &slider_height); + + if (slider_width != width) + gdk_window_resize (range->slider, width, slider_height); + } +} + +static gint +gtk_hscrollbar_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Left: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Right: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Home: + return_val = TRUE; + *pos = GTK_TROUGH_START; + break; + case GDK_End: + return_val = TRUE; + *pos = GTK_TROUGH_END; + break; + } + return return_val; +} diff --git a/gtk/gtkhscrollbar.h b/gtk/gtkhscrollbar.h new file mode 100644 index 0000000000..7d69512592 --- /dev/null +++ b/gtk/gtkhscrollbar.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_HSCROLLBAR_H__ +#define __GTK_HSCROLLBAR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkscrollbar.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HSCROLLBAR(obj) GTK_CHECK_CAST (obj, gtk_hscrollbar_get_type (), GtkHScrollbar) +#define GTK_HSCROLLBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hscrollbar_get_type (), GtkHScrollbarClass) +#define GTK_IS_HSCROLLBAR(obj) GTK_CHECK_TYPE (obj, gtk_hscrollbar_get_type ()) + + +typedef struct _GtkHScrollbar GtkHScrollbar; +typedef struct _GtkHScrollbarClass GtkHScrollbarClass; + +struct _GtkHScrollbar +{ + GtkScrollbar scrollbar; +}; + +struct _GtkHScrollbarClass +{ + GtkScrollbarClass parent_class; +}; + + +guint gtk_hscrollbar_get_type (void); +GtkWidget* gtk_hscrollbar_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HSCROLLBAR_H__ */ diff --git a/gtk/gtkhseparator.c b/gtk/gtkhseparator.c new file mode 100644 index 0000000000..5f3a38c209 --- /dev/null +++ b/gtk/gtkhseparator.c @@ -0,0 +1,90 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkhseparator.h" + + +static void gtk_hseparator_class_init (GtkHSeparatorClass *klass); +static void gtk_hseparator_init (GtkHSeparator *hseparator); +static gint gtk_hseparator_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_hseparator_get_type () +{ + static guint hseparator_type = 0; + + if (!hseparator_type) + { + GtkTypeInfo hseparator_info = + { + "GtkHSeparator", + sizeof (GtkHSeparator), + sizeof (GtkHSeparatorClass), + (GtkClassInitFunc) gtk_hseparator_class_init, + (GtkObjectInitFunc) gtk_hseparator_init, + (GtkArgFunc) NULL, + }; + + hseparator_type = gtk_type_unique (gtk_separator_get_type (), &hseparator_info); + } + + return hseparator_type; +} + +static void +gtk_hseparator_class_init (GtkHSeparatorClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_hseparator_expose; +} + +static void +gtk_hseparator_init (GtkHSeparator *hseparator) +{ + GTK_WIDGET (hseparator)->requisition.width = 1; + GTK_WIDGET (hseparator)->requisition.height = GTK_WIDGET (hseparator)->style->klass->ythickness; +} + +GtkWidget* +gtk_hseparator_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_hseparator_get_type ())); +} + + +static gint +gtk_hseparator_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_HSEPARATOR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_draw_hline (widget->style, widget->window, GTK_STATE_NORMAL, + widget->allocation.x, + widget->allocation.x + widget->allocation.width, + widget->allocation.y + (widget->allocation.height - + widget->style->klass->ythickness) / 2); + + return FALSE; +} diff --git a/gtk/gtkhseparator.h b/gtk/gtkhseparator.h new file mode 100644 index 0000000000..9902631516 --- /dev/null +++ b/gtk/gtkhseparator.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_HSEPARATOR_H__ +#define __GTK_HSEPARATOR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkseparator.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HSEPARATOR(obj) GTK_CHECK_CAST (obj, gtk_hseparator_get_type (), GtkHSeparator) +#define GTK_HSEPARATOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hseparator_get_type (), GtkHSeparatorClass) +#define GTK_IS_HSEPARATOR(obj) GTK_CHECK_TYPE (obj, gtk_hseparator_get_type ()) + + +typedef struct _GtkHSeparator GtkHSeparator; +typedef struct _GtkHSeparatorClass GtkHSeparatorClass; + +struct _GtkHSeparator +{ + GtkSeparator separator; +}; + +struct _GtkHSeparatorClass +{ + GtkSeparatorClass parent_class; +}; + + +guint gtk_hseparator_get_type (void); +GtkWidget* gtk_hseparator_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HSEPARATOR_H__ */ diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c new file mode 100644 index 0000000000..fddd06a5dc --- /dev/null +++ b/gtk/gtkimage.c @@ -0,0 +1,181 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkcontainer.h" +#include "gtkimage.h" + + +static void gtk_image_class_init (GtkImageClass *klass); +static void gtk_image_init (GtkImage *image); +static gint gtk_image_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_image_get_type () +{ + static guint image_type = 0; + + if (!image_type) + { + GtkTypeInfo image_info = + { + "GtkImage", + sizeof (GtkImage), + sizeof (GtkImageClass), + (GtkClassInitFunc) gtk_image_class_init, + (GtkObjectInitFunc) gtk_image_init, + (GtkArgFunc) NULL, + }; + + image_type = gtk_type_unique (gtk_misc_get_type (), &image_info); + } + + return image_type; +} + +static void +gtk_image_class_init (GtkImageClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_image_expose; +} + +static void +gtk_image_init (GtkImage *image) +{ + GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW); + + image->image = NULL; + image->mask = NULL; +} + +GtkWidget* +gtk_image_new (GdkImage *val, + GdkBitmap *mask) +{ + GtkImage *image; + + g_return_val_if_fail (val != NULL, NULL); + + image = gtk_type_new (gtk_image_get_type ()); + + gtk_image_set (image, val, mask); + + return GTK_WIDGET (image); +} + +void +gtk_image_set (GtkImage *image, + GdkImage *val, + GdkBitmap *mask) +{ + g_return_if_fail (image != NULL); + g_return_if_fail (GTK_IS_IMAGE (image)); + + image->image = val; + image->mask = mask; + + if (image->image) + { + GTK_WIDGET (image)->requisition.width = image->image->width + GTK_MISC (image)->xpad * 2; + GTK_WIDGET (image)->requisition.height = image->image->height + GTK_MISC (image)->ypad * 2; + } + else + { + GTK_WIDGET (image)->requisition.width = 0; + GTK_WIDGET (image)->requisition.height = 0; + } + + if (GTK_WIDGET_VISIBLE (image)) + gtk_widget_queue_resize (GTK_WIDGET (image)); +} + +void +gtk_image_get (GtkImage *image, + GdkImage **val, + GdkBitmap **mask) +{ + g_return_if_fail (image != NULL); + g_return_if_fail (GTK_IS_IMAGE (image)); + + if (val) + *val = image->image; + if (mask) + *mask = image->mask; +} + + +static gint +gtk_image_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkImage *image; + GtkMisc *misc; + GdkRectangle area; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + image = GTK_IMAGE (widget); + misc = GTK_MISC (widget); + + x = (widget->allocation.x * (1.0 - misc->xalign) + + (widget->allocation.x + widget->allocation.width + - (widget->requisition.width - misc->xpad * 2)) * + misc->xalign) + 0.5; + y = (widget->allocation.y * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height + - (widget->requisition.height - misc->ypad * 2)) * + misc->yalign) + 0.5; + + if (image->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, image->mask); + gdk_gc_set_clip_origin (widget->style->black_gc, x, y); + } + + area = event->area; + if ((area.x < 0) || (area.y < 0)) + { + area.x = area.y = 0; + area.width = image->image->width; + area.height = image->image->height; + } + + gdk_draw_image (widget->window, + widget->style->black_gc, + image->image, + area.x, area.y, x+area.x, y+area.y, + area.width, area.height); + + if (image->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, NULL); + gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0); + } + } + + return FALSE; +} diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h new file mode 100644 index 0000000000..d3481d51dd --- /dev/null +++ b/gtk/gtkimage.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_IMAGE_H__ +#define __GTK_IMAGE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkmisc.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_IMAGE(obj) GTK_CHECK_CAST (obj, gtk_image_get_type (), GtkImage) +#define GTK_IMAGE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_image_get_type (), GtkImageClass) +#define GTK_IS_IMAGE(obj) GTK_CHECK_TYPE (obj, gtk_image_get_type ()) + + +typedef struct _GtkImage GtkImage; +typedef struct _GtkImageClass GtkImageClass; + +struct _GtkImage +{ + GtkMisc misc; + + GdkImage *image; + GdkBitmap *mask; +}; + +struct _GtkImageClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_image_get_type (void); +GtkWidget* gtk_image_new (GdkImage *val, + GdkBitmap *mask); +void gtk_image_set (GtkImage *image, + GdkImage *val, + GdkBitmap *mask); +void gtk_image_get (GtkImage *image, + GdkImage **val, + GdkBitmap **mask); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_IMAGE_H__ */ diff --git a/gtk/gtkinputdialog.c b/gtk/gtkinputdialog.c new file mode 100644 index 0000000000..1d412a32ea --- /dev/null +++ b/gtk/gtkinputdialog.c @@ -0,0 +1,546 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +/* + * gtkinputdialog.c + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "gdk/gdkkeysyms.h" +#include "gtkbutton.h" +#include "gtkhbox.h" +#include "gtkhseparator.h" +#include "gtkinputdialog.h" +#include "gtklabel.h" +#include "gtklistitem.h" +#include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtkoptionmenu.h" +#include "gtkscrolledwindow.h" +#include "gtksignal.h" +#include "gtkvbox.h" + +typedef void (*GtkInputDialogSignal1) (GtkObject *object, + int arg1, + gpointer data); + +enum +{ + ENABLE_DEVICE, + DISABLE_DEVICE, + LAST_SIGNAL +}; + + +#define AXIS_LIST_WIDTH 160 +#define AXIS_LIST_HEIGHT 175 + +/* Forward declarations */ + +static void gtk_input_dialog_marshal_signal1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_input_dialog_class_init (GtkInputDialogClass *klass); +static void gtk_input_dialog_init (GtkInputDialog *inputd); +static GdkDeviceInfo *gtk_input_dialog_get_device_info(guint32 deviceid); +static void gtk_input_dialog_set_device(GtkWidget *widget, gpointer data); +static void gtk_input_dialog_destroy (GtkObject *object); +static void gtk_input_dialog_set_mapping_mode(GtkWidget *w, + gpointer data); +static void gtk_input_dialog_set_axis(GtkWidget *widget, gpointer data); +static void gtk_input_dialog_fill_axes (GtkInputDialog *inputd, + GdkDeviceInfo *info); + +static GtkObjectClass *parent_class = NULL; +static gint input_dialog_signals[LAST_SIGNAL] = { 0 }; + +static void +gtk_input_dialog_marshal_signal1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkInputDialogSignal1 rfunc; + + rfunc = (GtkInputDialogSignal1) func; + (* rfunc) (object, GTK_VALUE_INT(args[0]), func_data); +} + +static GdkDeviceInfo * +gtk_input_dialog_get_device_info(guint32 deviceid) +{ + GList *tmp_list = gdk_input_list_devices(); + while (tmp_list) + { + if (((GdkDeviceInfo *)tmp_list->data)->deviceid == deviceid) + return (GdkDeviceInfo *)tmp_list->data; + tmp_list = tmp_list->next; + } + + return NULL; +} + +guint +gtk_input_dialog_get_type () +{ + static guint input_dialog_type = 0; + + if (!input_dialog_type) + { + GtkTypeInfo input_dialog_info = + { + "GtkInputDialog", + sizeof (GtkInputDialog), + sizeof (GtkInputDialogClass), + (GtkClassInitFunc) gtk_input_dialog_class_init, + (GtkObjectInitFunc) gtk_input_dialog_init, + (GtkArgFunc) NULL, + }; + + input_dialog_type = gtk_type_unique (gtk_dialog_get_type (), + &input_dialog_info); + } + + return input_dialog_type; +} + +static void +gtk_input_dialog_class_init (GtkInputDialogClass *klass) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) klass; + + parent_class = gtk_type_class (gtk_dialog_get_type ()); + + input_dialog_signals[ENABLE_DEVICE] = + gtk_signal_new ("enable_device", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkInputDialogClass, enable_device), + gtk_input_dialog_marshal_signal1, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + input_dialog_signals[DISABLE_DEVICE] = + gtk_signal_new ("disable_device", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkInputDialogClass, disable_device), + gtk_input_dialog_marshal_signal1, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, input_dialog_signals, + LAST_SIGNAL); + + + object_class->destroy = gtk_input_dialog_destroy; + klass->enable_device = NULL; + klass->disable_device = NULL; +} + +static void +gtk_input_dialog_init (GtkInputDialog *inputd) +{ + GtkWidget *vbox; + GtkWidget *util_box; + GtkWidget *label; + GtkWidget *device_menu; + GtkWidget *mapping_menu; + GtkWidget *menuitem; + GtkWidget *optionmenu; + GtkWidget *separator; + + GList *tmp_list; + GList *device_info; + + device_info = gdk_input_list_devices(); + + /* shell and main vbox */ + + gtk_window_set_title (GTK_WINDOW (inputd), "Input"); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_border_width(GTK_CONTAINER (vbox), 5); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (inputd)->vbox), vbox, TRUE, TRUE, 0); + + if (g_list_length(device_info) <= 1) /* only core device */ + { + label = gtk_label_new ("No input devices"); + gtk_container_add (GTK_CONTAINER (vbox), label); + + gtk_widget_show (label); + } + else + { + /* menu for selecting device */ + + device_menu = gtk_menu_new (); + + for (tmp_list = device_info; tmp_list; tmp_list = tmp_list->next) { + GdkDeviceInfo *info = (GdkDeviceInfo *)(tmp_list->data); + if (info->deviceid != GDK_CORE_POINTER) + { + menuitem = gtk_menu_item_new_with_label(info->name); + + gtk_menu_append(GTK_MENU(device_menu),menuitem); + gtk_widget_show(menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_device, + (gpointer)((long)info->deviceid)); + } + } + + util_box = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); + + label = gtk_label_new("Device:"); + gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); + + optionmenu = gtk_option_menu_new (); + gtk_box_pack_start (GTK_BOX (util_box), optionmenu, TRUE, TRUE, 2); + gtk_widget_show (optionmenu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), device_menu); + + gtk_widget_show (label); + gtk_widget_show (util_box); + + /* Device options */ + + separator = gtk_hseparator_new(); + gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + util_box = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); + + /* mapping mode option menu */ + + mapping_menu = gtk_menu_new (); + + menuitem = gtk_menu_item_new_with_label("Disabled"); + gtk_menu_append(GTK_MENU(mapping_menu),menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_widget_show(menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_mapping_mode, + (gpointer)((long)GDK_MODE_DISABLED)); + + menuitem = gtk_menu_item_new_with_label("Screen"); + gtk_menu_append(GTK_MENU(mapping_menu),menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_widget_show(menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_mapping_mode, + (gpointer)((long)GDK_MODE_SCREEN)); + + menuitem = gtk_menu_item_new_with_label("Window"); + gtk_menu_append(GTK_MENU(mapping_menu),menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_widget_show(menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_mapping_mode, + (gpointer)((long)GDK_MODE_WINDOW)); + + label = gtk_label_new("Mode: "); + gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); + + inputd->mode_optionmenu = gtk_option_menu_new (); + gtk_box_pack_start (GTK_BOX (util_box), inputd->mode_optionmenu, FALSE, FALSE, 2); + gtk_widget_show (inputd->mode_optionmenu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (inputd->mode_optionmenu), mapping_menu); + + gtk_widget_show(label); + + gtk_widget_show (util_box); + + util_box = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX(vbox), util_box, FALSE, FALSE, 0); + + gtk_widget_show (label); + gtk_widget_show (util_box); + + /* The axis listbox */ + + label = gtk_label_new ("Axes"); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + inputd->axis_listbox = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_usize (inputd->axis_listbox, AXIS_LIST_WIDTH, AXIS_LIST_HEIGHT); + gtk_box_pack_start (GTK_BOX (vbox), inputd->axis_listbox, TRUE, TRUE, 0); + gtk_widget_show (inputd->axis_listbox); + + inputd->axis_list = 0; + + gtk_widget_show(label); + + /* ...set_device expects to get input dialog from widget user data */ + gtk_object_set_user_data (GTK_OBJECT (inputd), inputd); + gtk_input_dialog_set_device(GTK_WIDGET(inputd), (gpointer)((long) + ((GdkDeviceInfo *)device_info->data)->deviceid)); + } + + /* buttons */ + + inputd->save_button = gtk_button_new_with_label ("Save"); + GTK_WIDGET_SET_FLAGS (inputd->save_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(inputd)->action_area), + inputd->save_button, TRUE, TRUE, 0); + gtk_widget_show (inputd->save_button); + + inputd->close_button = gtk_button_new_with_label ("Close"); + GTK_WIDGET_SET_FLAGS (inputd->close_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(inputd)->action_area), + inputd->close_button, TRUE, TRUE, 0); + + gtk_widget_show (inputd->close_button); + gtk_widget_grab_default (inputd->close_button); + + gtk_widget_show (vbox); +} + + +GtkWidget* +gtk_input_dialog_new (void) +{ + GtkInputDialog *inputd; + + inputd = gtk_type_new (gtk_input_dialog_get_type ()); + + return GTK_WIDGET (inputd); +} + +static void +gtk_input_dialog_set_device(GtkWidget *widget, gpointer data) +{ + guint32 deviceid = (guint32)data; + GdkDeviceInfo *info; + + GtkInputDialog *inputd = GTK_INPUT_DIALOG( + gtk_object_get_user_data(GTK_OBJECT(widget))); + + inputd->current_device = deviceid; + info = gtk_input_dialog_get_device_info((guint32)data); + + gtk_input_dialog_fill_axes(inputd, info); + + gtk_option_menu_set_history(GTK_OPTION_MENU(inputd->mode_optionmenu), + info->mode); +} + +static void +gtk_input_dialog_destroy (GtkObject *object) +{ + /* GtkInputDialog *inputd = GTK_INPUT_DIALOG (object); */ + + /* Clean up ? */ + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_input_dialog_set_mapping_mode(GtkWidget *w, + gpointer data) +{ + GtkInputDialog *inputd = GTK_INPUT_DIALOG( + gtk_object_get_user_data(GTK_OBJECT(w))); + GdkDeviceInfo *info = gtk_input_dialog_get_device_info (inputd->current_device); + GdkInputMode old_mode = info->mode; + GdkInputMode mode = (GdkInputMode)data; + + if (mode != old_mode) + { + if (gdk_input_set_mode(inputd->current_device, mode)) + { + if (mode == GDK_MODE_DISABLED) + gtk_signal_emit (GTK_OBJECT (inputd), + input_dialog_signals[DISABLE_DEVICE], + info->deviceid); + else + gtk_signal_emit (GTK_OBJECT (inputd), + input_dialog_signals[ENABLE_DEVICE], + info->deviceid); + } + else + gtk_option_menu_set_history (GTK_OPTION_MENU (inputd->mode_optionmenu), + old_mode); + + /* FIXME: error dialog ? */ + } +} + +static void +gtk_input_dialog_set_axis(GtkWidget *widget, gpointer data) +{ + GdkAxisUse use = (GdkAxisUse)data & 0xFFFF; + GdkAxisUse old_use; + GdkAxisUse *new_axes; + GtkInputDialog *inputd = GTK_INPUT_DIALOG (gtk_object_get_user_data (GTK_OBJECT (widget))); + GdkDeviceInfo *info = gtk_input_dialog_get_device_info (inputd->current_device); + + gint axis = ((gint)data >> 16) - 1; + gint old_axis; + int i; + + new_axes = g_new (GdkAxisUse, info->num_axes); + old_axis = -1; + for (i=0;i<info->num_axes;i++) + { + new_axes[i] = info->axes[i]; + if (info->axes[i] == use) + old_axis = i; + } + + if (axis != -1) + old_use = info->axes[axis]; + else + old_use = GDK_AXIS_IGNORE; + + if (axis == old_axis) + return; + + /* we must always have an x and a y axis */ + if ((axis == -1 && (use == GDK_AXIS_X || use == GDK_AXIS_Y)) || + (old_axis == -1 && (old_use == GDK_AXIS_X || old_use == GDK_AXIS_Y))) + { + gtk_option_menu_set_history ( + GTK_OPTION_MENU (inputd->axis_items[use]), + old_axis + 1); + } + else + { + if (axis != -1) + new_axes[axis] = use; + + if (old_axis != -1) + new_axes[old_axis] = old_use; + + if (old_use != GDK_AXIS_IGNORE) + { + gtk_option_menu_set_history ( + GTK_OPTION_MENU (inputd->axis_items[old_use]), + old_axis + 1); + } + gdk_input_set_axes (info->deviceid, new_axes); + } + + g_free (new_axes); +} + +static void +gtk_input_dialog_fill_axes(GtkInputDialog *inputd, GdkDeviceInfo *info) +{ + static char *axis_use_strings[GDK_AXIS_LAST] = + { + "", + "X", + "Y", + "Pressure", + "X Tilt", + "Y Tilt" + }; + + int i,j; + GtkWidget *list_item; + GtkWidget *menu; + GtkWidget *option_menu; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + + /* remove all the old items */ + if (inputd->axis_list) + { + gtk_widget_hide (inputd->axis_list); /* suppress resizes (or get warnings) */ + gtk_widget_destroy (inputd->axis_list); + } + inputd->axis_list = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (inputd->axis_listbox), inputd->axis_list); + gtk_widget_show (inputd->axis_list); + + gtk_widget_realize (inputd->axis_list); + gdk_window_set_background (inputd->axis_list->window, + &inputd->axis_list->style->white); + + for (i=GDK_AXIS_X;i<GDK_AXIS_LAST;i++) + { + list_item = gtk_list_item_new(); + + gtk_box_pack_start(GTK_BOX(inputd->axis_list),list_item,FALSE,FALSE,0); + gtk_widget_show (list_item); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add(GTK_CONTAINER (list_item), vbox); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 1); + + /* create the label */ + + label = gtk_label_new(axis_use_strings[i]); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 2); + + /* and the use option menu */ + menu = gtk_menu_new(); + + for (j = -1; j < info->num_axes; j++) + { + char buffer[16]; + GtkWidget *menu_item; + + if (j == -1) + menu_item = gtk_menu_item_new_with_label ("none"); + else + { + sprintf (buffer,"%d",j+1); + menu_item = gtk_menu_item_new_with_label (buffer); + } + gtk_object_set_user_data (GTK_OBJECT (menu_item), inputd); + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) gtk_input_dialog_set_axis, + (gpointer) ((long) (0x10000 * (j + 1) + i))); + gtk_widget_show (menu_item); + gtk_menu_append (GTK_MENU (menu), menu_item); + } + + inputd->axis_items[i] = option_menu = gtk_option_menu_new (); + gtk_box_pack_start (GTK_BOX (hbox), option_menu, FALSE, FALSE, 2); + + gtk_widget_show (option_menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + for (j = 0; j < info->num_axes; j++) + if (info->axes[j] == (GdkAxisUse) i) + { + gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), j+1); + break; + } + + gtk_widget_show (label); + + gtk_widget_show (hbox); + gtk_widget_show (vbox); + } +} diff --git a/gtk/gtkinputdialog.h b/gtk/gtkinputdialog.h new file mode 100644 index 0000000000..93c667f440 --- /dev/null +++ b/gtk/gtkinputdialog.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_INPUTDIALOG_H__ +#define __GTK_INPUTDIALOG_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkdialog.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_INPUT_DIALOG(obj) GTK_CHECK_CAST (obj, gtk_input_dialog_get_type (), GtkInputDialog) +#define GTK_INPUT_DIALOG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_input_dialog_get_type (), GtkInputDialogClass) +#define GTK_IS_INPUT_DIALOG(obj) GTK_CHECK_TYPE (obj, gtk_input_dialog_get_type ()) + + +typedef struct _GtkInputDialog GtkInputDialog; +typedef struct _GtkInputDialogClass GtkInputDialogClass; + +struct _GtkInputDialog +{ + GtkDialog dialog; + + GtkWidget *axis_list; + GtkWidget *axis_listbox; + GtkWidget *mode_optionmenu; + + GtkWidget *close_button; + GtkWidget *save_button; + + GtkWidget *axis_items[GDK_AXIS_LAST]; + guint32 current_device; +}; + +struct _GtkInputDialogClass +{ + GtkWindowClass parent_class; + + void (* enable_device) (GtkInputDialog *inputd, + guint32 devid, + gpointer *data); + void (* disable_device) (GtkInputDialog *inputd, + guint32 devid, + gpointer *data); +}; + + +guint gtk_input_dialog_get_type (void); +GtkWidget* gtk_input_dialog_new (); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_INPUTDIALOG_H__ */ diff --git a/gtk/gtkitem.c b/gtk/gtkitem.c new file mode 100644 index 0000000000..6dd0ec8dd8 --- /dev/null +++ b/gtk/gtkitem.c @@ -0,0 +1,191 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkitem.h" +#include "gtksignal.h" + + +enum { + SELECT, + DESELECT, + TOGGLE, + LAST_SIGNAL +}; + + +static void gtk_item_class_init (GtkItemClass *klass); +static void gtk_item_init (GtkItem *item); +static void gtk_item_map (GtkWidget *widget); +static void gtk_item_unmap (GtkWidget *widget); +static void gtk_item_realize (GtkWidget *widget); + + +static gint item_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_item_get_type () +{ + static guint item_type = 0; + + if (!item_type) + { + GtkTypeInfo item_info = + { + "GtkItem", + sizeof (GtkItem), + sizeof (GtkItemClass), + (GtkClassInitFunc) gtk_item_class_init, + (GtkObjectInitFunc) gtk_item_init, + (GtkArgFunc) NULL, + }; + + item_type = gtk_type_unique (gtk_bin_get_type (), &item_info); + } + + return item_type; +} + +static void +gtk_item_class_init (GtkItemClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + item_signals[SELECT] = + gtk_signal_new ("select", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkItemClass, select), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + item_signals[DESELECT] = + gtk_signal_new ("deselect", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkItemClass, deselect), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + item_signals[TOGGLE] = + gtk_signal_new ("toggle", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkItemClass, toggle), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, item_signals, LAST_SIGNAL); + + widget_class->activate_signal = item_signals[TOGGLE]; + widget_class->map = gtk_item_map; + widget_class->unmap = gtk_item_unmap; + widget_class->realize = gtk_item_realize; + + class->select = NULL; + class->deselect = NULL; + class->toggle = NULL; +} + +static void +gtk_item_init (GtkItem *item) +{ + GTK_WIDGET_UNSET_FLAGS (item, GTK_NO_WINDOW); +} + +void +gtk_item_select (GtkItem *item) +{ + gtk_signal_emit (GTK_OBJECT (item), item_signals[SELECT]); +} + +void +gtk_item_deselect (GtkItem *item) +{ + gtk_signal_emit (GTK_OBJECT (item), item_signals[DESELECT]); +} + +void +gtk_item_toggle (GtkItem *item) +{ + gtk_signal_emit (GTK_OBJECT (item), item_signals[TOGGLE]); +} + + +static void +gtk_item_map (GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ITEM (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + bin = GTK_BIN (widget); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); +} + +static void +gtk_item_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ITEM (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_item_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ITEM (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} diff --git a/gtk/gtkitem.h b/gtk/gtkitem.h new file mode 100644 index 0000000000..36cf1ab451 --- /dev/null +++ b/gtk/gtkitem.h @@ -0,0 +1,65 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_ITEM_H__ +#define __GTK_ITEM_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbin.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ITEM(obj) GTK_CHECK_CAST (obj, gtk_item_get_type (), GtkItem) +#define GTK_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_item_get_type (), GtkItemClass) +#define GTK_IS_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_item_get_type ()) + + +typedef struct _GtkItem GtkItem; +typedef struct _GtkItemClass GtkItemClass; + +struct _GtkItem +{ + GtkBin bin; +}; + +struct _GtkItemClass +{ + GtkBinClass parent_class; + + void (* select) (GtkItem *item); + void (* deselect) (GtkItem *item); + void (* toggle) (GtkItem *item); +}; + + +guint gtk_item_get_type (void); +void gtk_item_select (GtkItem *item); +void gtk_item_deselect (GtkItem *item); +void gtk_item_toggle (GtkItem *item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ITEM_H__ */ diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c new file mode 100644 index 0000000000..5cd1f804fc --- /dev/null +++ b/gtk/gtklabel.c @@ -0,0 +1,329 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include "gtklabel.h" + + +static void gtk_label_class_init (GtkLabelClass *klass); +static void gtk_label_init (GtkLabel *label); +static void gtk_label_destroy (GtkObject *object); +static void gtk_label_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static gint gtk_label_expose (GtkWidget *widget, + GdkEventExpose *event); + + +static GtkMiscClass *parent_class = NULL; + + +guint +gtk_label_get_type () +{ + static guint label_type = 0; + + if (!label_type) + { + GtkTypeInfo label_info = + { + "GtkLabel", + sizeof (GtkLabel), + sizeof (GtkLabelClass), + (GtkClassInitFunc) gtk_label_class_init, + (GtkObjectInitFunc) gtk_label_init, + (GtkArgFunc) NULL, + }; + + label_type = gtk_type_unique (gtk_misc_get_type (), &label_info); + } + + return label_type; +} + +void +gtk_label_class_init (GtkLabelClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_misc_get_type ()); + + object_class->destroy = gtk_label_destroy; + + widget_class->size_request = gtk_label_size_request; + widget_class->expose_event = gtk_label_expose; +} + +void +gtk_label_init (GtkLabel *label) +{ + GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW); + + label->label = NULL; + label->row = NULL; + label->jtype = GTK_JUSTIFY_CENTER; +} + +GtkWidget* +gtk_label_new (const char *str) +{ + GtkLabel *label; + + g_return_val_if_fail (str != NULL, NULL); + + label = gtk_type_new (gtk_label_get_type ()); + + gtk_label_set (label, str); + + return GTK_WIDGET (label); +} + +void +gtk_label_set (GtkLabel *label, + const char *str) +{ + char* p; + + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + g_return_if_fail (str != NULL); + + if (label->label) + g_free (label->label); + label->label = g_strdup (str); + + if (label->row) + g_slist_free (label->row); + label->row = NULL; + label->row = g_slist_append (label->row, label->label); + p = label->label; + while ((p = strchr(p, '\n'))) + label->row = g_slist_append (label->row, ++p); + + if (GTK_WIDGET_VISIBLE (label)) + { + if (GTK_WIDGET_MAPPED (label)) + gdk_window_clear_area (GTK_WIDGET (label)->window, + GTK_WIDGET (label)->allocation.x, + GTK_WIDGET (label)->allocation.y, + GTK_WIDGET (label)->allocation.width, + GTK_WIDGET (label)->allocation.height); + + gtk_widget_queue_resize (GTK_WIDGET (label)); + } +} + +void +gtk_label_set_justify (GtkLabel *label, GtkJustification jtype) +{ + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + + if ((GtkJustification) label->jtype != jtype) + { + label->jtype = jtype; + + if (GTK_WIDGET_VISIBLE (label)) + { + if (GTK_WIDGET_MAPPED (label)) + gdk_window_clear_area (GTK_WIDGET (label)->window, + GTK_WIDGET (label)->allocation.x, + GTK_WIDGET (label)->allocation.y, + GTK_WIDGET (label)->allocation.width, + GTK_WIDGET (label)->allocation.height); + + gtk_widget_queue_resize (GTK_WIDGET (label)); + } + } +} + +void +gtk_label_get (GtkLabel *label, + char **str) +{ + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + g_return_if_fail (str != NULL); + + *str = label->label; +} + + +static void +gtk_label_destroy (GtkObject *object) +{ + GtkLabel *label; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_LABEL (object)); + + label = GTK_LABEL (object); + + if (GTK_WIDGET (object)->parent && + GTK_WIDGET_MAPPED (object)) + gtk_widget_unmap (GTK_WIDGET (object)); + + g_free (label->label); + g_slist_free (label->row); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_label_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkLabel *label; + GSList *row; + gint width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LABEL (widget)); + g_return_if_fail (requisition != NULL); + + label = GTK_LABEL (widget); + + row = label->row; + width = 0; + while (row) + { + if (row->next) + width = MAX (width, + gdk_text_width (GTK_WIDGET (label)->style->font, row->data, + (gchar*) row->next->data - (gchar*) row->data)); + else + width = MAX (width, gdk_string_width (GTK_WIDGET (label)->style->font, row->data)); + row = row->next; + } + + requisition->width = width + label->misc.xpad * 2; + requisition->height = ((GTK_WIDGET (label)->style->font->ascent + + GTK_WIDGET (label)->style->font->descent + 2) * + g_slist_length(label->row) + + label->misc.ypad * 2); +} + +static gint +gtk_label_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkLabel *label; + GtkMisc *misc; + GSList *row; + gint state; + gint offset; + gint len; + gint maxl; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + label = GTK_LABEL (widget); + misc = GTK_MISC (widget); + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + /* We only draw the label if we have been allocated at least as + * much space as we requested. If we have less space than we + * need to draw the string then we _should_ have asked our + * parent container to resize and a new allocation _should_ + * be forthcoming so there is no reason to redraw (incorrectly) + * here. + */ + if ((widget->allocation.width >= widget->requisition.width) && + (widget->allocation.height >= widget->requisition.height)) + { + maxl = widget->requisition.width - misc->xpad * 2; + x = widget->allocation.x + misc->xpad + + (widget->allocation.width - widget->requisition.width) * misc->xalign + 0.5; + y = (widget->allocation.y * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height - (widget->requisition.height - + misc->ypad * 2)) * + misc->yalign + widget->style->font->ascent) + 1.5; + + row = label->row; + while (row && row->next) + { + len = (gchar*) row->next->data - (gchar*) row->data; + offset = 0; + if (label->jtype == GTK_JUSTIFY_CENTER) + offset = (maxl - gdk_text_width (widget->style->font, row->data, len)) / 2; + else if (label->jtype == GTK_JUSTIFY_RIGHT) + offset = (maxl - gdk_text_width (widget->style->font, row->data, len)); + if (state == GTK_STATE_INSENSITIVE) + gdk_draw_text (widget->window, widget->style->font, + widget->style->white_gc, + offset + x + 1, y + 1, row->data, len); + + gdk_draw_text (widget->window, widget->style->font, + widget->style->fg_gc[state], + offset + x, y, row->data, len); + row = row->next; + y += widget->style->font->ascent + widget->style->font->descent + 2; + } + + /* COMMENT: we can avoid gdk_text_width() calls here storing in label->row + the widths of the rows calculated in gtk_label_set. + Once we have a wrapping interface we can support GTK_JUSTIFY_FILL. + */ + offset = 0; + if (label->jtype == GTK_JUSTIFY_CENTER) + offset = (maxl - gdk_string_width (widget->style->font, row->data)) / 2; + else if (label->jtype == GTK_JUSTIFY_RIGHT) + offset = (maxl - gdk_string_width (widget->style->font, row->data)); + if (state == GTK_STATE_INSENSITIVE) + gdk_draw_string (widget->window, widget->style->font, + widget->style->white_gc, + offset + x + 1, y + 1, row->data); + + gdk_draw_string (widget->window, widget->style->font, + widget->style->fg_gc[state], + offset + x, y, row->data); + + /* + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_STATE_SELECTED], FALSE, + widget->allocation.x, widget->allocation.y, + widget->allocation.width - 1, widget->allocation.height - 1); + */ + } + else + { + /* + g_print ("gtk_label_expose: allocation too small: %d %d ( %d %d )\n", + widget->allocation.width, widget->allocation.height, + widget->requisition.width, widget->requisition.height); + */ + } + } + + return TRUE; +} + + + + diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h new file mode 100644 index 0000000000..81eca4afe7 --- /dev/null +++ b/gtk/gtklabel.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_LABEL_H__ +#define __GTK_LABEL_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkmisc.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_LABEL(obj) GTK_CHECK_CAST (obj, gtk_label_get_type (), GtkLabel) +#define GTK_LABEL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_label_get_type (), GtkLabelClass) +#define GTK_IS_LABEL(obj) GTK_CHECK_TYPE (obj, gtk_label_get_type ()) + + +typedef struct _GtkLabel GtkLabel; +typedef struct _GtkLabelClass GtkLabelClass; + +struct _GtkLabel +{ + GtkMisc misc; + + char *label; + GSList *row; + guint jtype : 2; +}; + +struct _GtkLabelClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_label_get_type (void); +GtkWidget* gtk_label_new (const char *str); +void gtk_label_set (GtkLabel *label, + const char *str); +void gtk_label_set_justify (GtkLabel *label, + GtkJustification jtype); +void gtk_label_get (GtkLabel *label, + char **str); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LABEL_H__ */ diff --git a/gtk/gtklist.c b/gtk/gtklist.c new file mode 100644 index 0000000000..7d7d4a66d7 --- /dev/null +++ b/gtk/gtklist.c @@ -0,0 +1,1007 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtklist.h" +#include "gtklistitem.h" +#include "gtkmain.h" +#include "gtksignal.h" + + +enum { + SELECTION_CHANGED, + SELECT_CHILD, + UNSELECT_CHILD, + LAST_SIGNAL +}; + + +typedef void (*GtkListSignal) (GtkObject *object, + gpointer arg1, + gpointer data); + + +static void gtk_list_class_init (GtkListClass *klass); +static void gtk_list_init (GtkList *list); +static void gtk_list_destroy (GtkObject *object); +static void gtk_list_map (GtkWidget *widget); +static void gtk_list_unmap (GtkWidget *widget); +static void gtk_list_realize (GtkWidget *widget); +static void gtk_list_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_list_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_list_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_list_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_list_button_release (GtkWidget *widget, + GdkEventButton *event); +static void gtk_list_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_list_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_list_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_list_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_list_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + +static void gtk_real_list_select_child (GtkList *list, + GtkWidget *child); +static void gtk_real_list_unselect_child (GtkList *list, + GtkWidget *child); + +static void gtk_list_marshal_signal (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + + +static GtkContainerClass *parent_class = NULL; +static gint list_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_list_get_type () +{ + static guint list_type = 0; + + if (!list_type) + { + GtkTypeInfo list_info = + { + "GtkList", + sizeof (GtkList), + sizeof (GtkListClass), + (GtkClassInitFunc) gtk_list_class_init, + (GtkObjectInitFunc) gtk_list_init, + (GtkArgFunc) NULL, + }; + + list_type = gtk_type_unique (gtk_container_get_type (), &list_info); + } + + return list_type; +} + +static void +gtk_list_class_init (GtkListClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + list_signals[SELECTION_CHANGED] = + gtk_signal_new ("selection_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkListClass, selection_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + list_signals[SELECT_CHILD] = + gtk_signal_new ("select_child", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkListClass, select_child), + gtk_list_marshal_signal, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + list_signals[UNSELECT_CHILD] = + gtk_signal_new ("unselect_child", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkListClass, unselect_child), + gtk_list_marshal_signal, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + + gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL); + + object_class->destroy = gtk_list_destroy; + + widget_class->map = gtk_list_map; + widget_class->unmap = gtk_list_unmap; + widget_class->realize = gtk_list_realize; + widget_class->draw = gtk_list_draw; + widget_class->expose_event = gtk_list_expose; + widget_class->motion_notify_event = gtk_list_motion_notify; + widget_class->button_press_event = gtk_list_button_press; + widget_class->button_release_event = gtk_list_button_release; + widget_class->size_request = gtk_list_size_request; + widget_class->size_allocate = gtk_list_size_allocate; + + container_class->add = gtk_list_add; + container_class->remove = gtk_list_remove; + container_class->foreach = gtk_list_foreach; + + class->selection_changed = NULL; + class->select_child = gtk_real_list_select_child; + class->unselect_child = gtk_real_list_unselect_child; +} + +static void +gtk_list_init (GtkList *list) +{ + list->children = NULL; + list->selection = NULL; + list->timer = 0; + list->selection_start_pos = 0; + list->selection_end_pos = 0; + list->selection_mode = GTK_SELECTION_SINGLE; + list->scroll_direction = 0; + list->have_grab = FALSE; +} + +GtkWidget* +gtk_list_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_list_get_type ())); +} + +void +gtk_list_insert_items (GtkList *list, + GList *items, + gint position) +{ + GtkWidget *widget; + GList *tmp_list; + GList *last; + gint nchildren; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + if (!items) + return; + + tmp_list = items; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_widget_set_parent (widget, GTK_WIDGET (list)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + } + + nchildren = g_list_length (list->children); + if ((position < 0) || (position > nchildren)) + position = nchildren; + + if (position == nchildren) + { + if (list->children) + { + tmp_list = g_list_last (list->children); + tmp_list->next = items; + items->prev = tmp_list; + } + else + { + list->children = items; + } + } + else + { + tmp_list = g_list_nth (list->children, position); + last = g_list_last (items); + + if (tmp_list->prev) + tmp_list->prev->next = items; + last->next = tmp_list; + items->prev = tmp_list->prev; + tmp_list->prev = last; + + if (tmp_list == list->children) + list->children = items; + } + + if (list->children && !list->selection && + (list->selection_mode == GTK_SELECTION_BROWSE)) + { + widget = list->children->data; + gtk_list_select_child (list, widget); + } + + if (GTK_WIDGET_VISIBLE (list)) + gtk_widget_queue_resize (GTK_WIDGET (list)); +} + +void +gtk_list_append_items (GtkList *list, + GList *items) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + gtk_list_insert_items (list, items, -1); +} + +void +gtk_list_prepend_items (GtkList *list, + GList *items) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + gtk_list_insert_items (list, items, 0); +} + +void +gtk_list_remove_items (GtkList *list, + GList *items) +{ + GtkWidget *widget; + GList *selected_widgets; + GList *tmp_list; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + tmp_list = items; + selected_widgets = NULL; + widget = NULL; + + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + if (widget->state == GTK_STATE_SELECTED) + selected_widgets = g_list_prepend (selected_widgets, widget); + + list->children = g_list_remove (list->children, widget); + + if (GTK_WIDGET_MAPPED (widget)) + gtk_widget_unmap (widget); + + gtk_widget_unparent (widget); + } + + if (selected_widgets) + { + tmp_list = selected_widgets; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_list_unselect_child (list, widget); + } + + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + + g_list_free (selected_widgets); + + if (list->children && !list->selection && + (list->selection_mode == GTK_SELECTION_BROWSE)) + { + widget = list->children->data; + gtk_list_select_child (list, widget); + } + + if (GTK_WIDGET_VISIBLE (list)) + gtk_widget_queue_resize (GTK_WIDGET (list)); +} + +void +gtk_list_clear_items (GtkList *list, + gint start, + gint end) +{ + GtkWidget *widget; + GList *start_list; + GList *end_list; + GList *tmp_list; + gint nchildren; + gint selection_changed; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + nchildren = g_list_length (list->children); + + if (nchildren > 0) + { + if ((end < 0) || (end > nchildren)) + end = nchildren; + + g_return_if_fail (start < end); + + start_list = g_list_nth (list->children, start); + end_list = g_list_nth (list->children, end); + + if (start_list->prev) + start_list->prev->next = end_list; + if (end_list && end_list->prev) + end_list->prev->next = NULL; + if (end_list) + end_list->prev = start_list->prev; + if (start_list == list->children) + list->children = end_list; + + selection_changed = FALSE; + widget = NULL; + tmp_list = start_list; + + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + if (widget->state == GTK_STATE_SELECTED) + { + selection_changed = TRUE; + list->selection = g_list_remove (list->selection, widget); + } + + /* list->children = g_list_remove (list->children, widget); */ + /* gtk_widget_unparent (widget); */ + + gtk_widget_destroy (widget); + } + + if (list->children && !list->selection && + (list->selection_mode == GTK_SELECTION_BROWSE)) + { + gtk_list_select_child (list, widget); + widget = list->children->data; + } + + if (selection_changed) + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + + gtk_widget_queue_resize (GTK_WIDGET (list)); + } +} + +void +gtk_list_select_item (GtkList *list, + gint item) +{ + GList *tmp_list; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + tmp_list = g_list_nth (list->children, item); + if (tmp_list) + gtk_list_select_child (list, GTK_WIDGET (tmp_list->data)); +} + +void +gtk_list_unselect_item (GtkList *list, + gint item) +{ + GList *tmp_list; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + tmp_list = g_list_nth (list->children, item); + if (tmp_list) + gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data)); +} + +void +gtk_list_select_child (GtkList *list, + GtkWidget *child) +{ + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child); +} + +void +gtk_list_unselect_child (GtkList *list, + GtkWidget *child) +{ + gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child); +} + +gint +gtk_list_child_position (GtkList *list, + GtkWidget *child) +{ + GList *children; + gint pos; + + g_return_val_if_fail (list != NULL, -1); + g_return_val_if_fail (GTK_IS_LIST (list), -1); + g_return_val_if_fail (child != NULL, -1); + + pos = 0; + children = list->children; + + while (children) + { + if (child == GTK_WIDGET (children->data)) + return pos; + + pos += 1; + children = children->next; + } + + return -1; +} + +void +gtk_list_set_selection_mode (GtkList *list, + GtkSelectionMode mode) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + list->selection_mode = mode; +} + + +static void +gtk_list_destroy (GtkObject *object) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_LIST (object)); + + list = GTK_LIST (object); + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + child->parent = NULL; + gtk_object_unref (GTK_OBJECT (child)); + gtk_widget_destroy (child); + } + + g_list_free (list->children); + g_list_free (list->selection); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_list_map (GtkWidget *widget) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + list = GTK_LIST (widget); + + gdk_window_show (widget->window); + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } +} + +static void +gtk_list_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_list_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gdk_window_set_background (widget->window, &widget->style->white); +} + +static void +gtk_list_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkList *list; + GtkWidget *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + list = GTK_LIST (widget); + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } + } +} + +static gint +gtk_list_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkList *list; + GtkWidget *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + list = GTK_LIST (widget); + + child_event = *event; + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static gint +gtk_list_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + g_print ("gtk_list_motion_notify\n"); + + return FALSE; +} + +static gint +gtk_list_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkList *list; + GtkWidget *item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + list = GTK_LIST (widget); + item = gtk_get_event_widget ((GdkEvent*) event); + + while (!gtk_type_is_a (GTK_WIDGET_TYPE (item), gtk_list_item_get_type ())) + item = item->parent; + + gtk_list_select_child (list, item); + + return FALSE; +} + +static gint +gtk_list_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkList *list; + GtkWidget *item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + list = GTK_LIST (widget); + item = gtk_get_event_widget ((GdkEvent*) event); + + return FALSE; +} + +static void +gtk_list_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + g_return_if_fail (requisition != NULL); + + list = GTK_LIST (widget); + requisition->width = 0; + requisition->height = 0; + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + gtk_widget_size_request (child, &child->requisition); + + requisition->width = MAX (requisition->width, child->requisition.width); + requisition->height += child->requisition.height; + } + } + + requisition->width += GTK_CONTAINER (list)->border_width * 2; + requisition->height += GTK_CONTAINER (list)->border_width * 2; + + requisition->width = MAX (requisition->width, 1); + requisition->height = MAX (requisition->height, 1); +} + +static void +gtk_list_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkList *list; + GtkWidget *child; + GtkAllocation child_allocation; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + g_return_if_fail (allocation != NULL); + + list = GTK_LIST (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + if (list->children) + { + child_allocation.x = GTK_CONTAINER (list)->border_width; + child_allocation.y = GTK_CONTAINER (list)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + + children = list->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + child_allocation.height = child->requisition.height; + + gtk_widget_size_allocate (child, &child_allocation); + + child_allocation.y += child_allocation.height; + } + } + } +} + +static void +gtk_list_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkList *list; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_LIST (container)); + g_return_if_fail (widget != NULL); + + list = GTK_LIST (container); + + gtk_widget_set_parent (widget, GTK_WIDGET (container)); + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + list->children = g_list_append (list->children, widget); + + if (!list->selection && (list->selection_mode == GTK_SELECTION_BROWSE)) + { + gtk_list_select_child (list, widget); + } + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (widget); +} + +static void +gtk_list_remove (GtkContainer *container, + GtkWidget *widget) +{ + GList *item_list; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_LIST (container)); + g_return_if_fail (widget != NULL); + g_return_if_fail (container == GTK_CONTAINER (widget->parent)); + + + item_list = g_list_alloc (); + item_list->data = widget; + + gtk_list_remove_items (GTK_LIST (container), item_list); + + g_list_free (item_list); +} + +static void +gtk_list_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_LIST (container)); + g_return_if_fail (callback != NULL); + + list = GTK_LIST (container); + children = list->children; + + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child, callback_data); + } +} + + +static void +gtk_real_list_select_child (GtkList *list, + GtkWidget *child) +{ + GList *selection; + GList *tmp_list; + GtkWidget *tmp_item; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + g_return_if_fail (child != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (child)); + + switch (list->selection_mode) + { + case GTK_SELECTION_SINGLE: + selection = list->selection; + + while (selection) + { + tmp_item = selection->data; + + if (tmp_item != child) + { + gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item)); + + tmp_list = selection; + selection = selection->next; + + list->selection = g_list_remove_link (list->selection, tmp_list); + + g_list_free (tmp_list); + } + else + selection = selection->next; + } + + if (child->state == GTK_STATE_NORMAL) + { + gtk_list_item_select (GTK_LIST_ITEM (child)); + list->selection = g_list_prepend (list->selection, child); + } + else if (child->state == GTK_STATE_SELECTED) + { + gtk_list_item_deselect (GTK_LIST_ITEM (child)); + list->selection = g_list_remove (list->selection, child); + } + + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + break; + + case GTK_SELECTION_BROWSE: + selection = list->selection; + + while (selection) + { + tmp_item = selection->data; + + if (tmp_item != child) + { + gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item)); + + tmp_list = selection; + selection = selection->next; + + list->selection = g_list_remove_link (list->selection, tmp_list); + + g_list_free (tmp_list); + } + else + selection = selection->next; + } + + if (child->state == GTK_STATE_NORMAL) + { + gtk_list_item_select (GTK_LIST_ITEM (child)); + list->selection = g_list_prepend (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + break; + + case GTK_SELECTION_MULTIPLE: + if (child->state == GTK_STATE_NORMAL) + { + gtk_list_item_select (GTK_LIST_ITEM (child)); + list->selection = g_list_prepend (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + else if (child->state == GTK_STATE_SELECTED) + { + gtk_list_item_deselect (GTK_LIST_ITEM (child)); + list->selection = g_list_remove (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + break; + + case GTK_SELECTION_EXTENDED: + break; + } +} + +static void +gtk_real_list_unselect_child (GtkList *list, + GtkWidget *child) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + g_return_if_fail (child != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (child)); + + switch (list->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_BROWSE: + if (child->state == GTK_STATE_SELECTED) + { + gtk_list_item_deselect (GTK_LIST_ITEM (child)); + list->selection = g_list_remove (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + break; + + case GTK_SELECTION_EXTENDED: + break; + } +} + + +static void +gtk_list_marshal_signal (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkListSignal rfunc; + + rfunc = (GtkListSignal) func; + + (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data); +} diff --git a/gtk/gtklist.h b/gtk/gtklist.h new file mode 100644 index 0000000000..3eff261b54 --- /dev/null +++ b/gtk/gtklist.h @@ -0,0 +1,107 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_LIST_H__ +#define __GTK_LIST_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_LIST(obj) GTK_CHECK_CAST (obj, gtk_list_get_type (), GtkList) +#define GTK_LIST_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_list_get_type (), GtkListClass) +#define GTK_IS_LIST(obj) GTK_CHECK_TYPE (obj, gtk_list_get_type ()) + + +typedef struct _GtkList GtkList; +typedef struct _GtkListClass GtkListClass; + +typedef enum +{ + GTK_SELECTION_SINGLE, + GTK_SELECTION_BROWSE, + GTK_SELECTION_MULTIPLE, + GTK_SELECTION_EXTENDED +} GtkSelectionMode; + +struct _GtkList +{ + GtkContainer container; + + GList *children; + GList *selection; + + guint32 timer; + guint16 selection_start_pos; + guint16 selection_end_pos; + guint selection_mode : 2; + guint scroll_direction : 1; + guint have_grab : 1; +}; + +struct _GtkListClass +{ + GtkContainerClass parent_class; + + void (* selection_changed) (GtkList *list); + void (* select_child) (GtkList *list, + GtkWidget *child); + void (* unselect_child) (GtkList *list, + GtkWidget *child); +}; + + +guint gtk_list_get_type (void); +GtkWidget* gtk_list_new (void); +void gtk_list_insert_items (GtkList *list, + GList *items, + gint position); +void gtk_list_append_items (GtkList *list, + GList *items); +void gtk_list_prepend_items (GtkList *list, + GList *items); +void gtk_list_remove_items (GtkList *list, + GList *items); +void gtk_list_clear_items (GtkList *list, + gint start, + gint end); +void gtk_list_select_item (GtkList *list, + gint item); +void gtk_list_unselect_item (GtkList *list, + gint item); +void gtk_list_select_child (GtkList *list, + GtkWidget *child); +void gtk_list_unselect_child (GtkList *list, + GtkWidget *child); +gint gtk_list_child_position (GtkList *list, + GtkWidget *child); +void gtk_list_set_selection_mode (GtkList *list, + GtkSelectionMode mode); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LIST_H__ */ diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c new file mode 100644 index 0000000000..6420270259 --- /dev/null +++ b/gtk/gtklistitem.c @@ -0,0 +1,394 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtklabel.h" +#include "gtklistitem.h" +#include "gtklist.h" + +static void gtk_list_item_class_init (GtkListItemClass *klass); +static void gtk_list_item_init (GtkListItem *list_item); +static void gtk_list_item_realize (GtkWidget *widget); +static void gtk_list_item_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_list_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_list_item_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_list_item_draw_focus (GtkWidget *widget); +static gint gtk_list_item_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_list_item_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_list_item_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_list_item_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_real_list_item_select (GtkItem *item); +static void gtk_real_list_item_deselect (GtkItem *item); +static void gtk_real_list_item_toggle (GtkItem *item); + + +static GtkItemClass *parent_class = NULL; + + +guint +gtk_list_item_get_type () +{ + static guint list_item_type = 0; + + if (!list_item_type) + { + GtkTypeInfo list_item_info = + { + "GtkListItem", + sizeof (GtkListItem), + sizeof (GtkListItemClass), + (GtkClassInitFunc) gtk_list_item_class_init, + (GtkObjectInitFunc) gtk_list_item_init, + (GtkArgFunc) NULL, + }; + + list_item_type = gtk_type_unique (gtk_item_get_type (), &list_item_info); + } + + return list_item_type; +} + +static void +gtk_list_item_class_init (GtkListItemClass *class) +{ + GtkWidgetClass *widget_class; + GtkItemClass *item_class; + + widget_class = (GtkWidgetClass*) class; + item_class = (GtkItemClass*) class; + + parent_class = gtk_type_class (gtk_item_get_type ()); + + widget_class->realize = gtk_list_item_realize; + widget_class->size_request = gtk_list_item_size_request; + widget_class->size_allocate = gtk_list_item_size_allocate; + widget_class->draw = gtk_list_item_draw; + widget_class->draw_focus = gtk_list_item_draw_focus; + widget_class->button_press_event = gtk_list_item_button_press; + widget_class->expose_event = gtk_list_item_expose; + widget_class->focus_in_event = gtk_list_item_focus_in; + widget_class->focus_out_event = gtk_list_item_focus_out; + + item_class->select = gtk_real_list_item_select; + item_class->deselect = gtk_real_list_item_deselect; + item_class->toggle = gtk_real_list_item_toggle; +} + +static void +gtk_list_item_init (GtkListItem *list_item) +{ + GTK_WIDGET_SET_FLAGS (list_item, GTK_CAN_FOCUS); +} + +GtkWidget* +gtk_list_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_list_item_get_type ())); +} + +GtkWidget* +gtk_list_item_new_with_label (const gchar *label) +{ + GtkWidget *list_item; + GtkWidget *label_widget; + + list_item = gtk_list_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (list_item), label_widget); + gtk_widget_show (label_widget); + + return list_item; +} + +void +gtk_list_item_select (GtkListItem *list_item) +{ + gtk_item_select (GTK_ITEM (list_item)); +} + +void +gtk_list_item_deselect (GtkListItem *list_item) +{ + gtk_item_deselect (GTK_ITEM (list_item)); +} + + +static void +gtk_list_item_realize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + + if (GTK_WIDGET_CLASS (parent_class)->realize) + (* GTK_WIDGET_CLASS (parent_class)->realize) (widget); + + gdk_window_set_background (widget->window, &widget->style->white); +} + +static void +gtk_list_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + g_return_if_fail (requisition != NULL); + + bin = GTK_BIN (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness) * 2; + requisition->height = GTK_CONTAINER (widget)->border_width * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_list_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + bin = GTK_BIN (widget); + + if (bin->child) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness); + child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static void +gtk_list_item_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + gtk_style_set_background (widget->style, widget->window, GTK_STATE_INSENSITIVE); + else if (widget->state == GTK_STATE_NORMAL) + gdk_window_set_background (widget->window, &widget->style->white); + else + gtk_style_set_background (widget->style, widget->window, widget->state); + + gdk_window_clear_area (widget->window, area->x, area->y, + area->width, area->height); + + if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + + gtk_widget_draw_focus (widget); + } +} + +static void +gtk_list_item_draw_focus (GtkWidget *widget) +{ + GdkGC *gc; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + if (GTK_WIDGET_HAS_FOCUS (widget)) + gc = widget->style->black_gc; + else if (!GTK_WIDGET_IS_SENSITIVE (widget)) + gc = widget->style->bg_gc[GTK_STATE_INSENSITIVE]; + else if (widget->state == GTK_STATE_NORMAL) + gc = widget->style->white_gc; + else + gc = widget->style->bg_gc[widget->state]; + + gdk_draw_rectangle (widget->window, gc, FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + } +} + +static gint +gtk_list_item_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->type == GDK_BUTTON_PRESS) + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + return FALSE; +} + +static gint +gtk_list_item_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + gdk_window_set_background (widget->window, &widget->style->bg[GTK_STATE_INSENSITIVE]); + else if (widget->state == GTK_STATE_NORMAL) + gdk_window_set_background (widget->window, &widget->style->white); + else + gdk_window_set_background (widget->window, &widget->style->bg[widget->state]); + + gdk_window_clear_area (widget->window, event->area.x, event->area.y, + event->area.width, event->area.height); + + if (bin->child) + { + child_event = *event; + + if (GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + gtk_widget_draw_focus (widget); + } + + return FALSE; +} + +static gint +gtk_list_item_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_list_item_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static void +gtk_real_list_item_select (GtkItem *item) +{ + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (item)); + + if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED) + return; + + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED); + gtk_widget_queue_draw (GTK_WIDGET (item)); +} + +static void +gtk_real_list_item_deselect (GtkItem *item) +{ + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (item)); + + if (GTK_WIDGET (item)->state == GTK_STATE_NORMAL) + return; + + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL); + gtk_widget_queue_draw (GTK_WIDGET (item)); +} + +static void +gtk_real_list_item_toggle (GtkItem *item) +{ + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (item)); + + if (GTK_WIDGET (item)->parent && GTK_IS_LIST (GTK_WIDGET (item)->parent)) + gtk_list_select_child (GTK_LIST (GTK_WIDGET (item)->parent), + GTK_WIDGET (item)); + else + { + /* Should we really bother with this bit? A listitem not in a list? + * -Johannes Keukelaar + * yes, always be on the save side! + * -timj + */ + if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED) + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL); + else + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED); + gtk_widget_queue_draw (GTK_WIDGET (item)); + } +} diff --git a/gtk/gtklistitem.h b/gtk/gtklistitem.h new file mode 100644 index 0000000000..4220ae73f8 --- /dev/null +++ b/gtk/gtklistitem.h @@ -0,0 +1,62 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_LIST_ITEM_H__ +#define __GTK_LIST_ITEM_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkitem.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_LIST_ITEM(obj) GTK_CHECK_CAST (obj, gtk_list_item_get_type (), GtkListItem) +#define GTK_LIST_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_list_item_get_type (), GtkListItemClass) +#define GTK_IS_LIST_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_list_item_get_type ()) + + +typedef struct _GtkListItem GtkListItem; +typedef struct _GtkListItemClass GtkListItemClass; + +struct _GtkListItem +{ + GtkItem item; +}; + +struct _GtkListItemClass +{ + GtkItemClass parent_class; +}; + + +guint gtk_list_item_get_type (void); +GtkWidget* gtk_list_item_new (void); +GtkWidget* gtk_list_item_new_with_label (const gchar *label); +void gtk_list_item_select (GtkListItem *list_item); +void gtk_list_item_deselect (GtkListItem *list_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LIST_ITEM_H__ */ diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c new file mode 100644 index 0000000000..50d262430b --- /dev/null +++ b/gtk/gtkmain.c @@ -0,0 +1,1129 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include <stdlib.h> +#include "gtkbutton.h" +#include "gtkhscrollbar.h" +#include "gtkhseparator.h" +#include "gtkmain.h" +#include "gtkpreview.h" +#include "gtkrc.h" +#include "gtkselection.h" +#include "gtksignal.h" +#include "gtktable.h" +#include "gtktext.h" +#include "gtkvbox.h" +#include "gtkvscrollbar.h" +#include "gtkwidget.h" +#include "gtkwindow.h" + + +/* Private type definitions + */ +typedef struct _GtkInitFunction GtkInitFunction; +typedef struct _GtkTimeoutFunction GtkTimeoutFunction; +typedef struct _GtkIdleFunction GtkIdleFunction; + +struct _GtkInitFunction +{ + GtkFunction function; + gpointer data; +}; + +struct _GtkTimeoutFunction +{ + gint tag; + guint32 start; + guint32 interval; + guint32 originterval; + gint interp; + GtkFunction function; + gpointer data; + GtkDestroyNotify destroy; +}; + +struct _GtkIdleFunction +{ + gint tag; + gint interp; + GtkFunction function; + gpointer data; + GtkDestroyNotify destroy; +}; + + +static void gtk_exit_func (void); +static void gtk_timeout_insert (GtkTimeoutFunction *timeoutf); +static void gtk_handle_current_timeouts (guint32 the_time); +static void gtk_handle_current_idles (); +static void gtk_handle_timeouts (void); +static void gtk_handle_idle (void); +static void gtk_handle_timer (void); +static void gtk_propagate_event (GtkWidget *widget, + GdkEvent *event); +static void gtk_error (char *str); +static void gtk_warning (char *str); +static void gtk_message (char *str); +static void gtk_print (char *str); + + +static int done; +static int initialized = FALSE; +static GdkEvent next_event; +static GdkEvent current_event; +static gint have_event = FALSE; +static gint have_next_event = FALSE; + +static GList *grabs = NULL; /* A list of grabs. The grabbing widget + * is the first one on the list. + */ +static GList *init_functions = NULL; /* A list of init functions. + */ +static GList *timeout_functions = NULL; /* A list of timeout functions sorted by + * when the length of the time interval + * remaining. Therefore, the first timeout + * function to expire is at the head of + * the list and the last to expire is at + * the tail of the list. + */ +static GList *idle_functions = NULL; /* A list of idle functions. + */ + +static GList *current_idles = NULL; +static GList *current_timeouts = NULL; +static GMemChunk *timeout_mem_chunk = NULL; +static GMemChunk *idle_mem_chunk = NULL; + +static GdkVisual *gtk_visual; /* The visual to be used in creating new + * widgets. + */ +static GdkColormap *gtk_colormap; /* The colormap to be used in creating new + * widgets. + */ + + +void +gtk_init (int *argc, + char ***argv) +{ + if (0) + { + g_set_error_handler (gtk_error); + g_set_warning_handler (gtk_warning); + g_set_message_handler (gtk_message); + g_set_print_handler (gtk_print); + } + + /* Initialize "gdk". We simply pass along the 'argc' and 'argv' + * parameters as they contain information that + */ + gdk_init (argc, argv); + + /* Initialize the default visual and colormap to be + * used in creating widgets. (We want to use the system + * defaults so as to be nice to the colormap). + */ + gtk_visual = gdk_visual_get_system (); + gtk_colormap = gdk_colormap_get_system (); + gtk_rc_init (); + + gtk_type_init (); + + /* Register an exit function to make sure we are able to cleanup. + */ + if (ATEXIT (gtk_exit_func)) + g_warning ("unable to register exit function"); + + /* Set the 'initialized' flag. + */ + initialized = TRUE; +} + +void +gtk_exit (int errorcode) +{ + /* Only if "gtk" has been initialized should we de-initialize. + */ + /* de-initialisation is done by the gtk_exit_funct(), + no need to do this here (Alex J.) */ + gdk_exit(errorcode); +} + +gchar* +gtk_set_locale () +{ + return gdk_set_locale (); +} + +void +gtk_main () +{ + GList *tmp_list; + GList *functions; + GtkInitFunction *init; + int old_done; + + tmp_list = functions = init_functions; + init_functions = NULL; + + while (tmp_list) + { + init = tmp_list->data; + tmp_list = tmp_list->next; + + (* init->function) (init->data); + g_free (init); + } + + g_list_free (functions); + + old_done = done; + while (!gtk_main_iteration ()) + ; + done = old_done; +} + +void +gtk_main_quit () +{ + done = TRUE; +} + +gint +gtk_main_iteration () +{ + GdkEvent event_copy; + GtkWidget *event_widget; + GtkWidget *grab_widget; + + done = FALSE; + + /* If this is a recursive call, and there are pending timeouts or + idles, finish them, then return immediately to avoid blocking + in gdk_event_get() */ + if (current_timeouts) + { + gtk_handle_current_timeouts( gdk_time_get()); + return done; + } + if (current_idles) + { + gtk_handle_current_idles(); + return done; + } + + /* If there is a valid event in 'next_event' then copy + * it to 'event' and unset the flag. + */ + if (have_next_event) + { + have_next_event = FALSE; + have_event = TRUE; + current_event = next_event; + } + + /* If we don't have an event then get one. + */ + if (!have_event) + { + /* Handle setting of the "gdk" timer. If there are no + * timeout functions, then the timer is turned off. + * If there are timeout functions, then the timer is + * set to the shortest timeout interval (which is + * the first timeout function). + */ + gtk_handle_timer (); + + have_event = gdk_event_get (¤t_event, NULL, NULL); + } + + /* "gdk_event_get" can return FALSE if the timer goes off + * and no events are pending. Therefore, we should make + * sure that we got an event before continuing. + */ + if (have_event) + { + have_event = FALSE; + + /* If there are any events pending then get the next one. + */ + if (gdk_events_pending () > 0) + have_next_event = gdk_event_get (&next_event, NULL, NULL); + + /* Try to compress enter/leave notify events. These event + * pairs occur when the mouse is dragged quickly across + * a window with many buttons (or through a menu). Instead + * of highlighting and de-highlighting each widget that + * is crossed it is better to simply de-highlight the widget + * which contained the mouse initially and highlight the + * widget which ends up containing the mouse. + */ + if (have_next_event) + if (((current_event.type == GDK_ENTER_NOTIFY) || + (current_event.type == GDK_LEAVE_NOTIFY)) && + ((next_event.type == GDK_ENTER_NOTIFY) || + (next_event.type == GDK_LEAVE_NOTIFY)) && + (next_event.type != current_event.type) && + (next_event.any.window == current_event.any.window)) + return done; + + /* Find the widget which got the event. We store the widget + * in the user_data field of GdkWindow's. + */ + event_widget = gtk_get_event_widget (¤t_event); + + /* If there is a grab in effect... + */ + if (grabs) + { + grab_widget = grabs->data; + + /* If the grab widget is an ancestor of the event widget + * then we send the event to the original event widget. + * This is the key to implementing modality. + */ + if (gtk_widget_is_ancestor (event_widget, grab_widget)) + grab_widget = event_widget; + } + else + { + grab_widget = event_widget; + } + + /* Not all events get sent to the grabbing widget. + * The delete, destroy, expose, focus change and resize + * events still get sent to the event widget because + * 1) these events have no meaning for the grabbing widget + * and 2) redirecting these events to the grabbing widget + * could cause the display to be messed up. + */ + event_copy = current_event; + switch (event_copy.type) + { + case GDK_NOTHING: + break; + + case GDK_DELETE: + if (gtk_widget_event (event_widget, &event_copy)) + gtk_widget_destroy (event_widget); + break; + + case GDK_DESTROY: + gtk_widget_event (event_widget, &event_copy); + gtk_widget_destroy (event_widget); + break; + + case GDK_PROPERTY_NOTIFY: + /* To handle selection INCR transactions, we select + PropertyNotify events on the requestor window and create + a corresponding (fake) GdkWindow so that events get + here. There won't be a widget though, so we have to handle + them specially */ + + if (event_widget == NULL) + { + gtk_selection_incr_event (event_copy.any.window, + &event_copy.property); + break; + } + /* otherwise fall through */ + + case GDK_EXPOSE: + case GDK_FOCUS_CHANGE: + case GDK_CONFIGURE: + case GDK_MAP: + case GDK_UNMAP: + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + case GDK_CLIENT_EVENT: + gtk_widget_event (event_widget, &event_copy); + break; + + case GDK_MOTION_NOTIFY: + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + case GDK_OTHER_EVENT: + case GDK_DRAG_BEGIN: + case GDK_DRAG_REQUEST: + case GDK_DROP_ENTER: + case GDK_DROP_LEAVE: + case GDK_DROP_DATA_AVAIL: + gtk_propagate_event (grab_widget, &event_copy); + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (grab_widget && GTK_WIDGET_IS_SENSITIVE (grab_widget)) + gtk_widget_event (grab_widget, &event_copy); + break; + } + } + else + { + if (gdk_events_pending() == 0) + gtk_handle_idle (); + } + + /* Handle a timeout functions that may have expired. + */ + gtk_handle_timeouts (); + + return done; +} + +gint +gtk_true (void) +{ + return TRUE; +} + +gint +gtk_false (void) +{ + return FALSE; +} + +void +gtk_grab_add (GtkWidget *widget) +{ + /* Place the grab on the front of the list of grabs. + */ + grabs = g_list_prepend (grabs, widget); +} + +void +gtk_grab_remove (GtkWidget *widget) +{ + /* Remove the grab from the list of grabs. + * Note: the grab being removed may be in + * the middle of the list. + */ + grabs = g_list_remove (grabs, widget); +} + +void +gtk_init_add (GtkFunction function, + gpointer data) +{ + GtkInitFunction *init; + + init = g_new (GtkInitFunction, 1); + init->function = function; + init->data = data; + + init_functions = g_list_prepend (init_functions, init); +} + +static gint +gtk_timeout_add_internal (guint32 interval, + gint interp, + GtkFunction function, + gpointer data, + GtkDestroyNotify destroy) +{ + static gint timeout_tag = 1; + GtkTimeoutFunction *timeoutf; + + /* Create a new timeout function structure. + * The start time is the current time. + */ + if (!timeout_mem_chunk) + timeout_mem_chunk = g_mem_chunk_new ("timeout mem chunk", sizeof (GtkTimeoutFunction), + 1024, G_ALLOC_AND_FREE); + + timeoutf = g_chunk_new (GtkTimeoutFunction, timeout_mem_chunk); + + timeoutf->tag = timeout_tag++; + timeoutf->start = gdk_time_get (); + timeoutf->interval = interval; + timeoutf->originterval = interval; + timeoutf->interp = interp; + timeoutf->function = function; + timeoutf->data = data; + timeoutf->destroy = destroy; + + gtk_timeout_insert (timeoutf); + + return timeoutf->tag; +} + +static void +gtk_timeout_destroy (GtkTimeoutFunction *timeoutf) +{ + if (timeoutf->destroy) + (timeoutf->destroy) (timeoutf->data); + g_mem_chunk_free (timeout_mem_chunk, timeoutf); +} + +gint +gtk_timeout_add (guint32 interval, + GtkFunction function, + gpointer data) +{ + return gtk_timeout_add_internal (interval, FALSE, function, data, NULL); +} + +gint +gtk_timeout_add_interp (guint32 interval, + GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy) +{ + return gtk_timeout_add_internal (interval, TRUE, + (GtkFunction) function, + data, destroy); +} + +void +gtk_timeout_remove (gint tag) +{ + GtkTimeoutFunction *timeoutf; + GList *tmp_list; + + /* Remove a timeout function. + * (Which, basically, involves searching the + * list for the tag). + */ + tmp_list = timeout_functions; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->tag == tag) + { + timeout_functions = g_list_remove_link (timeout_functions, tmp_list); + g_list_free (tmp_list); + gtk_timeout_destroy (timeoutf); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_timeouts; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->tag == tag) + { + current_timeouts = g_list_remove_link (current_timeouts, tmp_list); + g_list_free (tmp_list); + gtk_timeout_destroy (timeoutf); + + return; + } + + tmp_list = tmp_list->next; + } +} + +static gint +gtk_idle_add_internal (gint interp, + GtkFunction function, + gpointer data, + GtkDestroyNotify destroy) +{ + static gint idle_tag = 1; + GtkIdleFunction *idlef; + + if (!idle_mem_chunk) + idle_mem_chunk = g_mem_chunk_new ("idle mem chunk", sizeof (GtkIdleFunction), + 1024, G_ALLOC_AND_FREE); + + idlef = g_chunk_new (GtkIdleFunction, idle_mem_chunk); + + idlef->tag = idle_tag++; + idlef->interp = interp; + idlef->function = function; + idlef->data = data; + idlef->destroy = destroy; + + idle_functions = g_list_append (idle_functions, idlef); + + return idlef->tag; +} + +static void +gtk_idle_destroy (GtkIdleFunction *idlef) +{ + if (idlef->destroy) + idlef->destroy (idlef->data); + g_mem_chunk_free (idle_mem_chunk, idlef); +} + +gint +gtk_idle_add (GtkFunction function, + gpointer data) +{ + return gtk_idle_add_internal (FALSE, function, data, NULL); +} + +gint +gtk_idle_add_interp (GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy) +{ + return gtk_idle_add_internal (TRUE, (GtkFunction)function, data, destroy); +} + +void +gtk_idle_remove (gint tag) +{ + GtkIdleFunction *idlef; + GList *tmp_list; + + tmp_list = idle_functions; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->tag == tag) + { + idle_functions = g_list_remove_link (idle_functions, tmp_list); + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_idles; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->tag == tag) + { + current_idles = g_list_remove_link (current_idles, tmp_list); + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + + return; + } + + tmp_list = tmp_list->next; + } +} + +void +gtk_idle_remove_by_data (gpointer data) +{ + GtkIdleFunction *idlef; + GList *tmp_list; + + tmp_list = idle_functions; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->data == data) + { + idle_functions = g_list_remove_link (idle_functions, tmp_list); + g_list_free (tmp_list); + g_mem_chunk_free (idle_mem_chunk, idlef); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_idles; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->data == data) + { + current_idles = g_list_remove_link (current_idles, tmp_list); + g_list_free (tmp_list); + g_mem_chunk_free (idle_mem_chunk, idlef); + + return; + } + + tmp_list = tmp_list->next; + } +} + +void +gtk_get_current_event (GdkEvent *event) +{ + g_assert (event != NULL); + + *event = current_event; +} + +GtkWidget* +gtk_get_event_widget (GdkEvent *event) +{ + GtkWidget *widget; + gdk_window_get_user_data (event->any.window, (void**) &widget); + + return widget; +} + +static void +gtk_exit_func () +{ + if (initialized) + { + initialized = FALSE; + gtk_preview_uninit (); + } +} + +static void +gtk_timeout_insert (GtkTimeoutFunction *timeoutf) +{ + GtkTimeoutFunction *temp; + GList *temp_list; + GList *new_list; + + g_assert (timeoutf != NULL); + + /* Insert the timeout function appropriately. + * Appropriately meaning sort it into the list + * of timeout functions. + */ + temp_list = timeout_functions; + while (temp_list) + { + temp = temp_list->data; + if (timeoutf->interval < temp->interval) + { + new_list = g_list_alloc (); + new_list->data = timeoutf; + new_list->next = temp_list; + new_list->prev = temp_list->prev; + if (temp_list->prev) + temp_list->prev->next = new_list; + temp_list->prev = new_list; + + if (temp_list == timeout_functions) + timeout_functions = new_list; + + return; + } + + temp_list = temp_list->next; + } + + timeout_functions = g_list_append (timeout_functions, timeoutf); +} + +static gint +gtk_invoke_timeout_function (GtkTimeoutFunction *timeoutf) +{ + if (!timeoutf->interp) + return timeoutf->function (timeoutf->data); + else + { + GtkArg args[1]; + gint ret_val = FALSE; + args[0].name = NULL; + args[0].type = GTK_TYPE_BOOL; + args[0].d.pointer_data = &ret_val; + ((GtkCallbackMarshal)timeoutf->function) (NULL, + timeoutf->data, + 0, args); + return ret_val; + } +} + +static void +gtk_handle_current_timeouts (guint32 the_time) +{ + GList *tmp_list; + GtkTimeoutFunction *timeoutf; + + while (current_timeouts) + { + tmp_list = current_timeouts; + timeoutf = tmp_list->data; + + current_timeouts = g_list_remove_link (current_timeouts, tmp_list); + g_list_free (tmp_list); + + if (gtk_invoke_timeout_function (timeoutf) == FALSE) + { + gtk_timeout_destroy (timeoutf); + } + else + { + timeoutf->interval = timeoutf->originterval; + timeoutf->start = the_time; + gtk_timeout_insert (timeoutf); + } + } +} + +/* Utility function - make up for an ommision in glib */ +static GList * +gtk_main_list_concat (GList *list1, GList *list2) +{ + GList *tmp_list; + GList *list; + + if (list2) + { + tmp_list = g_list_last (list1); + if (tmp_list) + tmp_list->next = list2; + else + list1 = list2; + list2->prev = tmp_list; + } + + return list1; +} + +static void +gtk_handle_timeouts () +{ + guint32 the_time; + GList *tmp_list; + GList *tmp_list2; + GList *tmp_list3; + GtkTimeoutFunction *timeoutf; + + /* Caller must already have called gtk_handle_current_timeouts if + * necessary */ + g_assert (current_timeouts == NULL); + + if (timeout_functions) + { + the_time = gdk_time_get (); + + tmp_list = timeout_functions; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->interval <= (the_time - timeoutf->start)) + { + tmp_list2 = tmp_list; + tmp_list = tmp_list->next; + + timeout_functions = g_list_remove_link (timeout_functions, tmp_list2); + current_timeouts = gtk_main_list_concat (current_timeouts, tmp_list2); + } + else + { + timeoutf->interval -= (the_time - timeoutf->start); + timeoutf->start = the_time; + tmp_list = tmp_list->next; + } + } + + if (current_timeouts) + gtk_handle_current_timeouts(the_time); + } +} + +static gint +gtk_idle_invoke_function (GtkIdleFunction *idlef) +{ + if (!idlef->interp) + return idlef->function (idlef->data); + else + { + GtkArg args[1]; + gint ret_val = FALSE; + args[0].name = NULL; + args[0].type = GTK_TYPE_BOOL; + args[0].d.pointer_data = &ret_val; + ((GtkCallbackMarshal)idlef->function) (NULL, + idlef->data, + 0, args); + return ret_val; + } +} + +static void +gtk_handle_current_idles () +{ + GList *tmp_list; + GtkIdleFunction *idlef; + + while (current_idles) + { + tmp_list = current_idles; + idlef = tmp_list->data; + + current_idles = g_list_remove_link (current_idles, tmp_list); + + if (gtk_idle_invoke_function (idlef) == FALSE) + { + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + } + else + { + idle_functions = gtk_main_list_concat (idle_functions, tmp_list); + } + } +} + +static void +gtk_handle_idle () +{ + GtkIdleFunction *idlef; + GList *tmp_list; + GList *tmp_list2; + + /* Caller must already have called gtk_handle_current_idles if + necessary */ + g_assert (current_idles == NULL); + + if (idle_functions) + { + current_idles = idle_functions; + idle_functions = NULL; + + gtk_handle_current_idles(); + } +} + +static void +gtk_handle_timer () +{ + GtkTimeoutFunction *timeoutf; + + if (idle_functions) + { + gdk_timer_set (0); + gdk_timer_enable (); + } + else if (timeout_functions) + { + timeoutf = timeout_functions->data; + gdk_timer_set (timeoutf->interval); + gdk_timer_enable (); + } + else + { + gdk_timer_set (0); + gdk_timer_disable (); + } +} + +static void +gtk_propagate_event (GtkWidget *widget, + GdkEvent *event) +{ + GtkWidget *parent; + gint handled_event; + gint parent_old_value; + gint old_value; + + g_return_if_fail (widget != NULL); + g_return_if_fail (event != NULL); + + handled_event = FALSE; + + if ((event->type == GDK_KEY_PRESS) || + (event->type == GDK_KEY_RELEASE)) + { + /* Only send key events to window widgets. + * The window widget will in turn pass the + * key event on to the currently focused widget + * for that window. + */ + parent = gtk_widget_get_ancestor (widget, gtk_window_get_type ()); + if (parent && GTK_WIDGET_IS_SENSITIVE (parent)) + { + parent_old_value = GTK_OBJECT_IN_CALL (parent); + GTK_OBJECT_SET_FLAGS (parent, GTK_IN_CALL); + + handled_event = gtk_widget_event (parent, event); + + if (!parent_old_value) + GTK_OBJECT_UNSET_FLAGS (parent, GTK_IN_CALL); + + if (GTK_OBJECT_NEED_DESTROY (parent) && !GTK_OBJECT_IN_CALL (parent)) + { + gtk_object_destroy (GTK_OBJECT (parent)); + return; + } + } + } + + if (!handled_event) + { + old_value = GTK_OBJECT_IN_CALL (widget); + GTK_OBJECT_SET_FLAGS (widget, GTK_IN_CALL); + + /* Other events get propagated up the widget tree + * so that parents can see the button and motion + * events of the children. + */ + parent = widget; + while (parent) + { + parent_old_value = GTK_OBJECT_IN_CALL (parent); + GTK_OBJECT_SET_FLAGS (parent, GTK_IN_CALL); + + handled_event = (!GTK_WIDGET_IS_SENSITIVE (parent) || + gtk_widget_event (parent, event)); + + if (!parent_old_value) + GTK_OBJECT_UNSET_FLAGS (parent, GTK_IN_CALL); + + if (handled_event) + break; + + if (GTK_OBJECT_NEED_DESTROY (parent) && !GTK_OBJECT_IN_CALL (parent)) + { + gtk_object_destroy (GTK_OBJECT (parent)); + break; + } + + parent = parent->parent; + } + + if (!old_value) + GTK_OBJECT_UNSET_FLAGS (widget, GTK_IN_CALL); + + if (GTK_OBJECT_NEED_DESTROY (widget) && !GTK_OBJECT_IN_CALL (widget)) + gtk_object_destroy (GTK_OBJECT (widget)); + } +} + + +static void +gtk_error (char *str) +{ + gtk_print (str); +} + +static void +gtk_warning (char *str) +{ + gtk_print (str); +} + +static void +gtk_message (char *str) +{ + gtk_print (str); +} + +static void +gtk_print (char *str) +{ + static GtkWidget *window = NULL; + static GtkWidget *text; + static int level = 0; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *table; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *separator; + GtkWidget *button; + + if (level > 0) + { + fputs (str, stdout); + fflush (stdout); + return; + } + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + /* + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gtk_widget_destroyed, + &window); + */ + gtk_window_set_title (GTK_WINDOW (window), "Messages"); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + text = gtk_text_new (NULL, NULL); + gtk_text_set_editable (GTK_TEXT (text), FALSE); + gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); + gtk_widget_show (text); + gtk_widget_realize (text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_hide, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + level += 1; + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1); + level -= 1; + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); +} diff --git a/gtk/gtkmain.h b/gtk/gtkmain.h new file mode 100644 index 0000000000..9d014e47c9 --- /dev/null +++ b/gtk/gtkmain.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MAIN_H__ +#define __GTK_MAIN_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Initialization, exit, mainloop and miscellaneous routines + */ +void gtk_init (int *argc, + char ***argv); +void gtk_exit (gint error_code); +gchar* gtk_set_locale (void); +void gtk_main (void); +void gtk_main_quit (void); +gint gtk_main_iteration (void); + +gint gtk_true (void); +gint gtk_false (void); + +void gtk_grab_add (GtkWidget *widget); +void gtk_grab_remove (GtkWidget *widget); + +void gtk_init_add (GtkFunction function, + gpointer data); + +gint gtk_timeout_add (guint32 interval, + GtkFunction function, + gpointer data); +gint gtk_timeout_add_interp (guint32 interval, + GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify notify); +void gtk_timeout_remove (gint tag); + +gint gtk_idle_add (GtkFunction function, + gpointer data); +gint gtk_idle_add_interp (GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy); +void gtk_idle_remove (gint tag); +void gtk_idle_remove_by_data (gpointer data); + +void gtk_get_current_event (GdkEvent *event); +GtkWidget* gtk_get_event_widget (GdkEvent *event); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MAIN_H__ */ diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c new file mode 100644 index 0000000000..13fff9023a --- /dev/null +++ b/gtk/gtkmenu.c @@ -0,0 +1,732 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <ctype.h> +#include "gdk/gdkkeysyms.h" +#include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtksignal.h" + + +#define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_menu_class_init (GtkMenuClass *klass); +static void gtk_menu_init (GtkMenu *menu); +static void gtk_menu_show (GtkWidget *widget); +static void gtk_menu_map (GtkWidget *widget); +static void gtk_menu_unmap (GtkWidget *widget); +static void gtk_menu_realize (GtkWidget *widget); +static void gtk_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_menu_paint (GtkWidget *widget); +static void gtk_menu_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_menu_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_menu_configure (GtkWidget *widget, + GdkEventConfigure *event); +static gint gtk_menu_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_menu_need_resize (GtkContainer *container); +static void gtk_menu_deactivate (GtkMenuShell *menu_shell); + + +guint +gtk_menu_get_type () +{ + static guint menu_type = 0; + + if (!menu_type) + { + GtkTypeInfo menu_info = + { + "GtkMenu", + sizeof (GtkMenu), + sizeof (GtkMenuClass), + (GtkClassInitFunc) gtk_menu_class_init, + (GtkObjectInitFunc) gtk_menu_init, + (GtkArgFunc) NULL, + }; + + menu_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_info); + } + + return menu_type; +} + +static void +gtk_menu_class_init (GtkMenuClass *class) +{ + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + GtkMenuShellClass *menu_shell_class; + + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + menu_shell_class = (GtkMenuShellClass*) class; + + widget_class->show = gtk_menu_show; + widget_class->map = gtk_menu_map; + widget_class->unmap = gtk_menu_unmap; + widget_class->realize = gtk_menu_realize; + widget_class->draw = gtk_menu_draw; + widget_class->size_request = gtk_menu_size_request; + widget_class->size_allocate = gtk_menu_size_allocate; + widget_class->expose_event = gtk_menu_expose; + widget_class->configure_event = gtk_menu_configure; + widget_class->key_press_event = gtk_menu_key_press; + + container_class->need_resize = gtk_menu_need_resize; + + menu_shell_class->submenu_placement = GTK_LEFT_RIGHT; + menu_shell_class->deactivate = gtk_menu_deactivate; +} + +static void +gtk_menu_init (GtkMenu *menu) +{ + GTK_WIDGET_SET_FLAGS (menu, GTK_ANCHORED); + + menu->parent_menu_item = NULL; + menu->old_active_menu_item = NULL; + menu->accelerator_table = NULL; + menu->position_func = NULL; + menu->position_func_data = NULL; + + GTK_MENU_SHELL (menu)->menu_flag = TRUE; +} + +GtkWidget* +gtk_menu_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_menu_get_type ())); +} + +void +gtk_menu_append (GtkMenu *menu, + GtkWidget *child) +{ + gtk_menu_shell_append (GTK_MENU_SHELL (menu), child); +} + +void +gtk_menu_prepend (GtkMenu *menu, + GtkWidget *child) +{ + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), child); +} + +void +gtk_menu_insert (GtkMenu *menu, + GtkWidget *child, + gint position) +{ + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), child, position); +} + +void +gtk_menu_popup (GtkMenu *menu, + GtkWidget *parent_menu_shell, + GtkWidget *parent_menu_item, + GtkMenuPositionFunc func, + gpointer data, + gint button, + guint32 activate_time) +{ + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + GTK_MENU_SHELL (menu)->parent_menu_shell = parent_menu_shell; + GTK_MENU_SHELL (menu)->active = TRUE; + GTK_MENU_SHELL (menu)->button = button; + + menu->parent_menu_item = parent_menu_item; + menu->position_func = func; + menu->position_func_data = data; + GTK_MENU_SHELL (menu)->activate_time = activate_time; + + gtk_widget_show (GTK_WIDGET (menu)); + gtk_grab_add (GTK_WIDGET (menu)); +} + +void +gtk_menu_popdown (GtkMenu *menu) +{ + GtkMenuShell *menu_shell; + + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + menu_shell = GTK_MENU_SHELL (menu); + + menu_shell->parent_menu_shell = NULL; + menu_shell->active = FALSE; + + if (menu_shell->active_menu_item) + { + menu->old_active_menu_item = menu_shell->active_menu_item; + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + menu_shell->active_menu_item = NULL; + } + + gtk_widget_hide (GTK_WIDGET (menu)); + gtk_grab_remove (GTK_WIDGET (menu)); +} + +GtkWidget* +gtk_menu_get_active (GtkMenu *menu) +{ + GtkWidget *child; + GList *children; + + g_return_val_if_fail (menu != NULL, NULL); + g_return_val_if_fail (GTK_IS_MENU (menu), NULL); + + if (!menu->old_active_menu_item) + { + child = NULL; + children = GTK_MENU_SHELL (menu)->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_BIN (child)->child) + break; + child = NULL; + } + + menu->old_active_menu_item = child; + } + + return menu->old_active_menu_item; +} + +void +gtk_menu_set_active (GtkMenu *menu, + gint index) +{ + GtkWidget *child; + GList *tmp_list; + + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + tmp_list = g_list_nth (GTK_MENU_SHELL (menu)->children, index); + if (tmp_list) + { + child = tmp_list->data; + if (GTK_BIN (child)->child) + menu->old_active_menu_item = child; + } +} + +void +gtk_menu_set_accelerator_table (GtkMenu *menu, + GtkAcceleratorTable *table) +{ + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + if (menu->accelerator_table) + gtk_accelerator_table_unref (menu->accelerator_table); + + menu->accelerator_table = table; + if (menu->accelerator_table) + gtk_accelerator_table_ref (menu->accelerator_table); +} + + +static void +gtk_menu_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + gtk_widget_map (widget); +} + +static void +gtk_menu_map (GtkWidget *widget) +{ + GtkMenu *menu; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + GtkAllocation allocation; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + menu = GTK_MENU (widget); + menu_shell = GTK_MENU_SHELL (widget); + GTK_WIDGET_SET_FLAGS (menu_shell, GTK_MAPPED); + GTK_WIDGET_UNSET_FLAGS (menu_shell, GTK_UNMAPPED); + + gtk_widget_size_request (widget, &widget->requisition); + + if (menu_shell->menu_flag) + { + menu_shell->menu_flag = FALSE; + + allocation.x = widget->allocation.x; + allocation.y = widget->allocation.y; + allocation.width = widget->requisition.width; + allocation.height = widget->requisition.height; + + gtk_widget_size_allocate (widget, &allocation); + } + + gdk_window_get_pointer (NULL, &x, &y, NULL); + + if (menu->position_func) + (* menu->position_func) (menu, &x, &y, menu->position_func_data); + else + { + gint screen_width; + gint screen_height; + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + x -= 2; + y -= 2; + + if ((x + widget->requisition.width) > screen_width) + x -= ((x + widget->requisition.width) - screen_width); + if (x < 0) + x = 0; + if ((y + widget->requisition.height) > screen_height) + y -= ((y + widget->requisition.height) - screen_height); + if (y < 0) + y = 0; + } + + gdk_window_move_resize (widget->window, x, y, + widget->requisition.width, + widget->requisition.height); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + gdk_window_show (widget->window); +} + +static void +gtk_menu_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + GTK_WIDGET_SET_FLAGS (widget, GTK_UNMAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_menu_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.window_type = GDK_WINDOW_TEMP; + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_KEY_PRESS_MASK | + GDK_STRUCTURE_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkMenu *menu; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + gint max_accelerator_size; + gint max_toggle_size; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + g_return_if_fail (requisition != NULL); + + menu = GTK_MENU (widget); + menu_shell = GTK_MENU_SHELL (widget); + + requisition->width = 0; + requisition->height = 0; + + max_accelerator_size = 0; + max_toggle_size = 0; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE; + gtk_widget_size_request (child, &child->requisition); + + requisition->width = MAX (requisition->width, child->requisition.width); + requisition->height += child->requisition.height; + + max_accelerator_size = MAX (max_accelerator_size, GTK_MENU_ITEM (child)->accelerator_size); + max_toggle_size = MAX (max_toggle_size, MENU_ITEM_CLASS (child)->toggle_size); + } + } + + requisition->width += max_toggle_size + max_accelerator_size; + requisition->width += (GTK_CONTAINER (menu)->border_width + + widget->style->klass->xthickness) * 2; + requisition->height += (GTK_CONTAINER (menu)->border_width + + widget->style->klass->ythickness) * 2; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + GTK_MENU_ITEM (child)->accelerator_size = max_accelerator_size; + GTK_MENU_ITEM (child)->toggle_size = max_toggle_size; + } +} + +static void +gtk_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkMenu *menu; + GtkMenuShell *menu_shell; + GtkWidget *child; + GtkAllocation child_allocation; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + g_return_if_fail (allocation != NULL); + + menu = GTK_MENU (widget); + menu_shell = GTK_MENU_SHELL (widget); + + widget->allocation = *allocation; + + if (menu_shell->children) + { + child_allocation.x = (GTK_CONTAINER (menu)->border_width + + widget->style->klass->xthickness); + child_allocation.y = (GTK_CONTAINER (menu)->border_width + + widget->style->klass->ythickness); + child_allocation.width = allocation->width - child_allocation.x * 2; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + child_allocation.height = child->requisition.height; + + gtk_widget_size_allocate (child, &child_allocation); + + child_allocation.y += child_allocation.height; + } + } + } +} + +static void +gtk_menu_paint (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_draw_shadow (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_OUT, + 0, 0, + widget->allocation.width, + widget->allocation.height); + } +} + +static void +gtk_menu_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } + } +} + +static gint +gtk_menu_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (!GTK_WIDGET_UNMAPPED (widget)) + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + child_event = *event; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static gint +gtk_menu_configure (GtkWidget *widget, + GdkEventConfigure *event) +{ + GtkAllocation allocation; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_MENU_SHELL (widget)->menu_flag) + { + GTK_MENU_SHELL (widget)->menu_flag = FALSE; + + allocation.x = 0; + allocation.y = 0; + allocation.width = event->width; + allocation.height = event->height; + + gtk_widget_size_allocate (widget, &allocation); + } + + return FALSE; +} + +static gint +gtk_menu_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkAllocation allocation; + GtkAcceleratorTable *table; + GtkMenuShell *menu_shell; + GtkMenuItem *menu_item; + gchar *signame; + int delete; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + delete = ((event->keyval == GDK_Delete) || + (event->keyval == GDK_BackSpace)); + + if (delete || ((event->keyval >= 0x20) && (event->keyval <= 0xFF))) + { + menu_shell = GTK_MENU_SHELL (widget); + menu_item = GTK_MENU_ITEM (menu_shell->active_menu_item); + + if (menu_item && GTK_BIN (menu_item)->child) + { + /* block resizes */ + gtk_container_block_resize (GTK_CONTAINER (widget)); + + table = NULL; + /* if the menu item currently has an accelerator then we'll + * remove it before we do anything else. + */ + if (menu_item->accelerator_signal) + { + signame = gtk_signal_name (menu_item->accelerator_signal); + table = gtk_accelerator_table_find (GTK_OBJECT (widget), + signame, + menu_item->accelerator_key, + menu_item->accelerator_mods); + if (!table) + table = GTK_MENU (widget)->accelerator_table; + gtk_widget_remove_accelerator (GTK_WIDGET (menu_item), + table, signame); + } + + if (!table) + table = GTK_MENU (widget)->accelerator_table; + + /* if we aren't simply deleting the accelerator, then we'll install + * the new one now. + */ + if (!delete) + gtk_widget_install_accelerator (GTK_WIDGET (menu_item), + table, "activate", + toupper (event->keyval), + event->state); + + /* check and see if the menu has changed size. */ + gtk_widget_size_request (widget, &widget->requisition); + + allocation.x = widget->allocation.x; + allocation.y = widget->allocation.y; + allocation.width = widget->requisition.width; + allocation.height = widget->requisition.height; + + if ((allocation.width == widget->allocation.width) && + (allocation.height == widget->allocation.height)) + { + gtk_widget_queue_draw (widget); + } + else + { + gtk_widget_size_allocate (GTK_WIDGET (widget), &allocation); + gtk_menu_map (widget); + } + + /* unblock resizes */ + gtk_container_unblock_resize (GTK_CONTAINER (widget)); + } + } + + return FALSE; +} + +static gint +gtk_menu_need_resize (GtkContainer *container) +{ + GtkAllocation allocation; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (container), FALSE); + + if (GTK_WIDGET_VISIBLE (container)) + { + GTK_MENU_SHELL (container)->menu_flag = FALSE; + + gtk_widget_size_request (GTK_WIDGET (container), + >K_WIDGET (container)->requisition); + + allocation.x = GTK_WIDGET (container)->allocation.x; + allocation.y = GTK_WIDGET (container)->allocation.y; + allocation.width = GTK_WIDGET (container)->requisition.width; + allocation.height = GTK_WIDGET (container)->requisition.height; + + gtk_widget_size_allocate (GTK_WIDGET (container), &allocation); + } + else + { + GTK_MENU_SHELL (container)->menu_flag = TRUE; + } + + return FALSE; +} + +static void +gtk_menu_deactivate (GtkMenuShell *menu_shell) +{ + GtkMenuShell *parent; + + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU (menu_shell)); + + parent = GTK_MENU_SHELL (menu_shell->parent_menu_shell); + + menu_shell->activate_time = 0; + gtk_menu_popdown (GTK_MENU (menu_shell)); + + if (parent) + gtk_menu_shell_deactivate (parent); +} diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h new file mode 100644 index 0000000000..5cd5d28fa9 --- /dev/null +++ b/gtk/gtkmenu.h @@ -0,0 +1,94 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MENU_H__ +#define __GTK_MENU_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkaccelerator.h> +#include <gtk/gtkmenushell.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU(obj) GTK_CHECK_CAST (obj, gtk_menu_get_type (), GtkMenu) +#define GTK_MENU_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_get_type (), GtkMenuClass) +#define GTK_IS_MENU(obj) GTK_CHECK_TYPE (obj, gtk_menu_get_type ()) + + +typedef struct _GtkMenu GtkMenu; +typedef struct _GtkMenuClass GtkMenuClass; + +typedef void (*GtkMenuPositionFunc) (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data); + +struct _GtkMenu +{ + GtkMenuShell menu_shell; + + GList *children; + + GtkWidget *parent_menu_item; + GtkWidget *old_active_menu_item; + + GtkAcceleratorTable *accelerator_table; + GtkMenuPositionFunc position_func; + gpointer position_func_data; +}; + +struct _GtkMenuClass +{ + GtkMenuShellClass parent_class; +}; + + +guint gtk_menu_get_type (void); +GtkWidget* gtk_menu_new (void); +void gtk_menu_append (GtkMenu *menu, + GtkWidget *child); +void gtk_menu_prepend (GtkMenu *menu, + GtkWidget *child); +void gtk_menu_insert (GtkMenu *menu, + GtkWidget *child, + gint position); +void gtk_menu_popup (GtkMenu *menu, + GtkWidget *parent_menu_shell, + GtkWidget *parent_menu_item, + GtkMenuPositionFunc func, + gpointer data, + gint button, + guint32 activate_time); +void gtk_menu_popdown (GtkMenu *menu); +GtkWidget* gtk_menu_get_active (GtkMenu *menu); +void gtk_menu_set_active (GtkMenu *menu, + gint index); +void gtk_menu_set_accelerator_table (GtkMenu *menu, + GtkAcceleratorTable *table); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_H__ */ diff --git a/gtk/gtkmenubar.c b/gtk/gtkmenubar.c new file mode 100644 index 0000000000..19f0aa3e76 --- /dev/null +++ b/gtk/gtkmenubar.c @@ -0,0 +1,310 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkmain.h" +#include "gtkmenubar.h" +#include "gtkmenuitem.h" + + +#define BORDER_SPACING 2 +#define CHILD_SPACING 3 + + +static void gtk_menu_bar_class_init (GtkMenuBarClass *klass); +static void gtk_menu_bar_init (GtkMenuBar *menu_bar); +static void gtk_menu_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_menu_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_menu_bar_paint (GtkWidget *widget); +static void gtk_menu_bar_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_menu_bar_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_menu_bar_get_type () +{ + static guint menu_bar_type = 0; + + if (!menu_bar_type) + { + GtkTypeInfo menu_bar_info = + { + "GtkMenuBar", + sizeof (GtkMenuBar), + sizeof (GtkMenuBarClass), + (GtkClassInitFunc) gtk_menu_bar_class_init, + (GtkObjectInitFunc) gtk_menu_bar_init, + (GtkArgFunc) NULL, + }; + + menu_bar_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_bar_info); + } + + return menu_bar_type; +} + +static void +gtk_menu_bar_class_init (GtkMenuBarClass *class) +{ + GtkWidgetClass *widget_class; + GtkMenuShellClass *menu_shell_class; + + widget_class = (GtkWidgetClass*) class; + menu_shell_class = (GtkMenuShellClass*) class; + + widget_class->draw = gtk_menu_bar_draw; + widget_class->size_request = gtk_menu_bar_size_request; + widget_class->size_allocate = gtk_menu_bar_size_allocate; + widget_class->expose_event = gtk_menu_bar_expose; + + menu_shell_class->submenu_placement = GTK_TOP_BOTTOM; +} + +static void +gtk_menu_bar_init (GtkMenuBar *menu_bar) +{ +} + +GtkWidget* +gtk_menu_bar_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_menu_bar_get_type ())); +} + +void +gtk_menu_bar_append (GtkMenuBar *menu_bar, + GtkWidget *child) +{ + gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), child); +} + +void +gtk_menu_bar_prepend (GtkMenuBar *menu_bar, + GtkWidget *child) +{ + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu_bar), child); +} + +void +gtk_menu_bar_insert (GtkMenuBar *menu_bar, + GtkWidget *child, + gint position) +{ + gtk_menu_shell_insert (GTK_MENU_SHELL (menu_bar), child, position); +} + + +static void +gtk_menu_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkMenuBar *menu_bar; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + gint nchildren; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + g_return_if_fail (requisition != NULL); + + requisition->width = 0; + requisition->height = 0; + + if (GTK_WIDGET_VISIBLE (widget)) + { + menu_bar = GTK_MENU_BAR (widget); + menu_shell = GTK_MENU_SHELL (widget); + + nchildren = 0; + children = menu_shell->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + GTK_MENU_ITEM (child)->show_submenu_indicator = FALSE; + gtk_widget_size_request (child, &child->requisition); + + requisition->width += child->requisition.width; + requisition->height = MAX (requisition->height, child->requisition.height); + + nchildren += 1; + } + } + + requisition->width += (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING) * 2; + requisition->height += (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->ythickness + + BORDER_SPACING) * 2; + + if (nchildren > 0) + requisition->width += 2 * CHILD_SPACING * (nchildren - 1); + } +} + +static void +gtk_menu_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkMenuBar *menu_bar; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + GtkAllocation child_allocation; + guint offset; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + g_return_if_fail (allocation != NULL); + + menu_bar = GTK_MENU_BAR (widget); + menu_shell = GTK_MENU_SHELL (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + if (menu_shell->children) + { + child_allocation.x = (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING); + offset = child_allocation.x; /* Window edge to menubar start */ + + child_allocation.y = (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->ythickness + + BORDER_SPACING); + child_allocation.height = allocation->height - child_allocation.y * 2; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + /* Support for the right justified help menu */ + if ( (children == NULL) && (GTK_IS_MENU_ITEM(child)) + && (GTK_MENU_ITEM(child)->right_justify)) { + child_allocation.x = allocation->width - + child_allocation.width - CHILD_SPACING - offset; + } + if (GTK_WIDGET_VISIBLE (child)) + { + child_allocation.width = child->requisition.width; + + gtk_widget_size_allocate (child, &child_allocation); + + child_allocation.x += child_allocation.width + CHILD_SPACING * 2; + } + } + } +} + +static void +gtk_menu_bar_paint (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_draw_shadow (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_OUT, + 0, 0, + widget->allocation.width, + widget->allocation.height); + } +} + +static void +gtk_menu_bar_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_bar_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } + } +} + +static gint +gtk_menu_bar_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_bar_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + child_event = *event; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} diff --git a/gtk/gtkmenubar.h b/gtk/gtkmenubar.h new file mode 100644 index 0000000000..691e8f36f3 --- /dev/null +++ b/gtk/gtkmenubar.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MENU_BAR_H__ +#define __GTK_MENU_BAR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkmenushell.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU_BAR(obj) GTK_CHECK_CAST (obj, gtk_menu_bar_get_type (), GtkMenuBar) +#define GTK_MENU_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_bar_get_type (), GtkMenuBarClass) +#define GTK_IS_MENU_BAR(obj) GTK_CHECK_TYPE (obj, gtk_menu_bar_get_type ()) + + +typedef struct _GtkMenuBar GtkMenuBar; +typedef struct _GtkMenuBarClass GtkMenuBarClass; + +struct _GtkMenuBar +{ + GtkMenuShell menu_shell; +}; + +struct _GtkMenuBarClass +{ + GtkMenuShellClass parent_class; +}; + + +guint gtk_menu_bar_get_type (void); +GtkWidget* gtk_menu_bar_new (void); +void gtk_menu_bar_append (GtkMenuBar *menu_bar, + GtkWidget *child); +void gtk_menu_bar_prepend (GtkMenuBar *menu_bar, + GtkWidget *child); +void gtk_menu_bar_insert (GtkMenuBar *menu_bar, + GtkWidget *child, + gint position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_BAR_H__ */ diff --git a/gtk/gtkmenufactory.c b/gtk/gtkmenufactory.c new file mode 100644 index 0000000000..d6e9ea6841 --- /dev/null +++ b/gtk/gtkmenufactory.c @@ -0,0 +1,541 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include "gtkcheckmenuitem.h" +#include "gtkmenu.h" +#include "gtkmenubar.h" +#include "gtkmenufactory.h" +#include "gtkmenuitem.h" +#include "gtksignal.h" + + +enum +{ + CREATE = 1 << 0, + DESTROY = 1 << 1, + CHECK = 1 << 2 +}; + + +static void gtk_menu_factory_create (GtkMenuFactory *factory, + GtkMenuEntry *entry, + GtkWidget *parent, + const char *path); +static void gtk_menu_factory_remove (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path); +static GtkWidget* gtk_menu_factory_make_widget (GtkMenuFactory *factory); +static GtkMenuPath* gtk_menu_factory_get (GtkWidget *parent, + const char *path, + int flags); +static GtkMenuPath* gtk_menu_factory_find_recurse (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path); +static void gtk_menu_factory_parse_accelerator (const char *accelerator, + char *accelerator_key, + guint8 *accelerator_mods); + + +GtkMenuFactory* +gtk_menu_factory_new (GtkMenuFactoryType type) +{ + GtkMenuFactory *factory; + + factory = g_new (GtkMenuFactory, 1); + factory->path = NULL; + factory->type = type; + factory->table = NULL; + factory->widget = NULL; + factory->subfactories = NULL; + + return factory; +} + +void +gtk_menu_factory_destroy (GtkMenuFactory *factory) +{ + GtkMenuFactory *subfactory; + GList *tmp_list; + + g_return_if_fail (factory != NULL); + + if (factory->path) + g_free (factory->path); + + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_menu_factory_destroy (subfactory); + } +} + +void +gtk_menu_factory_add_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries) +{ + int i; + + g_return_if_fail (factory != NULL); + g_return_if_fail (entries != NULL); + g_return_if_fail (nentries > 0); + + if (!factory->widget) + factory->widget = gtk_menu_factory_make_widget (factory); + + for (i = 0; i < nentries; i++) + gtk_menu_factory_create (factory, &entries[i], factory->widget, entries[i].path); +} + +void +gtk_menu_factory_add_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path) +{ + g_return_if_fail (factory != NULL); + g_return_if_fail (subfactory != NULL); + g_return_if_fail (path != NULL); + + if (subfactory->path) + g_free (subfactory->path); + subfactory->path = g_strdup (path); + + factory->subfactories = g_list_append (factory->subfactories, subfactory); +} + +void +gtk_menu_factory_remove_paths (GtkMenuFactory *factory, + char **paths, + int npaths) +{ + int i; + + g_return_if_fail (factory != NULL); + g_return_if_fail (paths != NULL); + g_return_if_fail (npaths > 0); + + if (factory->widget) + { + for (i = 0; i < npaths; i++) + gtk_menu_factory_remove (factory, factory->widget, paths[i]); + } +} + +void +gtk_menu_factory_remove_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries) +{ + int i; + + g_return_if_fail (factory != NULL); + g_return_if_fail (entries != NULL); + g_return_if_fail (nentries > 0); + + if (factory->widget) + { + for (i = 0; i < nentries; i++) + gtk_menu_factory_remove (factory, factory->widget, entries[i].path); + } +} + +void +gtk_menu_factory_remove_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path) +{ + g_return_if_fail (factory != NULL); + g_return_if_fail (subfactory != NULL); + g_return_if_fail (path != NULL); + + g_warning ("FIXME: gtk_menu_factory_remove_subfactory"); +} + +GtkMenuPath* +gtk_menu_factory_find (GtkMenuFactory *factory, + const char *path) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (path != NULL, NULL); + + return gtk_menu_factory_find_recurse (factory, factory->widget, path); +} + + +static void +gtk_menu_factory_create (GtkMenuFactory *factory, + GtkMenuEntry *entry, + GtkWidget *parent, + const char *path) +{ + GtkMenuFactory *subfactory; + GtkMenuPath *menu_path; + GtkWidget *menu; + GList *tmp_list; + char tmp_path[256]; + char accelerator_key; + guint8 accelerator_mods; + char *p; + + g_return_if_fail (factory != NULL); + g_return_if_fail (entry != NULL); + + /* If 'path' is empty, then simply return. + */ + if (!path || path[0] == '\0') + return; + + /* Strip off the next part of the path. + */ + p = strchr (path, '/'); + + /* If this is the last part of the path ('p' is + * NULL), then we create an item. + */ + if (!p) + { + /* Check to see if this item is a separator. + */ + if (strcmp (path, "<separator>") == 0) + { + entry->widget = gtk_menu_item_new (); + gtk_container_add (GTK_CONTAINER (parent), entry->widget); + gtk_widget_show (entry->widget); + } + else + { + if (strncmp (path, "<check>", 7) == 0) + menu_path = gtk_menu_factory_get (parent, path + 7, CREATE | CHECK); + else + menu_path = gtk_menu_factory_get (parent, path, CREATE); + entry->widget = menu_path->widget; + + if (strcmp (path, "<nothing>") == 0) + gtk_widget_hide (entry->widget); + + if (entry->accelerator) + { + gtk_menu_factory_parse_accelerator (entry->accelerator, + &accelerator_key, + &accelerator_mods); + if (!factory->table) + { + factory->table = gtk_accelerator_table_new (); + gtk_accelerator_table_ref (factory->table); + } + + gtk_widget_install_accelerator (menu_path->widget, + factory->table, + "activate", + accelerator_key, + accelerator_mods); + } + + if (entry->callback) + gtk_signal_connect (GTK_OBJECT (menu_path->widget), "activate", + (GtkSignalFunc) entry->callback, + entry->callback_data); + } + } + else + { + strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path)); + tmp_path[(long) p - (long) path] = '\0'; + + menu_path = gtk_menu_factory_get (parent, tmp_path, 0); + if (!menu_path) + { + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + if (subfactory->path && + (strcmp (subfactory->path, tmp_path) == 0)) + { + if (!subfactory->widget) + subfactory->widget = gtk_menu_factory_make_widget (subfactory); + gtk_menu_factory_create (subfactory, entry, subfactory->widget, p + 1); + return; + } + } + + menu_path = gtk_menu_factory_get (parent, tmp_path, CREATE); + } + + entry->widget = menu_path->widget; + menu = GTK_MENU_ITEM (menu_path->widget)->submenu; + + if (!menu) + { + menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_path->widget), menu); + + if (!factory->table) + { + factory->table = gtk_accelerator_table_new (); + gtk_accelerator_table_ref (factory->table); + } + gtk_menu_set_accelerator_table (GTK_MENU (menu), factory->table); + } + + gtk_menu_factory_create (factory, entry, menu, p + 1); + } +} + +static void +gtk_menu_factory_remove (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path) +{ + GtkMenuFactory *subfactory; + GtkMenuPath *menu_path; + GtkWidget *menu; + GList *tmp_list; + char tmp_path[256]; + char *p; + + if (!path || path[0] == '\0') + return; + + p = strchr (path, '/'); + + if (!p) + { + if (parent) + gtk_menu_factory_get (parent, path, DESTROY); + } + else + { + strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path)); + tmp_path[(long) p - (long) path] = '\0'; + + menu_path = gtk_menu_factory_get (parent, tmp_path, 0); + if (!menu_path) + { + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + if (subfactory->path && + (strcmp (subfactory->path, tmp_path) == 0)) + { + if (!subfactory->widget) + return; + gtk_menu_factory_remove (subfactory, subfactory->widget, p + 1); + } + } + } + else + { + menu = GTK_MENU_ITEM (menu_path->widget)->submenu; + if (menu) + gtk_menu_factory_remove (factory, menu, p + 1); + } + } +} + +static GtkWidget* +gtk_menu_factory_make_widget (GtkMenuFactory *factory) +{ + GtkWidget *widget; + + g_return_val_if_fail (factory != NULL, NULL); + + switch (factory->type) + { + case GTK_MENU_FACTORY_MENU: + widget = gtk_menu_new (); + + if (!factory->table) + { + factory->table = gtk_accelerator_table_new (); + gtk_accelerator_table_ref (factory->table); + } + gtk_menu_set_accelerator_table (GTK_MENU (widget), factory->table); + return widget; + case GTK_MENU_FACTORY_MENU_BAR: + return gtk_menu_bar_new (); + case GTK_MENU_FACTORY_OPTION_MENU: + g_error ("not implemented"); + break; + } + + return NULL; +} + +static GtkMenuPath* +gtk_menu_factory_get (GtkWidget *parent, + const char *path, + int flags) +{ + GtkMenuPath *menu_path; + GList *tmp_list; + + tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent)); + while (tmp_list) + { + menu_path = tmp_list->data; + tmp_list = tmp_list->next; + + if (strcmp (menu_path->path, path) == 0) + { + if (flags & DESTROY) + { + tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent)); + tmp_list = g_list_remove (tmp_list, menu_path); + gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list); + + gtk_widget_destroy (menu_path->widget); + g_free (menu_path->path); + g_free (menu_path); + + return NULL; + } + else + { + return menu_path; + } + } + } + + if (flags & CREATE) + { + menu_path = g_new (GtkMenuPath, 1); + menu_path->path = g_strdup (path); + + if (flags & CHECK) + menu_path->widget = gtk_check_menu_item_new_with_label (path); + else + menu_path->widget = gtk_menu_item_new_with_label (path); + + gtk_container_add (GTK_CONTAINER (parent), menu_path->widget); + gtk_object_set_user_data (GTK_OBJECT (menu_path->widget), NULL); + gtk_widget_show (menu_path->widget); + + tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent)); + tmp_list = g_list_prepend (tmp_list, menu_path); + gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list); + + return menu_path; + } + + return NULL; +} + +static GtkMenuPath* +gtk_menu_factory_find_recurse (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path) +{ + GtkMenuFactory *subfactory; + GtkMenuPath *menu_path; + GtkWidget *menu; + GList *tmp_list; + char tmp_path[256]; + char *p; + + if (!path || path[0] == '\0') + return NULL; + + p = strchr (path, '/'); + + if (!p) + { + if (parent) + return gtk_menu_factory_get (parent, path, 0); + } + else + { + strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path)); + tmp_path[(long) p - (long) path] = '\0'; + + menu_path = gtk_menu_factory_get (parent, tmp_path, 0); + if (!menu_path) + { + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + if (subfactory->path && + (strcmp (subfactory->path, tmp_path) == 0)) + { + if (!subfactory->widget) + return NULL; + return gtk_menu_factory_find_recurse (subfactory, subfactory->widget, p + 1); + } + } + + return NULL; + } + + menu = GTK_MENU_ITEM (menu_path->widget)->submenu; + if (menu) + return gtk_menu_factory_find_recurse (factory, menu, p + 1); + } + + return NULL; +} + +static void +gtk_menu_factory_parse_accelerator (const char *accelerator, + char *accelerator_key, + guint8 *accelerator_mods) +{ + int done; + + g_return_if_fail (accelerator != NULL); + g_return_if_fail (accelerator_key != NULL); + g_return_if_fail (accelerator_mods != NULL); + + *accelerator_key = 0; + *accelerator_mods = 0; + + done = FALSE; + while (!done) + { + if (strncmp (accelerator, "<shift>", 7) == 0) + { + accelerator += 7; + *accelerator_mods |= GDK_SHIFT_MASK; + } + else if (strncmp (accelerator, "<alt>", 5) == 0) + { + accelerator += 5; + *accelerator_mods |= GDK_MOD1_MASK; + } + else if (strncmp (accelerator, "<control>", 9) == 0) + { + accelerator += 9; + *accelerator_mods |= GDK_CONTROL_MASK; + } + else + { + done = TRUE; + *accelerator_key = accelerator[0]; + } + } +} diff --git a/gtk/gtkmenufactory.h b/gtk/gtkmenufactory.h new file mode 100644 index 0000000000..d95fdb7751 --- /dev/null +++ b/gtk/gtkmenufactory.h @@ -0,0 +1,88 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MENU_FACTORY_H__ +#define __GTK_MENU_FACTORY_H__ + + +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GtkMenuEntry GtkMenuEntry; +typedef struct _GtkMenuPath GtkMenuPath; +typedef struct _GtkMenuFactory GtkMenuFactory; + +typedef void (*GtkMenuCallback) (GtkWidget *widget, + gpointer user_data); + +struct _GtkMenuEntry +{ + char *path; + char *accelerator; + GtkMenuCallback callback; + gpointer callback_data; + GtkWidget *widget; +}; + +struct _GtkMenuPath +{ + char *path; + GtkWidget *widget; +}; + +struct _GtkMenuFactory +{ + char *path; + GtkMenuFactoryType type; + GtkAcceleratorTable *table; + GtkWidget *widget; + GList *subfactories; +}; + + +GtkMenuFactory* gtk_menu_factory_new (GtkMenuFactoryType type); +void gtk_menu_factory_destroy (GtkMenuFactory *factory); +void gtk_menu_factory_add_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries); +void gtk_menu_factory_add_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path); +void gtk_menu_factory_remove_paths (GtkMenuFactory *factory, + char **paths, + int npaths); +void gtk_menu_factory_remove_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries); +void gtk_menu_factory_remove_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path); +GtkMenuPath* gtk_menu_factory_find (GtkMenuFactory *factory, + const char *path); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_FACTORY_H__ */ diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c new file mode 100644 index 0000000000..f7715fb25e --- /dev/null +++ b/gtk/gtkmenuitem.c @@ -0,0 +1,746 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtksignal.h" + + +#define BORDER_SPACING 3 +#define SELECT_TIMEOUT 20 + +#define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) + + +enum { + ACTIVATE, + LAST_SIGNAL +}; + + +static void gtk_menu_item_class_init (GtkMenuItemClass *klass); +static void gtk_menu_item_init (GtkMenuItem *menu_item); +static void gtk_menu_item_destroy (GtkObject *object); +static void gtk_menu_item_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_menu_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_menu_item_install_accel (GtkWidget *widget, + const gchar *signal_name, + gchar key, + guint8 modifiers); +static void gtk_menu_item_remove_accel (GtkWidget *widget, + const gchar *signal_name); +static void gtk_menu_item_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_menu_item_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_menu_item_enter (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_menu_item_leave (GtkWidget *widget, + GdkEventCrossing *event); +static void gtk_real_menu_item_select (GtkItem *item); +static void gtk_real_menu_item_deselect (GtkItem *item); +static gint gtk_menu_item_select_timeout (gpointer data); +static void gtk_menu_item_position_menu (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data); + +static GtkItemClass *parent_class; +static gint menu_item_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_menu_item_get_type () +{ + static guint menu_item_type = 0; + + if (!menu_item_type) + { + GtkTypeInfo menu_item_info = + { + "GtkMenuItem", + sizeof (GtkMenuItem), + sizeof (GtkMenuItemClass), + (GtkClassInitFunc) gtk_menu_item_class_init, + (GtkObjectInitFunc) gtk_menu_item_init, + (GtkArgFunc) NULL, + }; + + menu_item_type = gtk_type_unique (gtk_item_get_type (), &menu_item_info); + } + + return menu_item_type; +} + +static void +gtk_menu_item_class_init (GtkMenuItemClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + item_class = (GtkItemClass*) klass; + + parent_class = gtk_type_class (gtk_item_get_type ()); + + menu_item_signals[ACTIVATE] = + gtk_signal_new ("activate", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuItemClass, activate), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, menu_item_signals, LAST_SIGNAL); + + object_class->destroy = gtk_menu_item_destroy; + + widget_class->activate_signal = menu_item_signals[ACTIVATE]; + widget_class->size_request = gtk_menu_item_size_request; + widget_class->size_allocate = gtk_menu_item_size_allocate; + widget_class->install_accelerator = gtk_menu_item_install_accel; + widget_class->remove_accelerator = gtk_menu_item_remove_accel; + widget_class->draw = gtk_menu_item_draw; + widget_class->expose_event = gtk_menu_item_expose; + widget_class->enter_notify_event = gtk_menu_item_enter; + widget_class->leave_notify_event = gtk_menu_item_leave; + + item_class->select = gtk_real_menu_item_select; + item_class->deselect = gtk_real_menu_item_deselect; + + klass->activate = NULL; + + klass->toggle_size = 0; + klass->shift_text = "Shft"; + klass->control_text = "Ctl"; + klass->alt_text = "Alt"; + klass->separator_text = "+"; +} + +static void +gtk_menu_item_init (GtkMenuItem *menu_item) +{ + menu_item->submenu = NULL; + menu_item->accelerator_key = 0; + menu_item->accelerator_mods = 0; + menu_item->accelerator_size = 0; + menu_item->accelerator_signal = 0; + menu_item->toggle_size = 0; + menu_item->show_toggle_indicator = FALSE; + menu_item->show_submenu_indicator = FALSE; + menu_item->submenu_direction = GTK_DIRECTION_RIGHT; + menu_item->submenu_placement = GTK_TOP_BOTTOM; + menu_item->right_justify = FALSE; + + menu_item->timer = 0; +} + +GtkWidget* +gtk_menu_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_menu_item_get_type ())); +} + +GtkWidget* +gtk_menu_item_new_with_label (const gchar *label) +{ + GtkWidget *menu_item; + GtkWidget *label_widget; + + menu_item = gtk_menu_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (menu_item), label_widget); + gtk_widget_show (label_widget); + + return menu_item; +} + +static void +gtk_menu_item_destroy (GtkObject *object) +{ + GtkMenuItem *menu_item; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (object)); + + menu_item = GTK_MENU_ITEM (object); + + if (menu_item->submenu) + { + gtk_object_unref (GTK_OBJECT (menu_item->submenu)); + /* gtk_widget_destroy (menu_item->submenu); */ + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +void +gtk_menu_item_set_submenu (GtkMenuItem *menu_item, + GtkWidget *submenu) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (menu_item->submenu) + { + g_return_if_fail (!GTK_WIDGET_VISIBLE (menu_item->submenu)); + gtk_object_unref (GTK_OBJECT (menu_item->submenu)); + } + + menu_item->submenu = submenu; + + if (menu_item->submenu) + gtk_object_ref (GTK_OBJECT (menu_item->submenu)); + + if (GTK_WIDGET (menu_item)->parent) + gtk_widget_queue_resize (GTK_WIDGET (menu_item)); +} + +void +gtk_menu_item_set_placement (GtkMenuItem *menu_item, + GtkSubmenuPlacement placement) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + menu_item->submenu_placement = placement; +} + +void +gtk_menu_item_accelerator_size (GtkMenuItem *menu_item) +{ + char buf[32]; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (menu_item->accelerator_key) + { + gtk_menu_item_accelerator_text (menu_item, buf); + menu_item->accelerator_size = gdk_string_width (GTK_WIDGET (menu_item)->style->font, buf) + 13; + } + else if (menu_item->submenu && menu_item->show_submenu_indicator) + { + menu_item->accelerator_size = 21; + } + else + { + menu_item->accelerator_size = 0; + } +} + +void +gtk_menu_item_accelerator_text (GtkMenuItem *menu_item, + gchar *buffer) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (menu_item->accelerator_key) + { + buffer[0] = '\0'; + if (menu_item->accelerator_mods & GDK_SHIFT_MASK) + { + strcat (buffer, MENU_ITEM_CLASS (menu_item)->shift_text); + strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text); + } + if (menu_item->accelerator_mods & GDK_CONTROL_MASK) + { + strcat (buffer, MENU_ITEM_CLASS (menu_item)->control_text); + strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text); + } + if (menu_item->accelerator_mods & GDK_MOD1_MASK) + { + strcat (buffer, MENU_ITEM_CLASS (menu_item)->alt_text); + strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text); + } + strncat (buffer, &menu_item->accelerator_key, 1); + } +} + +void +gtk_menu_item_configure (GtkMenuItem *menu_item, + gint show_toggle_indicator, + gint show_submenu_indicator) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + menu_item->show_toggle_indicator = (show_toggle_indicator == TRUE); + menu_item->show_submenu_indicator = (show_submenu_indicator == TRUE); +} + +void +gtk_menu_item_select (GtkMenuItem *menu_item) +{ + gtk_item_select (GTK_ITEM (menu_item)); +} + +void +gtk_menu_item_deselect (GtkMenuItem *menu_item) +{ + gtk_item_deselect (GTK_ITEM (menu_item)); +} + +void +gtk_menu_item_activate (GtkMenuItem *menu_item) +{ + gtk_signal_emit (GTK_OBJECT (menu_item), menu_item_signals[ACTIVATE]); +} + + +static void +gtk_menu_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (requisition != NULL); + + bin = GTK_BIN (widget); + + gtk_menu_item_accelerator_size (GTK_MENU_ITEM (widget)); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING) * 2; + requisition->height = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->ythickness) * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_menu_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + bin = GTK_BIN (widget); + + if (bin->child) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING); + child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size; + child_allocation.width -= (GTK_MENU_ITEM (widget)->toggle_size + + GTK_MENU_ITEM (widget)->accelerator_size); + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static gint +gtk_menu_item_install_accel (GtkWidget *widget, + const gchar *signal_name, + gchar key, + guint8 modifiers) +{ + GtkMenuItem *menu_item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (signal_name != NULL, FALSE); + + menu_item = GTK_MENU_ITEM (widget); + + menu_item->accelerator_signal = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (widget)); + if (menu_item->accelerator_signal > 0) + { + menu_item->accelerator_key = key; + menu_item->accelerator_mods = modifiers; + + if (widget->parent) + gtk_widget_queue_resize (widget); + + return TRUE; + } + + return FALSE; +} + +static void +gtk_menu_item_remove_accel (GtkWidget *widget, + const gchar *signal_name) +{ + GtkMenuItem *menu_item; + gint signal_num; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (signal_name != NULL); + + menu_item = GTK_MENU_ITEM (widget); + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (widget)); + if (menu_item->accelerator_signal == signal_num) + { + menu_item->accelerator_key = 0; + menu_item->accelerator_mods = 0; + menu_item->accelerator_signal = 0; + + if (GTK_WIDGET_VISIBLE (widget)) + { + gtk_widget_queue_draw (widget); + GTK_MENU_SHELL (widget->parent)->menu_flag = TRUE; + } + else + gtk_container_need_resize (GTK_CONTAINER (widget->parent)); + } +} + +static void +gtk_menu_item_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkMenuItem *menu_item; + GtkStateType state_type; + GtkShadowType shadow_type; + GdkFont *font; + gint width, height; + gint x, y; + char buf[32]; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + menu_item = GTK_MENU_ITEM (widget); + + state_type = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + gtk_style_set_background (widget->style, widget->window, state_type); + gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); + + x = GTK_CONTAINER (menu_item)->border_width; + y = GTK_CONTAINER (menu_item)->border_width; + width = widget->allocation.width - x * 2; + height = widget->allocation.height - y * 2; + + if ((state_type == GTK_STATE_PRELIGHT) && + (GTK_BIN (menu_item)->child)) + gtk_draw_shadow (widget->style, + widget->window, + GTK_STATE_PRELIGHT, + GTK_SHADOW_OUT, + x, y, width, height); + + if (menu_item->accelerator_key) + { + gtk_menu_item_accelerator_text (menu_item, buf); + + font = widget->style->font; + x = x + width - menu_item->accelerator_size + 13 - 4; + y = y + ((height - (font->ascent + font->descent)) / 2) + font->ascent; + + if (state_type == GTK_STATE_INSENSITIVE) + gdk_draw_string (widget->window, widget->style->font, + widget->style->white_gc, + x + 1, y + 1, buf); + + gdk_draw_string (widget->window, widget->style->font, + widget->style->fg_gc[state_type], + x, y, buf); + } + else if (menu_item->submenu && menu_item->show_submenu_indicator) + { + shadow_type = GTK_SHADOW_OUT; + if (state_type == GTK_STATE_PRELIGHT) + shadow_type = GTK_SHADOW_IN; + + gtk_draw_arrow (widget->style, widget->window, + state_type, shadow_type, GTK_ARROW_RIGHT, FALSE, + x + width - 15, y + height / 2 - 5, 10, 10); + } + else if (!GTK_BIN (menu_item)->child) + { + gtk_draw_hline (widget->style, widget->window, GTK_STATE_NORMAL, + 0, widget->allocation.width, 0); + } + } +} + +static void +gtk_menu_item_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_item_paint (widget, area); + + bin = GTK_BIN (widget); + + if (bin->child) + { + if (gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } + } +} + +static gint +gtk_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_item_paint (widget, &event->area); + + bin = GTK_BIN (widget); + + if (bin->child) + { + child_event = *event; + + if (GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static gint +gtk_menu_item_enter (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return gtk_widget_event (widget->parent, (GdkEvent*) event); +} + +static gint +gtk_menu_item_leave (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return gtk_widget_event (widget->parent, (GdkEvent*) event); +} + +static void +gtk_real_menu_item_select (GtkItem *item) +{ + GtkMenuItem *menu_item; + + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (item)); + + menu_item = GTK_MENU_ITEM (item); + + if (menu_item->submenu && !GTK_WIDGET_VISIBLE (menu_item->submenu)) + menu_item->timer = gtk_timeout_add (SELECT_TIMEOUT, gtk_menu_item_select_timeout, menu_item); + + gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT); + gtk_widget_draw (GTK_WIDGET (menu_item), NULL); +} + +static void +gtk_real_menu_item_deselect (GtkItem *item) +{ + GtkMenuItem *menu_item; + + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (item)); + + menu_item = GTK_MENU_ITEM (item); + + if (menu_item->submenu) + { + if (menu_item->timer) + gtk_timeout_remove (menu_item->timer); + else + gtk_menu_popdown (GTK_MENU (menu_item->submenu)); + } + + gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL); + gtk_widget_draw (GTK_WIDGET (menu_item), NULL); +} + +static gint +gtk_menu_item_select_timeout (gpointer data) +{ + GtkMenuItem *menu_item; + + menu_item = GTK_MENU_ITEM (data); + menu_item->timer = 0; + + gtk_menu_popup (GTK_MENU (menu_item->submenu), + GTK_WIDGET (menu_item)->parent, + GTK_WIDGET (menu_item), + gtk_menu_item_position_menu, + menu_item, + GTK_MENU_SHELL (GTK_WIDGET (menu_item)->parent)->button, + 0); + + return FALSE; +} + +static void +gtk_menu_item_position_menu (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data) +{ + GtkMenuItem *menu_item; + GtkMenuItem *parent_menu_item; + gint screen_width; + gint screen_height; + gint twidth, theight; + gint tx, ty; + + g_return_if_fail (menu != NULL); + g_return_if_fail (x != NULL); + g_return_if_fail (y != NULL); + + menu_item = GTK_MENU_ITEM (user_data); + + twidth = GTK_WIDGET (menu)->requisition.width; + theight = GTK_WIDGET (menu)->requisition.height; + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + g_return_if_fail (gdk_window_get_origin (GTK_WIDGET (menu_item)->window, &tx, &ty)); + + switch (menu_item->submenu_placement) + { + case GTK_TOP_BOTTOM: + if ((ty + GTK_WIDGET (menu_item)->allocation.height + theight) <= screen_height) + ty += GTK_WIDGET (menu_item)->allocation.height; + else if ((ty - theight) >= 0) + ty -= theight; + else + ty += GTK_WIDGET (menu_item)->allocation.height; + + if ((tx + twidth) > screen_width) + { + tx -= ((tx + twidth) - screen_width); + if (tx < 0) + tx = 0; + } + break; + + case GTK_LEFT_RIGHT: + menu_item->submenu_direction = GTK_DIRECTION_RIGHT; + parent_menu_item = GTK_MENU_ITEM (GTK_MENU (GTK_WIDGET (menu_item)->parent)->parent_menu_item); + if (parent_menu_item) + menu_item->submenu_direction = parent_menu_item->submenu_direction; + + switch (menu_item->submenu_direction) + { + case GTK_DIRECTION_LEFT: + if ((tx - twidth) >= 0) + tx -= twidth; + else + { + menu_item->submenu_direction = GTK_DIRECTION_RIGHT; + tx += GTK_WIDGET (menu_item)->allocation.width - 5; + } + break; + + case GTK_DIRECTION_RIGHT: + if ((tx + GTK_WIDGET (menu_item)->allocation.width + twidth - 5) <= screen_width) + tx += GTK_WIDGET (menu_item)->allocation.width - 5; + else + { + menu_item->submenu_direction = GTK_DIRECTION_LEFT; + tx -= twidth; + } + break; + } + + if ((ty + GTK_WIDGET (menu_item)->allocation.height / 4 + theight) <= screen_height) + ty += GTK_WIDGET (menu_item)->allocation.height / 4; + else + { + ty -= ((ty + theight) - screen_height); + if (ty < 0) + ty = 0; + } + break; + } + + *x = tx; + *y = ty; +} + +void +gtk_menu_item_right_justify(GtkMenuItem *menuitem) +{ + g_return_if_fail (menuitem != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menuitem)); + + menuitem->right_justify = 1; +} diff --git a/gtk/gtkmenuitem.h b/gtk/gtkmenuitem.h new file mode 100644 index 0000000000..da51681090 --- /dev/null +++ b/gtk/gtkmenuitem.h @@ -0,0 +1,98 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MENU_ITEM_H__ +#define __GTK_MENU_ITEM_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkitem.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU_ITEM(obj) GTK_CHECK_CAST (obj, gtk_menu_item_get_type (), GtkMenuItem) +#define GTK_MENU_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_item_get_type (), GtkMenuItemClass) +#define GTK_IS_MENU_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_menu_item_get_type ()) + + +typedef struct _GtkMenuItem GtkMenuItem; +typedef struct _GtkMenuItemClass GtkMenuItemClass; + +struct _GtkMenuItem +{ + GtkItem item; + + GtkWidget *submenu; + + gint accelerator_signal; + gchar accelerator_key; + guint8 accelerator_mods; + guint16 accelerator_size; + guint16 toggle_size; + + guint show_toggle_indicator : 1; + guint show_submenu_indicator : 1; + guint submenu_placement : 1; + guint submenu_direction : 1; + guint right_justify: 1; + gint timer; +}; + +struct _GtkMenuItemClass +{ + GtkItemClass parent_class; + + gint toggle_size; + + gchar *shift_text; + gchar *control_text; + gchar *alt_text; + gchar *separator_text; + + void (* activate) (GtkMenuItem *menu_item); +}; + + +guint gtk_menu_item_get_type (void); +GtkWidget* gtk_menu_item_new (void); +GtkWidget* gtk_menu_item_new_with_label (const gchar *label); +void gtk_menu_item_set_submenu (GtkMenuItem *menu_item, + GtkWidget *submenu); +void gtk_menu_item_set_placement (GtkMenuItem *menu_item, + GtkSubmenuPlacement placement); +void gtk_menu_item_accelerator_size (GtkMenuItem *menu_item); +void gtk_menu_item_accelerator_text (GtkMenuItem *menu_item, + gchar *buffer); +void gtk_menu_item_configure (GtkMenuItem *menu_item, + gint show_toggle_indicator, + gint show_submenu_indicator); +void gtk_menu_item_select (GtkMenuItem *menu_item); +void gtk_menu_item_deselect (GtkMenuItem *menu_item); +void gtk_menu_item_activate (GtkMenuItem *menu_item); +void gtk_menu_item_right_justify (GtkMenuItem *menu_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_ITEM_H__ */ diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c new file mode 100644 index 0000000000..6d3de5a7f8 --- /dev/null +++ b/gtk/gtkmenushell.c @@ -0,0 +1,633 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkmain.h" +#include "gtkmenuitem.h" +#include "gtkmenushell.h" +#include "gtksignal.h" + + +#define MENU_SHELL_TIMEOUT 500 +#define MENU_SHELL_CLASS(w) GTK_MENU_SHELL_CLASS (GTK_OBJECT (w)->klass) + + +enum { + DEACTIVATE, + LAST_SIGNAL +}; + + +static void gtk_menu_shell_class_init (GtkMenuShellClass *klass); +static void gtk_menu_shell_init (GtkMenuShell *menu_shell); +static void gtk_menu_shell_destroy (GtkObject *object); +static void gtk_menu_shell_map (GtkWidget *widget); +static void gtk_menu_shell_realize (GtkWidget *widget); +static gint gtk_menu_shell_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_menu_shell_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_menu_shell_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_menu_shell_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static void gtk_menu_shell_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_menu_shell_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_menu_shell_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell); +static gint gtk_menu_shell_is_item (GtkMenuShell *menu_shell, + GtkWidget *child); + + +static GtkContainerClass *parent_class = NULL; +static gint menu_shell_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_menu_shell_get_type () +{ + static guint menu_shell_type = 0; + + if (!menu_shell_type) + { + GtkTypeInfo menu_shell_info = + { + "GtkMenuShell", + sizeof (GtkMenuShell), + sizeof (GtkMenuShellClass), + (GtkClassInitFunc) gtk_menu_shell_class_init, + (GtkObjectInitFunc) gtk_menu_shell_init, + (GtkArgFunc) NULL, + }; + + menu_shell_type = gtk_type_unique (gtk_container_get_type (), &menu_shell_info); + } + + return menu_shell_type; +} + +static void +gtk_menu_shell_class_init (GtkMenuShellClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + menu_shell_signals[DEACTIVATE] = + gtk_signal_new ("deactivate", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuShellClass, deactivate), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, menu_shell_signals, LAST_SIGNAL); + + object_class->destroy = gtk_menu_shell_destroy; + + widget_class->map = gtk_menu_shell_map; + widget_class->realize = gtk_menu_shell_realize; + widget_class->button_press_event = gtk_menu_shell_button_press; + widget_class->button_release_event = gtk_menu_shell_button_release; + widget_class->enter_notify_event = gtk_menu_shell_enter_notify; + widget_class->leave_notify_event = gtk_menu_shell_leave_notify; + + container_class->add = gtk_menu_shell_add; + container_class->remove = gtk_menu_shell_remove; + container_class->foreach = gtk_menu_shell_foreach; + + klass->submenu_placement = GTK_TOP_BOTTOM; + klass->deactivate = gtk_real_menu_shell_deactivate; +} + +static void +gtk_menu_shell_init (GtkMenuShell *menu_shell) +{ + menu_shell->children = NULL; + menu_shell->active_menu_item = NULL; + menu_shell->parent_menu_shell = NULL; + menu_shell->active = FALSE; + menu_shell->have_grab = FALSE; + menu_shell->have_xgrab = FALSE; + menu_shell->ignore_leave = FALSE; + menu_shell->button = 0; + menu_shell->menu_flag = 0; + menu_shell->activate_time = 0; +} + +void +gtk_menu_shell_append (GtkMenuShell *menu_shell, + GtkWidget *child) +{ + gtk_menu_shell_insert (menu_shell, child, -1); +} + +void +gtk_menu_shell_prepend (GtkMenuShell *menu_shell, + GtkWidget *child) +{ + gtk_menu_shell_insert (menu_shell, child, 0); +} + +void +gtk_menu_shell_insert (GtkMenuShell *menu_shell, + GtkWidget *child, + gint position) +{ + GList *tmp_list; + GList *new_list; + gint nchildren; + + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + g_return_if_fail (child != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (child)); + + gtk_widget_set_parent (child, GTK_WIDGET (menu_shell)); + + if (GTK_WIDGET_VISIBLE (child->parent)) + { + if (GTK_WIDGET_REALIZED (child->parent) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (child->parent) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + nchildren = g_list_length (menu_shell->children); + if ((position < 0) || (position > nchildren)) + position = nchildren; + + if (position == nchildren) + { + menu_shell->children = g_list_append (menu_shell->children, child); + } + else + { + tmp_list = g_list_nth (menu_shell->children, position); + new_list = g_list_alloc (); + new_list->data = child; + + if (tmp_list->prev) + tmp_list->prev->next = new_list; + new_list->next = tmp_list; + new_list->prev = tmp_list->prev; + tmp_list->prev = new_list; + + if (tmp_list == menu_shell->children) + menu_shell->children = new_list; + } + + if (GTK_WIDGET_VISIBLE (menu_shell)) + gtk_widget_queue_resize (GTK_WIDGET (menu_shell)); +} + +void +gtk_menu_shell_deactivate (GtkMenuShell *menu_shell) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + + gtk_signal_emit (GTK_OBJECT (menu_shell), menu_shell_signals[DEACTIVATE]); +} + +static void +gtk_menu_shell_destroy (GtkObject *object) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (object)); + + menu_shell = GTK_MENU_SHELL (object); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + child->parent = NULL; + gtk_object_unref (GTK_OBJECT (child)); + gtk_widget_destroy (child); + } + + g_list_free (menu_shell->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_menu_shell_map (GtkWidget *widget) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (widget)); + + menu_shell = GTK_MENU_SHELL (widget); + GTK_WIDGET_SET_FLAGS (menu_shell, GTK_MAPPED); + gdk_window_show (widget->window); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } +} + +static void +gtk_menu_shell_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static gint +gtk_menu_shell_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *menu_item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->type != GDK_BUTTON_PRESS) + return FALSE; + + menu_shell = GTK_MENU_SHELL (widget); + + if (menu_shell->parent_menu_shell) + { + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + } + else if (!menu_shell->active || !menu_shell->button) + { + if (!menu_shell->active) + { + gtk_grab_add (GTK_WIDGET (widget)); + menu_shell->have_grab = TRUE; + } + menu_shell->active = TRUE; + + menu_item = gtk_get_event_widget ((GdkEvent*) event); + if (GTK_IS_MENU_ITEM (menu_item) && gtk_menu_shell_is_item (menu_shell, menu_item)) + { + if ((menu_item->parent == widget) && + (menu_item != menu_shell->active_menu_item)) + { + if (menu_shell->active_menu_item) + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + + menu_shell->active_menu_item = menu_item; + gtk_menu_item_set_placement (GTK_MENU_ITEM (menu_shell->active_menu_item), + MENU_SHELL_CLASS (menu_shell)->submenu_placement); + gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item)); + } + } + else if (!menu_shell->button) + { + gtk_menu_shell_deactivate (menu_shell); + } + + if (menu_shell->active) + menu_shell->button = event->button; + } + else + { + widget = gtk_get_event_widget ((GdkEvent*) event); + if (widget == GTK_WIDGET (menu_shell)) + gtk_menu_shell_deactivate (menu_shell); + } + + return TRUE; +} + +static gint +gtk_menu_shell_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *menu_item; + gint deactivate; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + menu_shell = GTK_MENU_SHELL (widget); + if (menu_shell->active) + { + if (menu_shell->button && (event->button != menu_shell->button)) + { + menu_shell->button = 0; + if (menu_shell->parent_menu_shell) + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + return TRUE; + } + + menu_shell->button = 0; + menu_item = gtk_get_event_widget ((GdkEvent*) event); + deactivate = TRUE; + + if ((event->time - menu_shell->activate_time) > MENU_SHELL_TIMEOUT) + { + if (menu_shell->active_menu_item == menu_item) + { + if (GTK_MENU_ITEM (menu_item)->submenu == NULL) + { + gtk_menu_shell_deactivate (menu_shell); + gtk_widget_activate (menu_item); + return TRUE; + } + } + else if (menu_shell->parent_menu_shell) + { + menu_shell->active = TRUE; + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + return TRUE; + } + } + else + deactivate = FALSE; + + if ((!deactivate || (menu_shell->active_menu_item == menu_item)) && + (gdk_pointer_grab (widget->window, TRUE, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK, + NULL, NULL, event->time) == 0)) + { + deactivate = FALSE; + menu_shell->have_xgrab = TRUE; + menu_shell->ignore_leave = TRUE; + } + else + deactivate = TRUE; + + if (deactivate) + gtk_menu_shell_deactivate (menu_shell); + } + + return TRUE; +} + +static gint +gtk_menu_shell_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *menu_item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + menu_shell = GTK_MENU_SHELL (widget); + if (menu_shell->active) + { + menu_item = gtk_get_event_widget ((GdkEvent*) event); + + if (!GTK_WIDGET_IS_SENSITIVE (menu_item)) + return TRUE; + + if ((menu_item->parent == widget) && + (menu_shell->active_menu_item != menu_item) && + GTK_IS_MENU_ITEM (menu_item)) + { + if ((event->detail != GDK_NOTIFY_INFERIOR) && + (GTK_WIDGET_STATE (menu_item) != GTK_STATE_PRELIGHT)) + { + if (menu_shell->active_menu_item) + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + + menu_shell->active_menu_item = menu_item; + gtk_menu_item_set_placement (GTK_MENU_ITEM (menu_shell->active_menu_item), + MENU_SHELL_CLASS (menu_shell)->submenu_placement); + gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item)); + } + } + else if (menu_shell->parent_menu_shell) + { + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + } + } + + return TRUE; +} + +static gint +gtk_menu_shell_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkMenuShell *menu_shell; + GtkMenuItem *menu_item; + GtkWidget *event_widget; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget)) + { + menu_shell = GTK_MENU_SHELL (widget); + event_widget = gtk_get_event_widget ((GdkEvent*) event); + + if (!GTK_IS_MENU_ITEM (event_widget)) + return TRUE; + + menu_item = GTK_MENU_ITEM (event_widget); + + if (!GTK_WIDGET_IS_SENSITIVE (menu_item)) + return TRUE; + + if (menu_shell->ignore_leave) + { + menu_shell->ignore_leave = FALSE; + return TRUE; + } + + if ((menu_shell->active_menu_item == event_widget) && + (menu_item->submenu == NULL)) + { + if ((event->detail != GDK_NOTIFY_INFERIOR) && + (GTK_WIDGET_STATE (menu_item) != GTK_STATE_NORMAL)) + { + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + menu_shell->active_menu_item = NULL; + } + } + else if (menu_shell->parent_menu_shell) + { + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + } + } + + return TRUE; +} + +static void +gtk_menu_shell_add (GtkContainer *container, + GtkWidget *widget) +{ + gtk_menu_shell_append (GTK_MENU_SHELL (container), widget); +} + +static void +gtk_menu_shell_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkMenuShell *menu_shell; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (container)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + + gtk_widget_unparent (widget); + + menu_shell = GTK_MENU_SHELL (container); + menu_shell->children = g_list_remove (menu_shell->children, widget); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); +} + +static void +gtk_menu_shell_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (container)); + g_return_if_fail (callback != NULL); + + menu_shell = GTK_MENU_SHELL (container); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child, callback_data); + } +} + + +static void +gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + + if (menu_shell->active) + { + menu_shell->button = 0; + menu_shell->active = FALSE; + + if (menu_shell->active_menu_item) + { + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + menu_shell->active_menu_item = NULL; + } + + if (menu_shell->have_grab) + { + menu_shell->have_grab = FALSE; + gtk_grab_remove (GTK_WIDGET (menu_shell)); + } + if (menu_shell->have_xgrab) + { + menu_shell->have_xgrab = FALSE; + gdk_pointer_ungrab (GDK_CURRENT_TIME); + } + } +} + +static gint +gtk_menu_shell_is_item (GtkMenuShell *menu_shell, + GtkWidget *child) +{ + GtkMenuShell *parent; + + g_return_val_if_fail (menu_shell != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE); + g_return_val_if_fail (child != NULL, FALSE); + + parent = GTK_MENU_SHELL (child->parent); + while (parent && GTK_IS_MENU_SHELL (parent)) + { + if (parent == menu_shell) + return TRUE; + parent = GTK_MENU_SHELL (parent->parent_menu_shell); + } + + return FALSE; +} diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h new file mode 100644 index 0000000000..a468631ed2 --- /dev/null +++ b/gtk/gtkmenushell.h @@ -0,0 +1,83 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MENU_SHELL_H__ +#define __GTK_MENU_SHELL_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU_SHELL(obj) GTK_CHECK_CAST (obj, gtk_menu_shell_get_type (), GtkMenuShell) +#define GTK_MENU_SHELL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_shell_get_type (), GtkMenuShellClass) +#define GTK_IS_MENU_SHELL(obj) GTK_CHECK_TYPE (obj, gtk_menu_shell_get_type ()) + + +typedef struct _GtkMenuShell GtkMenuShell; +typedef struct _GtkMenuShellClass GtkMenuShellClass; + +struct _GtkMenuShell +{ + GtkContainer container; + + GList *children; + GtkWidget *active_menu_item; + GtkWidget *parent_menu_shell; + + guint active : 1; + guint have_grab : 1; + guint have_xgrab : 1; + guint button : 2; + guint ignore_leave : 1; + guint menu_flag : 1; + + guint32 activate_time; +}; + +struct _GtkMenuShellClass +{ + GtkContainerClass parent_class; + + guint submenu_placement : 1; + + void (*deactivate) (GtkMenuShell *menu_shell); +}; + + +guint gtk_menu_shell_get_type (void); +void gtk_menu_shell_append (GtkMenuShell *menu_shell, + GtkWidget *child); +void gtk_menu_shell_prepend (GtkMenuShell *menu_shell, + GtkWidget *child); +void gtk_menu_shell_insert (GtkMenuShell *menu_shell, + GtkWidget *child, + gint position); +void gtk_menu_shell_deactivate (GtkMenuShell *menu_shell); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_SHELL_H__ */ diff --git a/gtk/gtkmisc.c b/gtk/gtkmisc.c new file mode 100644 index 0000000000..0ef8f0731c --- /dev/null +++ b/gtk/gtkmisc.c @@ -0,0 +1,181 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkcontainer.h" +#include "gtkmisc.h" + + +static void gtk_misc_class_init (GtkMiscClass *klass); +static void gtk_misc_init (GtkMisc *misc); +static void gtk_misc_realize (GtkWidget *widget); + + +guint +gtk_misc_get_type () +{ + static guint misc_type = 0; + + if (!misc_type) + { + GtkTypeInfo misc_info = + { + "GtkMisc", + sizeof (GtkMisc), + sizeof (GtkMiscClass), + (GtkClassInitFunc) gtk_misc_class_init, + (GtkObjectInitFunc) gtk_misc_init, + (GtkArgFunc) NULL, + }; + + misc_type = gtk_type_unique (gtk_widget_get_type (), &misc_info); + } + + return misc_type; +} + +static void +gtk_misc_class_init (GtkMiscClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_misc_realize; +} + +static void +gtk_misc_init (GtkMisc *misc) +{ + GTK_WIDGET_SET_FLAGS (misc, GTK_BASIC); + + misc->xalign = 0.5; + misc->yalign = 0.5; + misc->xpad = 0; + misc->ypad = 0; +} + +void +gtk_misc_set_alignment (GtkMisc *misc, + gfloat xalign, + gfloat yalign) +{ + g_return_if_fail (misc != NULL); + g_return_if_fail (GTK_IS_MISC (misc)); + + if (xalign < 0.0) + xalign = 0.0; + else if (xalign > 1.0) + xalign = 1.0; + + if (yalign < 0.0) + yalign = 0.0; + else if (yalign > 1.0) + yalign = 1.0; + + if ((xalign != misc->xalign) || (yalign != misc->yalign)) + { + misc->xalign = xalign; + misc->yalign = yalign; + + /* clear the area that was allocated before the change + */ + if (GTK_WIDGET_VISIBLE (misc)) + { + GtkWidget *widget; + + widget = GTK_WIDGET (misc); + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + } + + gtk_widget_queue_draw (GTK_WIDGET (misc)); + } +} + +void +gtk_misc_set_padding (GtkMisc *misc, + gint xpad, + gint ypad) +{ + GtkRequisition *requisition; + + g_return_if_fail (misc != NULL); + g_return_if_fail (GTK_IS_MISC (misc)); + + if (xpad < 0) + xpad = 0; + if (ypad < 0) + ypad = 0; + + if ((xpad != misc->xpad) || (ypad != misc->ypad)) + { + requisition = &(GTK_WIDGET (misc)->requisition); + requisition->width -= misc->xpad * 2; + requisition->height -= misc->ypad * 2; + + misc->xpad = xpad; + misc->ypad = ypad; + + requisition->width += misc->xpad * 2; + requisition->height += misc->ypad * 2; + + if (GTK_WIDGET (misc)->parent && GTK_WIDGET_VISIBLE (misc)) + gtk_widget_queue_resize (GTK_WIDGET (misc)); + } +} + +static void +gtk_misc_realize (GtkWidget *widget) +{ + GtkMisc *misc; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MISC (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + misc = GTK_MISC (widget); + + if (GTK_WIDGET_NO_WINDOW (widget)) + { + widget->window = widget->parent->window; + widget->style = gtk_style_attach (widget->style, widget->window); + } + else + { + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gdk_window_set_back_pixmap (widget->window, NULL, TRUE); + } +} diff --git a/gtk/gtkmisc.h b/gtk/gtkmisc.h new file mode 100644 index 0000000000..1bc9cbb93e --- /dev/null +++ b/gtk/gtkmisc.h @@ -0,0 +1,70 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MISC_H__ +#define __GTK_MISC_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MISC(obj) GTK_CHECK_CAST (obj, gtk_misc_get_type (), GtkMisc) +#define GTK_MISC_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_misc_get_type (), GtkMiscClass) +#define GTK_IS_MISC(obj) GTK_CHECK_TYPE (obj, gtk_misc_get_type ()) + + +typedef struct _GtkMisc GtkMisc; +typedef struct _GtkMiscClass GtkMiscClass; + +struct _GtkMisc +{ + GtkWidget widget; + + gfloat xalign; + gfloat yalign; + + guint16 xpad; + guint16 ypad; +}; + +struct _GtkMiscClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_misc_get_type (void); +void gtk_misc_set_alignment (GtkMisc *misc, + gfloat xalign, + gfloat yalign); +void gtk_misc_set_padding (GtkMisc *misc, + gint xpad, + gint ypad); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LABEL_H__ */ diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c new file mode 100644 index 0000000000..0b3115034e --- /dev/null +++ b/gtk/gtknotebook.c @@ -0,0 +1,1303 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtknotebook.h" + + +#define CHILD_SPACING 2 +#define TAB_OVERLAP 2 +#define TAB_CURVATURE 1 + + +static void gtk_notebook_class_init (GtkNotebookClass *klass); +static void gtk_notebook_init (GtkNotebook *notebook); +static void gtk_notebook_destroy (GtkObject *object); +static void gtk_notebook_map (GtkWidget *widget); +static void gtk_notebook_unmap (GtkWidget *widget); +static void gtk_notebook_realize (GtkWidget *widget); +static void gtk_notebook_unrealize (GtkWidget *widget); +static void gtk_notebook_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_notebook_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_notebook_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_notebook_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_notebook_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_notebook_button_press (GtkWidget *widget, + GdkEventButton *event); +static void gtk_notebook_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_notebook_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_notebook_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_notebook_switch_page (GtkNotebook *notebook, + GtkNotebookPage *page); +static void gtk_notebook_draw_tab (GtkNotebook *notebook, + GtkNotebookPage *page, + GdkRectangle *area); +static void gtk_notebook_pages_allocate (GtkNotebook *notebook, + GtkAllocation *allocation); +static void gtk_notebook_page_allocate (GtkNotebook *notebook, + GtkNotebookPage *page, + GtkAllocation *allocation); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_notebook_get_type () +{ + static guint notebook_type = 0; + + if (!notebook_type) + { + GtkTypeInfo notebook_info = + { + "GtkNotebook", + sizeof (GtkNotebook), + sizeof (GtkNotebookClass), + (GtkClassInitFunc) gtk_notebook_class_init, + (GtkObjectInitFunc) gtk_notebook_init, + (GtkArgFunc) NULL, + }; + + notebook_type = gtk_type_unique (gtk_container_get_type (), ¬ebook_info); + } + + return notebook_type; +} + +static void +gtk_notebook_class_init (GtkNotebookClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_notebook_destroy; + + widget_class->map = gtk_notebook_map; + widget_class->unmap = gtk_notebook_unmap; + widget_class->realize = gtk_notebook_realize; + widget_class->unrealize = gtk_notebook_unrealize; + widget_class->size_request = gtk_notebook_size_request; + widget_class->size_allocate = gtk_notebook_size_allocate; + widget_class->draw = gtk_notebook_draw; + widget_class->expose_event = gtk_notebook_expose; + widget_class->button_press_event = gtk_notebook_button_press; + + container_class->add = gtk_notebook_add; + container_class->remove = gtk_notebook_remove; + container_class->foreach = gtk_notebook_foreach; +} + +static void +gtk_notebook_init (GtkNotebook *notebook) +{ + notebook->cur_page = NULL; + notebook->children = NULL; + notebook->show_tabs = TRUE; + notebook->show_border = TRUE; + notebook->tab_pos = GTK_POS_TOP; +} + +GtkWidget* +gtk_notebook_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_notebook_get_type ())); +} + +void +gtk_notebook_append_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + gtk_notebook_insert_page (notebook, child, tab_label, -1); +} + +void +gtk_notebook_prepend_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + gtk_notebook_insert_page (notebook, child, tab_label, 0); +} + +void +gtk_notebook_insert_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label, + gint position) +{ + GtkNotebookPage *page; + gint nchildren; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + page = g_new (GtkNotebookPage, 1); + page->child = child; + page->tab_label = tab_label; + page->requisition.width = 0; + page->requisition.height = 0; + page->allocation.x = 0; + page->allocation.y = 0; + page->allocation.width = 0; + page->allocation.height = 0; + + nchildren = g_list_length (notebook->children); + if ((position < 0) || (position > nchildren)) + position = nchildren; + + notebook->children = g_list_insert (notebook->children, page, position); + + if (!notebook->cur_page) + notebook->cur_page = page; + + gtk_widget_show (tab_label); + gtk_widget_set_parent (child, GTK_WIDGET (notebook)); + gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook)); + + if (GTK_WIDGET_VISIBLE (notebook)) + { + if (GTK_WIDGET_REALIZED (notebook) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (notebook) && + !GTK_WIDGET_MAPPED (child) && notebook->cur_page == page) + gtk_widget_map (child); + + if (GTK_WIDGET_REALIZED (notebook) && + !GTK_WIDGET_REALIZED (tab_label)) + gtk_widget_realize (tab_label); + + if (GTK_WIDGET_MAPPED (notebook) && + !GTK_WIDGET_MAPPED (tab_label)) + gtk_widget_map (tab_label); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (child); +} + +void +gtk_notebook_remove_page (GtkNotebook *notebook, + gint page_num) +{ + GtkNotebookPage *page; + GList *tmp_list; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + tmp_list = g_list_nth (notebook->children, page_num); + if (tmp_list) + { + page = tmp_list->data; + + if (notebook->cur_page == page) + gtk_notebook_prev_page (notebook); + if (notebook->cur_page == page) + notebook->cur_page = NULL; + + notebook->children = g_list_remove_link (notebook->children, tmp_list); + g_list_free (tmp_list); + g_free (page); + } +} + +gint +gtk_notebook_current_page (GtkNotebook *notebook) +{ + GList *children; + gint cur_page; + + g_return_val_if_fail (notebook != NULL, -1); + g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1); + + if (notebook->cur_page) + { + cur_page = 0; + children = notebook->children; + + while (children) + { + if (children->data == notebook->cur_page) + break; + children = children->next; + cur_page += 1; + } + + if (!children) + cur_page = -1; + } + else + { + cur_page = -1; + } + + return cur_page; +} + +void +gtk_notebook_set_page (GtkNotebook *notebook, + gint page_num) +{ + GtkNotebookPage *page; + GList *tmp_list; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + tmp_list = g_list_nth (notebook->children, page_num); + if (tmp_list) + { + page = tmp_list->data; + gtk_notebook_switch_page (notebook, page); + } +} + +void +gtk_notebook_next_page (GtkNotebook *notebook) +{ + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + children = notebook->children; + while (children) + { + page = children->data; + + if (notebook->cur_page == page) + { + children = children->next; + if (!children) + children = notebook->children; + page = children->data; + + gtk_notebook_switch_page (notebook, page); + } + + children = children->next; + } +} + +void +gtk_notebook_prev_page (GtkNotebook *notebook) +{ + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + children = notebook->children; + while (children) + { + page = children->data; + + if (notebook->cur_page == page) + { + children = children->prev; + if (!children) + children = g_list_last (notebook->children); + page = children->data; + + gtk_notebook_switch_page (notebook, page); + } + + children = children->next; + } +} + +void +gtk_notebook_set_tab_pos (GtkNotebook *notebook, + GtkPositionType pos) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->tab_pos != pos) + { + notebook->tab_pos = pos; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +void +gtk_notebook_set_show_tabs (GtkNotebook *notebook, + gint show_tabs) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->show_tabs != show_tabs) + { + notebook->show_tabs = show_tabs; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +void +gtk_notebook_set_show_border (GtkNotebook *notebook, + gint show_border) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->show_border != show_border) + { + notebook->show_border = show_border; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +static void +gtk_notebook_destroy (GtkObject *object) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (object)); + + notebook = GTK_NOTEBOOK (object); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + page->child->parent = NULL; + page->tab_label->parent = NULL; + + gtk_object_unref (GTK_OBJECT (page->child)); + gtk_object_unref (GTK_OBJECT (page->tab_label)); + + gtk_widget_destroy (page->child); + gtk_widget_destroy (page->tab_label); + + g_free (page); + } + + g_list_free (notebook->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_notebook_map (GtkWidget *widget) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + notebook = GTK_NOTEBOOK (widget); + + if (notebook->cur_page && + GTK_WIDGET_VISIBLE (notebook->cur_page->child) && + !GTK_WIDGET_MAPPED (notebook->cur_page->child)) + gtk_widget_map (notebook->cur_page->child); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child) && + !GTK_WIDGET_MAPPED (page->tab_label)) + gtk_widget_map (page->tab_label); + } +} + +static void +gtk_notebook_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_notebook_realize (GtkWidget *widget) +{ + GtkNotebook *notebook; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + notebook = GTK_NOTEBOOK (widget); + GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, notebook); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_notebook_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + widget->window = NULL; +} + +static void +gtk_notebook_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + gint tab_width; + gint tab_height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (requisition != NULL); + + notebook = GTK_NOTEBOOK (widget); + widget->requisition.width = 0; + widget->requisition.height = 0; + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + gtk_widget_size_request (page->child, &page->child->requisition); + + widget->requisition.width = MAX (widget->requisition.width, + page->child->requisition.width); + widget->requisition.height = MAX (widget->requisition.height, + page->child->requisition.height); + } + } + + widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2; + widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2; + + if (notebook->show_tabs) + { + widget->requisition.width += GTK_WIDGET (widget)->style->klass->xthickness * 2; + widget->requisition.height += GTK_WIDGET (widget)->style->klass->ythickness * 2; + + tab_width = 0; + tab_height = 0; + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + gtk_widget_size_request (page->tab_label, &page->tab_label->requisition); + + page->requisition.width = (page->tab_label->requisition.width + + (GTK_WIDGET (widget)->style->klass->xthickness + + CHILD_SPACING) * 2); + page->requisition.height = (page->tab_label->requisition.height + + (GTK_WIDGET (widget)->style->klass->ythickness + + CHILD_SPACING) * 2); + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + page->requisition.width -= TAB_OVERLAP; + page->requisition.height -= GTK_WIDGET (widget)->style->klass->ythickness; + + tab_width += page->requisition.width; + tab_height = MAX (tab_height, page->requisition.height); + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + page->requisition.width -= GTK_WIDGET (widget)->style->klass->xthickness; + page->requisition.height -= TAB_OVERLAP; + + tab_width = MAX (tab_width, page->requisition.width); + tab_height += page->requisition.height; + break; + } + } + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + if ((notebook->tab_pos == GTK_POS_TOP) || + (notebook->tab_pos == GTK_POS_BOTTOM)) + page->requisition.height = tab_height; + else + page->requisition.width = tab_width; + } + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + tab_width += GTK_WIDGET (widget)->style->klass->xthickness; + widget->requisition.width = MAX (widget->requisition.width, tab_width); + widget->requisition.height += tab_height; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + tab_height += GTK_WIDGET (widget)->style->klass->ythickness; + widget->requisition.width += tab_width; + widget->requisition.height = MAX (widget->requisition.height, tab_height); + break; + } + } + else if (notebook->show_border) + { + widget->requisition.width += GTK_WIDGET (widget)->style->klass->xthickness * 2; + widget->requisition.height += GTK_WIDGET (widget)->style->klass->ythickness * 2; + } +} + +static void +gtk_notebook_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GtkAllocation child_allocation; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + notebook = GTK_NOTEBOOK (widget); + if (notebook->children) + { + child_allocation.x = GTK_CONTAINER (widget)->border_width; + child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + + if (notebook->show_tabs || notebook->show_border) + { + child_allocation.x += GTK_WIDGET (widget)->style->klass->xthickness; + child_allocation.y += GTK_WIDGET (widget)->style->klass->ythickness; + child_allocation.width -= GTK_WIDGET (widget)->style->klass->xthickness * 2; + child_allocation.height -= GTK_WIDGET (widget)->style->klass->ythickness * 2; + + if (notebook->show_tabs && notebook->children) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + child_allocation.y += notebook->cur_page->requisition.height; + case GTK_POS_BOTTOM: + child_allocation.height -= notebook->cur_page->requisition.height; + break; + case GTK_POS_LEFT: + child_allocation.x += notebook->cur_page->requisition.width; + case GTK_POS_RIGHT: + child_allocation.width -= notebook->cur_page->requisition.width; + break; + } + } + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + gtk_widget_size_allocate (page->child, &child_allocation); + } + + if (notebook->show_tabs && notebook->children) + gtk_notebook_pages_allocate (notebook, allocation); + } +} + +static void +gtk_notebook_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + GdkPoint points[6]; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gdk_window_clear_area (widget->window, + area->x, area->y, + area->width, area->height); + + if (notebook->show_tabs || notebook->show_border) + { + x = GTK_CONTAINER (widget)->border_width; + y = GTK_CONTAINER (widget)->border_width; + width = widget->allocation.width - x * 2; + height = widget->allocation.height - y * 2; + + if (notebook->show_tabs && notebook->children) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + y += notebook->cur_page->allocation.height; + case GTK_POS_BOTTOM: + height -= notebook->cur_page->allocation.height; + break; + case GTK_POS_LEFT: + x += notebook->cur_page->allocation.width; + case GTK_POS_RIGHT: + width -= notebook->cur_page->allocation.width; + break; + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + points[0].x = notebook->cur_page->allocation.x; + points[0].y = y; + points[1].x = x; + points[1].y = y; + points[2].x = x; + points[2].y = y + height - 1; + points[3].x = x + width - 1; + points[3].y = y + height - 1; + points[4].x = x + width - 1; + points[4].y = y; + points[5].x = (notebook->cur_page->allocation.x + + notebook->cur_page->allocation.width - + GTK_WIDGET (notebook)->style->klass->xthickness); + points[5].y = y; + + if (points[5].x == (x + width)) + points[5].x -= 1; + break; + case GTK_POS_BOTTOM: + points[0].x = (notebook->cur_page->allocation.x + + notebook->cur_page->allocation.width - + GTK_WIDGET (notebook)->style->klass->xthickness); + points[0].y = y + height - 1; + points[1].x = x + width - 1; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y; + points[3].x = x; + points[3].y = y; + points[4].x = x; + points[4].y = y + height - 1; + points[5].x = notebook->cur_page->allocation.x; + points[5].y = y + height - 1; + + if (points[0].x == (x + width)) + points[0].x -= 1; + break; + case GTK_POS_LEFT: + points[0].x = x; + points[0].y = (notebook->cur_page->allocation.y + + notebook->cur_page->allocation.height - + GTK_WIDGET (notebook)->style->klass->ythickness); + points[1].x = x; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y + height - 1; + points[3].x = x + width - 1; + points[3].y = y; + points[4].x = x; + points[4].y = y; + points[5].x = x; + points[5].y = notebook->cur_page->allocation.y; + + if (points[0].y == (y + height)) + points[0].y -= 1; + break; + case GTK_POS_RIGHT: + points[0].x = x + width - 1; + points[0].y = notebook->cur_page->allocation.y; + points[1].x = x + width - 1; + points[1].y = y; + points[2].x = x; + points[2].y = y; + points[3].x = x; + points[3].y = y + height - 1; + points[4].x = x + width - 1; + points[4].y = y + height - 1; + points[5].x = x + width - 1; + points[5].y = (notebook->cur_page->allocation.y + + notebook->cur_page->allocation.height - + GTK_WIDGET (notebook)->style->klass->ythickness); + + if (points[5].y == (y + height)) + points[5].y -= 1; + break; + } + + gtk_draw_polygon (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + points, 6, FALSE); + + children = g_list_last (notebook->children); + while (children) + { + page = children->data; + children = children->prev; + + if (notebook->cur_page != page) + gtk_notebook_draw_tab (notebook, page, area); + } + + if (notebook->cur_page) + gtk_notebook_draw_tab (notebook, notebook->cur_page, area); + } + else if (notebook->show_border) + { + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + x, y, width, height); + } + } + } +} + +static void +gtk_notebook_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkNotebook *notebook; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gtk_notebook_paint (widget, area); + + if (notebook->cur_page && + gtk_widget_intersect (notebook->cur_page->child, area, &child_area)) + gtk_widget_draw (notebook->cur_page->child, &child_area); + } +} + +static gint +gtk_notebook_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkNotebook *notebook; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gtk_notebook_paint (widget, &event->area); + + child_event = *event; + if (notebook->cur_page && GTK_WIDGET_NO_WINDOW (notebook->cur_page->child) && + gtk_widget_intersect (notebook->cur_page->child, &event->area, &child_event.area)) + gtk_widget_event (notebook->cur_page->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static gint +gtk_notebook_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if ((event->type != GDK_BUTTON_PRESS) || + (event->window != widget->window)) + return FALSE; + + notebook = GTK_NOTEBOOK (widget); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child) && + (event->x >= page->allocation.x) && + (event->y >= page->allocation.y) && + (event->x <= (page->allocation.x + page->allocation.width)) && + (event->y <= (page->allocation.y + page->allocation.height))) + { + gtk_notebook_switch_page (notebook, page); + break; + } + } + + return FALSE; +} + +static void +gtk_notebook_add (GtkContainer *container, + GtkWidget *widget) +{ + g_warning ("gtk_notebook_add: use gtk_notebook_{append,prepend}_page instead\n"); +} + +static void +gtk_notebook_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (container)); + g_return_if_fail (widget != NULL); + + notebook = GTK_NOTEBOOK (container); + + children = notebook->children; + while (children) + { + page = children->data; + + if (page->child == widget) + { + gtk_widget_unparent (page->child); + gtk_widget_unparent (page->tab_label); + + notebook->children = g_list_remove_link (notebook->children, children); + g_list_free (children); + g_free (page); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + children = children->next; + } +} + +static void +gtk_notebook_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (container)); + g_return_if_fail (callback != NULL); + + notebook = GTK_NOTEBOOK (container); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + (* callback) (page->child, callback_data); + } +} + +static void +gtk_notebook_switch_page (GtkNotebook *notebook, + GtkNotebookPage *page) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + + if (notebook->cur_page != page) + { + if (notebook->cur_page && GTK_WIDGET_MAPPED (notebook->cur_page->child)) + gtk_widget_unmap (notebook->cur_page->child); + + notebook->cur_page = page; + gtk_notebook_pages_allocate (notebook, >K_WIDGET (notebook)->allocation); + + if (GTK_WIDGET_MAPPED (notebook)) + gtk_widget_map (notebook->cur_page->child); + + if (GTK_WIDGET_DRAWABLE (notebook)) + gtk_widget_queue_draw (GTK_WIDGET (notebook)); + } +} + +static void +gtk_notebook_draw_tab (GtkNotebook *notebook, + GtkNotebookPage *page, + GdkRectangle *area) +{ + GdkRectangle child_area; + GdkRectangle page_area; + GtkStateType state_type; + GdkPoint points[6]; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + g_return_if_fail (area != NULL); + + page_area.x = page->allocation.x; + page_area.y = page->allocation.y; + page_area.width = page->allocation.width; + page_area.height = page->allocation.height; + + if (gdk_rectangle_intersect (&page_area, area, &child_area)) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + points[0].x = page->allocation.x + page->allocation.width - 1; + points[0].y = page->allocation.y + page->allocation.height - 1; + + points[1].x = page->allocation.x + page->allocation.width - 1; + points[1].y = page->allocation.y + TAB_CURVATURE; + + points[2].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[2].y = page->allocation.y; + + points[3].x = page->allocation.x + TAB_CURVATURE; + points[3].y = page->allocation.y; + + points[4].x = page->allocation.x; + points[4].y = page->allocation.y + TAB_CURVATURE; + + points[5].x = page->allocation.x; + points[5].y = page->allocation.y + page->allocation.height - 1; + break; + case GTK_POS_BOTTOM: + points[0].x = page->allocation.x; + points[0].y = page->allocation.y; + + points[1].x = page->allocation.x; + points[1].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[2].x = page->allocation.x + TAB_CURVATURE; + points[2].y = page->allocation.y + page->allocation.height - 1; + + points[3].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[3].y = page->allocation.y + page->allocation.height - 1; + + points[4].x = page->allocation.x + page->allocation.width - 1; + points[4].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[5].x = page->allocation.x + page->allocation.width - 1; + points[5].y = page->allocation.y; + break; + case GTK_POS_LEFT: + points[0].x = page->allocation.x + page->allocation.width - 1; + points[0].y = page->allocation.y; + + points[1].x = page->allocation.x + TAB_CURVATURE; + points[1].y = page->allocation.y; + + points[2].x = page->allocation.x; + points[2].y = page->allocation.y + TAB_CURVATURE; + + points[3].x = page->allocation.x; + points[3].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[4].x = page->allocation.x + TAB_CURVATURE; + points[4].y = page->allocation.y + page->allocation.height - 1; + + points[5].x = page->allocation.x + page->allocation.width - 1; + points[5].y = page->allocation.y + page->allocation.height - 1; + break; + case GTK_POS_RIGHT: + points[0].x = page->allocation.x; + points[0].y = page->allocation.y + page->allocation.height - 1; + + points[1].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[1].y = page->allocation.y + page->allocation.height - 1; + + points[2].x = page->allocation.x + page->allocation.width - 1; + points[2].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[3].x = page->allocation.x + page->allocation.width - 1; + points[3].y = page->allocation.y + TAB_CURVATURE; + + points[4].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[4].y = page->allocation.y; + + points[5].x = page->allocation.x; + points[5].y = page->allocation.y; + break; + } + + if (notebook->cur_page == page) + state_type = GTK_STATE_NORMAL; + else + state_type = GTK_STATE_ACTIVE; + + gtk_draw_polygon (GTK_WIDGET (notebook)->style, + GTK_WIDGET (notebook)->window, + state_type, GTK_SHADOW_OUT, + points, 6, (notebook->cur_page != page)); + + if (gtk_widget_intersect (page->tab_label, area, &child_area)) + gtk_widget_draw (page->tab_label, &child_area); + } +} + +static void +gtk_notebook_pages_allocate (GtkNotebook *notebook, + GtkAllocation *allocation) +{ + GtkNotebookPage *page; + GtkAllocation child_allocation; + GList *children; + + if (notebook->show_tabs && notebook->children) + { + child_allocation.x = GTK_CONTAINER (notebook)->border_width; + child_allocation.y = GTK_CONTAINER (notebook)->border_width; + + switch (notebook->tab_pos) + { + case GTK_POS_BOTTOM: + child_allocation.y = allocation->height - notebook->cur_page->requisition.height; + case GTK_POS_TOP: + child_allocation.height = notebook->cur_page->requisition.height; + break; + case GTK_POS_RIGHT: + child_allocation.x = allocation->width - notebook->cur_page->requisition.width; + case GTK_POS_LEFT: + child_allocation.width = notebook->cur_page->requisition.width; + break; + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + child_allocation.width = page->requisition.width + TAB_OVERLAP; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + child_allocation.height = page->requisition.height + TAB_OVERLAP; + break; + } + + gtk_notebook_page_allocate (notebook, page, &child_allocation); + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + child_allocation.x += child_allocation.width - TAB_OVERLAP; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + child_allocation.y += child_allocation.height - TAB_OVERLAP; + break; + } + } + } + } +} + +static void +gtk_notebook_page_allocate (GtkNotebook *notebook, + GtkNotebookPage *page, + GtkAllocation *allocation) +{ + GtkAllocation child_allocation; + gint xthickness, ythickness; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + g_return_if_fail (allocation != NULL); + + page->allocation = *allocation; + + xthickness = GTK_WIDGET (notebook)->style->klass->xthickness; + ythickness = GTK_WIDGET (notebook)->style->klass->ythickness; + + if (notebook->cur_page != page) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + page->allocation.y += ythickness; + case GTK_POS_BOTTOM: + page->allocation.height -= ythickness; + break; + case GTK_POS_LEFT: + page->allocation.x += xthickness; + case GTK_POS_RIGHT: + page->allocation.width -= xthickness; + break; + } + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x * 2; + child_allocation.height = page->allocation.height - child_allocation.y; + child_allocation.x += page->allocation.x; + child_allocation.y += page->allocation.y; + break; + case GTK_POS_BOTTOM: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x * 2; + child_allocation.height = page->allocation.height - child_allocation.y; + child_allocation.x += page->allocation.x; + child_allocation.y = page->allocation.y; + break; + case GTK_POS_LEFT: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x; + child_allocation.height = page->allocation.height - child_allocation.y * 2; + child_allocation.x += page->allocation.x; + child_allocation.y += page->allocation.y; + break; + case GTK_POS_RIGHT: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x; + child_allocation.height = page->allocation.height - child_allocation.y * 2; + child_allocation.x = page->allocation.x; + child_allocation.y += page->allocation.y; + break; + } + + gtk_widget_size_allocate (page->tab_label, &child_allocation); +} diff --git a/gtk/gtknotebook.h b/gtk/gtknotebook.h new file mode 100644 index 0000000000..402823b2e3 --- /dev/null +++ b/gtk/gtknotebook.h @@ -0,0 +1,98 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_NOTEBOOK_H__ +#define __GTK_NOTEBOOK_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_NOTEBOOK(obj) GTK_CHECK_CAST (obj, gtk_notebook_get_type (), GtkNotebook) +#define GTK_NOTEBOOK_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_notebook_get_type (), GtkNotebookClass) +#define GTK_IS_NOTEBOOK(obj) GTK_CHECK_TYPE (obj, gtk_notebook_get_type ()) + + +typedef struct _GtkNotebook GtkNotebook; +typedef struct _GtkNotebookClass GtkNotebookClass; +typedef struct _GtkNotebookPage GtkNotebookPage; + +struct _GtkNotebook +{ + GtkContainer container; + + GtkNotebookPage *cur_page; + GList *children; + + guint show_tabs : 1; + guint show_border : 1; + guint tab_pos : 2; +}; + +struct _GtkNotebookClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkNotebookPage +{ + GtkWidget *child; + GtkWidget *tab_label; + GtkRequisition requisition; + GtkAllocation allocation; +}; + + +guint gtk_notebook_get_type (void); +GtkWidget* gtk_notebook_new (void); +void gtk_notebook_append_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label); +void gtk_notebook_prepend_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label); +void gtk_notebook_insert_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label, + gint position); +void gtk_notebook_remove_page (GtkNotebook *notebook, + gint page_num); +gint gtk_notebook_current_page (GtkNotebook *notebook); +void gtk_notebook_set_page (GtkNotebook *notebook, + gint page_num); +void gtk_notebook_next_page (GtkNotebook *notebook); +void gtk_notebook_prev_page (GtkNotebook *notebook); +void gtk_notebook_set_tab_pos (GtkNotebook *notebook, + GtkPositionType pos); +void gtk_notebook_set_show_tabs (GtkNotebook *notebook, + gint show_tabs); +void gtk_notebook_set_show_border (GtkNotebook *notebook, + gint show_border); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_NOTEBOOK_H__ */ diff --git a/gtk/gtkobject.c b/gtk/gtkobject.c new file mode 100644 index 0000000000..ffe487e891 --- /dev/null +++ b/gtk/gtkobject.c @@ -0,0 +1,994 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdarg.h> +#include <string.h> +#include "gtkobject.h" +#include "gtksignal.h" + + +#define OBJECT_DATA_ID_CHUNK 1024 + + +enum { + DESTROY, + LAST_SIGNAL +}; + + +typedef struct _GtkObjectData GtkObjectData; +typedef struct _GtkArgInfo GtkArgInfo; + +struct _GtkObjectData +{ + guint id; + gpointer data; + GtkObjectData *next; +}; + +struct _GtkArgInfo +{ + char *name; + GtkType type; +}; + + +static void gtk_object_class_init (GtkObjectClass *klass); +static void gtk_object_init (GtkObject *object); +static void gtk_object_arg (GtkObject *object, + GtkArg *arg); +static void gtk_real_object_destroy (GtkObject *object); +static void gtk_object_data_init (void); +static GtkObjectData* gtk_object_data_new (void); +static void gtk_object_data_destroy (GtkObjectData *odata); +static guint* gtk_object_data_id_alloc (void); +GtkArg* gtk_object_collect_args (gint *nargs, + va_list args1, + va_list args2); + + +static gint object_signals[LAST_SIGNAL] = { 0 }; + +static gint object_data_init = TRUE; +static GHashTable *object_data_ht = NULL; +static GMemChunk *object_data_mem_chunk = NULL; +static GtkObjectData *object_data_free_list = NULL; +static GSList *object_data_id_list = NULL; +static gint object_data_id_index = 0; + +static GHashTable *arg_info_ht = NULL; + +static const char *user_data_key = "user_data"; + + +/***************************************** + * gtk_object_get_type: + * + * arguments: + * + * results: + * The type identifier for GtkObject's + *****************************************/ + +void +gtk_object_init_type () +{ + GtkType object_type = 0; + GtkTypeInfo object_info = + { + "GtkObject", + sizeof (GtkObject), + sizeof (GtkObjectClass), + (GtkClassInitFunc) gtk_object_class_init, + (GtkObjectInitFunc) gtk_object_init, + (GtkArgFunc) gtk_object_arg, + }; + + object_type = gtk_type_unique (0, &object_info); + g_assert (object_type == GTK_TYPE_OBJECT); +} + +GtkType +gtk_object_get_type () +{ + return GTK_TYPE_OBJECT; +} + +/***************************************** + * gtk_object_class_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_class_init (GtkObjectClass *class) +{ + class->signals = NULL; + class->nsignals = 0; + + gtk_object_add_arg_type ("GtkObject::user_data", GTK_TYPE_POINTER); + gtk_object_add_arg_type ("GtkObject::signal", GTK_TYPE_SIGNAL); + + object_signals[DESTROY] = + gtk_signal_new ("destroy", + GTK_RUN_LAST, + class->type, + GTK_SIGNAL_OFFSET (GtkObjectClass, destroy), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (class, object_signals, LAST_SIGNAL); + + class->destroy = gtk_real_object_destroy; +} + +/***************************************** + * gtk_object_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_init (GtkObject *object) +{ + object->flags = 0; + object->ref_count = 0; + object->object_data = NULL; +} + +/***************************************** + * gtk_object_arg: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_arg (GtkObject *object, + GtkArg *arg) +{ + if (strcmp (arg->name, "user_data") == 0) + { + gtk_object_set_user_data (object, GTK_VALUE_POINTER (*arg)); + } + else if (strncmp (arg->name, "signal", 6) == 0) + { + if ((arg->name[6] != ':') || (arg->name[7] != ':')) + { + g_print ("invalid signal argument: \"%s\"\n", arg->name); + return; + } + + gtk_signal_connect (object, arg->name + 8, + (GtkSignalFunc) GTK_VALUE_SIGNAL (*arg).f, + GTK_VALUE_SIGNAL (*arg).d); + } +} + +/***************************************** + * gtk_object_class_add_signals: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_class_add_signals (GtkObjectClass *class, + gint *signals, + gint nsignals) +{ + gint *new_signals; + gint i; + + g_return_if_fail (class != NULL); + + new_signals = g_new (gint, class->nsignals + nsignals); + for (i = 0; i < class->nsignals; i++) + new_signals[i] = class->signals[i]; + for (i = 0; i < nsignals; i++) + new_signals[class->nsignals + i] = signals[i]; + + class->signals = new_signals; + class->nsignals += nsignals; +} + +/***************************************** + * gtk_object_ref: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_ref (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + object->ref_count += 1; +} + +/***************************************** + * gtk_object_new: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_unref (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + if (object->ref_count > 0) + object->ref_count -= 1; +} + +/***************************************** + * gtk_object_new: + * + * arguments: + * + * results: + *****************************************/ + +GtkObject* +gtk_object_new (guint type, + ...) +{ + GtkObject *obj; + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + obj = gtk_type_new (type); + + va_start (args1, type); + va_start (args2, type); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (obj, nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); + + return obj; +} + +/***************************************** + * gtk_object_newv: + * + * arguments: + * + * results: + *****************************************/ + +GtkObject* +gtk_object_newv (guint type, + gint nargs, + GtkArg *args) +{ + gpointer obj; + + obj = gtk_type_new (type); + gtk_object_setv (obj, nargs, args); + + return obj; +} + +/***************************************** + * gtk_object_set: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_set (GtkObject *obj, + ...) +{ + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + g_return_if_fail (obj != NULL); + + va_start (args1, obj); + va_start (args2, obj); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (obj, nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); +} + +/***************************************** + * gtk_object_setv: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_setv (GtkObject *obj, + gint nargs, + GtkArg *args) +{ + guint class_type; + char class_name[1024]; + char *arg_name; + int i; + + g_return_if_fail (obj != NULL); + + for (i = 0; i < nargs; i++) + { + arg_name = strchr (args[i].name, ':'); + if (!arg_name || (arg_name[0] != ':') || (arg_name[1] != ':')) + { + g_print ("invalid arg name: \"%s\"\n", args[i].name); + continue; + } + + strncpy (class_name, args[i].name, (long) (arg_name - args[i].name)); + class_name[(long) (arg_name - args[i].name)] = '\0'; + + args[i].name = arg_name + 2; + + class_type = gtk_type_from_name (class_name); + gtk_type_set_arg (obj, class_type, &args[i]); + } +} + +/***************************************** + * gtk_object_add_arg_type: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_add_arg_type (const char *arg_name, + GtkType arg_type) +{ + GtkArgInfo *info; + + info = g_new (GtkArgInfo, 1); + info->name = g_strdup(arg_name); + info->type = arg_type; + + if (!arg_info_ht) + arg_info_ht = g_hash_table_new (g_string_hash, g_string_equal); + + g_hash_table_insert (arg_info_ht, info->name, info); +} + +/***************************************** + * gtk_object_get_arg_type: + * + * arguments: + * + * results: + *****************************************/ + +GtkType +gtk_object_get_arg_type (const char *arg_name) +{ + GtkArgInfo *info; + char buffer[1024]; + char *t; + + if (!arg_info_ht) + return GTK_TYPE_INVALID; + + t = strchr (arg_name, ':'); + if (!t || (t[0] != ':') || (t[1] != ':')) + { + g_print ("invalid arg name: \"%s\"\n", arg_name); + return GTK_TYPE_INVALID; + } + + t = strchr (t + 2, ':'); + if (t) + { + strncpy (buffer, arg_name, (long) (t - arg_name)); + buffer[(long) (t - arg_name)] = '\0'; + arg_name = buffer; + } + + info = g_hash_table_lookup (arg_info_ht, (gpointer) arg_name); + if (info) + return info->type; + + return GTK_TYPE_INVALID; +} + +/***************************************** + * gtk_object_destroy: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_destroy (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + if ((object->ref_count > 0) || GTK_OBJECT_IN_CALL (object)) + { + GTK_OBJECT_SET_FLAGS (object, GTK_NEED_DESTROY); + } + else + { + GTK_OBJECT_UNSET_FLAGS (object, GTK_NEED_DESTROY); + GTK_OBJECT_SET_FLAGS (object, GTK_BEING_DESTROYED); + + gtk_signal_emit (object, object_signals[DESTROY]); + } +} + +/***************************************** + * gtk_object_set_data: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_set_data (GtkObject *object, + const gchar *key, + gpointer data) +{ + GtkObjectData *odata; + GtkObjectData *prev; + guint *id; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (key != NULL); + + if (object_data_init) + gtk_object_data_init (); + + id = g_hash_table_lookup (object_data_ht, (gpointer) key); + + if (!data) + { + if (id) + { + prev = NULL; + odata = object->object_data; + + while (odata) + { + if (odata->id == *id) + { + if (prev) + prev->next = odata->next; + if (odata == object->object_data) + object->object_data = odata->next; + + gtk_object_data_destroy (odata); + break; + } + + prev = odata; + odata = odata->next; + } + } + } + else + { + if (!id) + { + id = gtk_object_data_id_alloc (); + g_hash_table_insert (object_data_ht, (gpointer) key, id); + } + + odata = object->object_data; + while (odata) + { + if (odata->id == *id) + { + odata->data = data; + return; + } + + odata = odata->next; + } + + odata = gtk_object_data_new (); + odata->id = *id; + odata->data = data; + + odata->next = object->object_data; + object->object_data = odata; + } +} + +/***************************************** + * gtk_object_get_data: + * + * arguments: + * + * results: + *****************************************/ + +gpointer +gtk_object_get_data (GtkObject *object, + const gchar *key) +{ + GtkObjectData *odata; + guint *id; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (GTK_IS_OBJECT (object), NULL); + g_return_val_if_fail (key != NULL, NULL); + + if (object_data_init) + gtk_object_data_init (); + + id = g_hash_table_lookup (object_data_ht, (gpointer) key); + if (id) + { + odata = object->object_data; + while (odata) + { + if (odata->id == *id) + return odata->data; + odata = odata->next; + } + } + + return NULL; +} + +/***************************************** + * gtk_object_remove_data: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_remove_data (GtkObject *object, + const gchar *key) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (key != NULL); + + gtk_object_set_data (object, key, NULL); +} + +/***************************************** + * gtk_object_set_user_data: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_set_user_data (GtkObject *object, + gpointer data) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + gtk_object_set_data (object, user_data_key, data); +} + +/***************************************** + * gtk_object_get_user_data: + * + * arguments: + * + * results: + *****************************************/ + +gpointer +gtk_object_get_user_data (GtkObject *object) +{ + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (GTK_IS_OBJECT (object), NULL); + + return gtk_object_get_data (object, user_data_key); +} + +/***************************************** + * gtk_object_check_cast: + * + * arguments: + * + * results: + *****************************************/ + +GtkObject* +gtk_object_check_cast (GtkObject *obj, + GtkType cast_type) +{ + if (obj && obj->klass && !gtk_type_is_a (obj->klass->type, cast_type)) + { + gchar *from_name = gtk_type_name (obj->klass->type); + gchar *to_name = gtk_type_name (cast_type); + + g_warning ("invalid cast from \"%s\" to \"%s\"", + from_name ? from_name : "(unknown)", + to_name ? to_name : "(unknown)"); + } + + return obj; +} + +/***************************************** + * gtk_object_check_class_cast: + * + * arguments: + * + * results: + *****************************************/ + +GtkObjectClass* +gtk_object_check_class_cast (GtkObjectClass *klass, + GtkType cast_type) +{ + if (klass && !gtk_type_is_a (klass->type, cast_type)) + g_warning ("invalid cast from \"%sClass\" to \"%sClass\"", + gtk_type_name (klass->type), + gtk_type_name (cast_type)); + + return klass; +} + +/***************************************** + * gtk_real_object_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_object_destroy (GtkObject *object) +{ + GtkObjectData *odata; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + gtk_signal_handlers_destroy (object); + + if (object->object_data) + { + odata = object->object_data; + while (odata->next) + odata = odata->next; + + odata->next = object_data_free_list; + object_data_free_list = object->object_data; + } + + g_free (object); +} + +/***************************************** + * gtk_object_data_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_data_init () +{ + if (object_data_init) + { + object_data_init = FALSE; + + object_data_ht = g_hash_table_new (g_string_hash, g_string_equal); + } +} + +/***************************************** + * gtk_object_data_new: + * + * arguments: + * + * results: + *****************************************/ + +static GtkObjectData* +gtk_object_data_new () +{ + GtkObjectData *odata; + + if (!object_data_mem_chunk) + object_data_mem_chunk = g_mem_chunk_new ("object data mem chunk", + sizeof (GtkObjectData), + 1024, G_ALLOC_AND_FREE); + + odata = g_chunk_new (GtkObjectData, object_data_mem_chunk); + + odata->id = 0; + odata->data = NULL; + odata->next = NULL; + + return odata; +} + +/***************************************** + * gtk_object_data_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_data_destroy (GtkObjectData *odata) +{ + g_return_if_fail (odata != NULL); + + g_mem_chunk_free (object_data_mem_chunk, odata); +} + +/***************************************** + * gtk_object_data_id_alloc: + * + * arguments: + * + * results: + *****************************************/ + +static guint* +gtk_object_data_id_alloc () +{ + static guint next_id = 1; + guint *ids; + + if (!object_data_id_list || + (object_data_id_index == OBJECT_DATA_ID_CHUNK)) + { + ids = g_new (guint, OBJECT_DATA_ID_CHUNK); + object_data_id_index = 0; + object_data_id_list = g_slist_prepend (object_data_id_list, ids); + } + else + { + ids = object_data_id_list->data; + } + + ids[object_data_id_index] = next_id++; + return &ids[object_data_id_index++]; +} + +/***************************************** + * gtk_object_data_id_alloc: + * + * arguments: + * + * results: + *****************************************/ + +GtkArg* +gtk_object_collect_args (gint *nargs, + va_list args1, + va_list args2) +{ + GtkArg *args; + GtkType type; + char *name; + int done; + int i, n; + + n = 0; + done = FALSE; + + while (!done) + { + name = va_arg (args1, char *); + if (!name) + { + done = TRUE; + continue; + } + + type = gtk_object_get_arg_type (name); + + switch (GTK_FUNDAMENTAL_TYPE (type)) + { + case GTK_TYPE_INVALID: + g_print ("invalid arg name: \"%s\" %x\n", name, type); + (void) va_arg (args1, long); + continue; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + case GTK_TYPE_BOOL: + case GTK_TYPE_INT: + case GTK_TYPE_UINT: + case GTK_TYPE_ENUM: + case GTK_TYPE_FLAGS: + (void) va_arg (args1, gint); + break; + case GTK_TYPE_LONG: + case GTK_TYPE_ULONG: + (void) va_arg (args1, glong); + break; + case GTK_TYPE_FLOAT: + (void) va_arg (args1, gfloat); + break; + case GTK_TYPE_STRING: + (void) va_arg (args1, gchar*); + break; + case GTK_TYPE_POINTER: + case GTK_TYPE_BOXED: + (void) va_arg (args1, gpointer); + break; + case GTK_TYPE_SIGNAL: + (void) va_arg (args1, GtkFunction); + (void) va_arg (args1, gpointer); + break; + case GTK_TYPE_FOREIGN: + (void) va_arg (args1, gpointer); + (void) va_arg (args1, GtkDestroyNotify); + break; + case GTK_TYPE_CALLBACK: + (void) va_arg (args1, GtkCallbackMarshal); + (void) va_arg (args1, gpointer); + (void) va_arg (args1, GtkDestroyNotify); + break; + case GTK_TYPE_C_CALLBACK: + (void) va_arg (args1, GtkFunction); + (void) va_arg (args1, gpointer); + break; + case GTK_TYPE_ARGS: + (void) va_arg (args1, gint); + (void) va_arg (args1, GtkArg*); + break; + case GTK_TYPE_OBJECT: + (void) va_arg (args1, GtkObject*); + break; + default: + g_error ("unsupported type %s in args", gtk_type_name (type)); + break; + } + + n += 1; + } + + *nargs = n; + args = NULL; + + if (n > 0) + { + args = g_new0 (GtkArg, n); + + for (i = 0; i < n; i++) + { + args[i].name = va_arg (args2, char *); + args[i].type = gtk_object_get_arg_type (args[i].name); + + switch (GTK_FUNDAMENTAL_TYPE (args[i].type)) + { + case GTK_TYPE_INVALID: + (void) va_arg (args2, long); + i -= 1; + continue; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + GTK_VALUE_CHAR(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_BOOL: + GTK_VALUE_BOOL(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_INT: + GTK_VALUE_INT(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_UINT: + GTK_VALUE_UINT(args[i]) = va_arg (args2, guint); + break; + case GTK_TYPE_ENUM: + GTK_VALUE_ENUM(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_FLAGS: + GTK_VALUE_FLAGS(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_LONG: + GTK_VALUE_LONG(args[i]) = va_arg (args2, glong); + break; + case GTK_TYPE_ULONG: + GTK_VALUE_ULONG(args[i]) = va_arg (args2, gulong); + break; + case GTK_TYPE_FLOAT: + GTK_VALUE_FLOAT(args[i]) = va_arg (args2, gfloat); + break; + case GTK_TYPE_STRING: + GTK_VALUE_STRING(args[i]) = va_arg (args2, gchar*); + break; + case GTK_TYPE_POINTER: + GTK_VALUE_POINTER(args[i]) = va_arg (args2, gpointer); + break; + case GTK_TYPE_BOXED: + GTK_VALUE_BOXED(args[i]) = va_arg (args2, gpointer); + break; + case GTK_TYPE_SIGNAL: + GTK_VALUE_SIGNAL(args[i]).f = va_arg (args2, GtkFunction); + GTK_VALUE_SIGNAL(args[i]).d = va_arg (args2, gpointer); + break; + case GTK_TYPE_FOREIGN: + GTK_VALUE_FOREIGN(args[i]).data = va_arg (args2, gpointer); + GTK_VALUE_FOREIGN(args[i]).notify = + va_arg (args2, GtkDestroyNotify); + break; + case GTK_TYPE_CALLBACK: + GTK_VALUE_CALLBACK(args[i]).marshal = + va_arg (args2, GtkCallbackMarshal); + GTK_VALUE_CALLBACK(args[i]).data = va_arg (args2, gpointer); + GTK_VALUE_CALLBACK(args[i]).notify = + va_arg (args2, GtkDestroyNotify); + break; + case GTK_TYPE_C_CALLBACK: + GTK_VALUE_C_CALLBACK(args[i]).func = va_arg (args2, GtkFunction); + GTK_VALUE_C_CALLBACK(args[i]).func_data = + va_arg (args2, gpointer); + break; + case GTK_TYPE_ARGS: + GTK_VALUE_ARGS(args[i]).n_args = va_arg (args2, gint); + GTK_VALUE_ARGS(args[i]).args = va_arg (args2, GtkArg*); + break; + case GTK_TYPE_OBJECT: + GTK_VALUE_OBJECT(args[i]) = va_arg (args2, GtkObject*); + g_assert (GTK_VALUE_OBJECT(args[i]) == NULL || + GTK_CHECK_TYPE (GTK_VALUE_OBJECT(args[i]), + args[i].type)); + break; + default: + g_error ("unsupported type %s in args", + gtk_type_name (args[i].type)); + break; + } + } + } + + return args; +} diff --git a/gtk/gtkobject.h b/gtk/gtkobject.h new file mode 100644 index 0000000000..023bbbf0c3 --- /dev/null +++ b/gtk/gtkobject.h @@ -0,0 +1,250 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_OBJECT_H__ +#define __GTK_OBJECT_H__ + + +#include <gtk/gtkenums.h> +#include <gtk/gtktypeutils.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* GtkObject only uses the first 3 bits of the "flags" field. + * They refer to the following flags. + * GtkWidget uses the remaining bits. Though this is a kinda nasty + * break up, it does make the size of GtkWidget smaller. + */ +enum +{ + GTK_NEED_DESTROY = 1 << 0, + GTK_BEING_DESTROYED = 1 << 1, + GTK_IN_CALL = 1 << 2 +}; + + +/* The debugging versions of the casting macros make sure the cast is "ok" + * before proceeding, but they are definately slower than their less + * careful counterparts as they involve no less than 3 function calls. + */ +#ifdef NDEBUG + +#define GTK_CHECK_CAST(obj,cast_type,cast) ((cast*) obj) +#define GTK_CHECK_CLASS_CAST(klass,cast_type,cast) ((cast*) klass) + +#else /* NDEBUG */ + +#define GTK_CHECK_CAST(obj,cast_type,cast) \ + ((cast*) gtk_object_check_cast ((GtkObject*) obj, cast_type)) + +#define GTK_CHECK_CLASS_CAST(klass,cast_type,cast) \ + ((cast*) gtk_object_check_class_cast ((GtkObjectClass*) klass, cast_type)) + +#endif /* NDEBUG */ + + +/* Determines whether 'obj' is a type of 'otype'. + */ +#define GTK_CHECK_TYPE(obj,otype) (gtk_type_is_a (((GtkObject*) obj)->klass->type, otype)) + + +/* Macro for casting a pointer to a GtkObject pointer. + */ +#define GTK_OBJECT(obj) GTK_CHECK_CAST (obj, gtk_object_get_type (), GtkObject) + +/* Macros for extracting various fields from GtkObject and + * GtkObjectClass. + */ +#define GTK_OBJECT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_object_get_type (), GtkObjectClass) +#define GTK_OBJECT_FLAGS(obj) (GTK_OBJECT (obj)->flags) +#define GTK_OBJECT_NEED_DESTROY(obj) (GTK_OBJECT_FLAGS (obj) & GTK_NEED_DESTROY) +#define GTK_OBJECT_BEING_DESTROYED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_BEING_DESTROYED) +#define GTK_OBJECT_IN_CALL(obj) (GTK_OBJECT_FLAGS (obj) & GTK_IN_CALL) +#define GTK_OBJECT_DESTROY(obj) (GTK_OBJECT (obj)->klass->destroy) +#define GTK_OBJECT_TYPE(obj) (GTK_OBJECT (obj)->klass->type) +#define GTK_OBJECT_SIGNALS(obj) (GTK_OBJECT (obj)->klass->signals) +#define GTK_OBJECT_NSIGNALS(obj) (GTK_OBJECT (obj)->klass->signals) + +/* Macro for testing whether "obj" is of type GtkObject. + */ +#define GTK_IS_OBJECT(obj) GTK_CHECK_TYPE (obj, gtk_object_get_type ()) + +/* Macros for setting and clearing bits in the "flags" field of GtkObject. + */ +#define GTK_OBJECT_SET_FLAGS(obj,flag) (GTK_OBJECT_FLAGS (obj) |= (flag)) +#define GTK_OBJECT_UNSET_FLAGS(obj,flag) (GTK_OBJECT_FLAGS (obj) &= ~(flag)) + + +typedef struct _GtkObjectClass GtkObjectClass; + + +/* GtkObject is the base of the object hierarchy. It defines + * the few basic items that all derived classes contain. + */ +struct _GtkObject +{ + /* 32 bits of flags. GtkObject only uses 3 of these bits and + * GtkWidget uses the rest. This is done because structs are + * aligned on 4 or 8 byte boundaries. If bitfields were used + * both here and in GtkWidget much space would be wasted. + */ + guint32 flags; + + /* 16 bit reference count. "gtk_object_destroy" actually only + * destroys an object when its ref count is 0. (Decrementing + * a reference count of 0 is defined as a no-op). + */ + guint16 ref_count; + + /* A pointer to the objects class. This will actually point to + * the derived objects class struct (which will be derived from + * GtkObjectClass). + */ + GtkObjectClass *klass; + + /* The list of signal handlers and other data + * fields for this object. + */ + gpointer object_data; +}; + +/* GtkObjectClass is the base of the class hierarchy. It defines + * the basic necessities for the class mechanism to work. Namely, + * the "type", "signals" and "nsignals" fields. + */ +struct _GtkObjectClass +{ + /* The type identifier for the objects class. There is + * one unique identifier per class. + */ + guint type; + + /* The signals this object class handles. "signals" is an + * array of signal ID's. + */ + gint *signals; + + /* The number of signals listed in "signals". + */ + gint nsignals; + + /* The destroy function for objects. In one way ore another + * this is defined for all objects. If an object class overrides + * this method in order to perform class specific destruction + * then it should still call it after it is finished with its + * own cleanup. (See the destroy function for GtkWidget for + * an example of how to do this). + */ + void (* destroy) (GtkObject *object); +}; + + +/* Get the type identifier for GtkObject's. + */ +guint gtk_object_get_type (void); + +/* Append "signals" to those already defined in "class". + */ +void gtk_object_class_add_signals (GtkObjectClass *klass, + gint *signals, + gint nsignals); + +void gtk_object_ref (GtkObject *object); + +void gtk_object_unref (GtkObject *object); + +GtkObject* gtk_object_new (guint type, + ...); + +GtkObject* gtk_object_newv (guint type, + gint nargs, + GtkArg *args); + +void gtk_object_set (GtkObject *obj, + ...); + +void gtk_object_setv (GtkObject *obj, + gint nargs, + GtkArg *args); + +void gtk_object_add_arg_type (const char *arg_name, + GtkType arg_type); + +GtkType gtk_object_get_arg_type (const char *arg_name); + +/* Emit the "destroy" signal for "object". Normally it is + * permissible to emit a signal for an object instead of + * calling the corresponding convenience routine, however + * "gtk_object_destroy" should be called instead of emitting + * the signal manually as it checks to see if the object is + * currently handling another signal emittion (very likely) + * and sets the GTK_NEED_DESTROY flag which tells the object + * to be destroyed when it is done handling the signal emittion. + */ +void gtk_object_destroy (GtkObject *object); + +/* Set 'data' to the "object_data" field of the object. The + * data is indexed by the "key". If there is already data + * associated with "key" then the new data will replace it. + * If 'data' is NULL then this call is equivalent to + * 'gtk_object_remove_data'. + */ +void gtk_object_set_data (GtkObject *object, + const gchar *key, + gpointer data); + +/* Get the data associated with "key". + */ +gpointer gtk_object_get_data (GtkObject *object, + const gchar *key); + +/* Remove the data associated with "key". This call is + * equivalent to 'gtk_object_set_data' where 'data' is NULL. + */ +void gtk_object_remove_data (GtkObject *object, + const gchar *key); + +/* Set the "user_data" object data field of "object". It should + * be noted that this is no different than calling 'gtk_object_data_add' + * with a key of "user_data". It is merely provided as a convenience. + */ +void gtk_object_set_user_data (GtkObject *object, + gpointer data); + +/* Get the "user_data" object data field of "object". It should + * be noted that this is no different than calling 'gtk_object_data_find' + * with a key of "user_data". It is merely provided as a convenience. + */ +gpointer gtk_object_get_user_data (GtkObject *object); + +GtkObject* gtk_object_check_cast (GtkObject *obj, + GtkType cast_type); + +GtkObjectClass* gtk_object_check_class_cast (GtkObjectClass *klass, + GtkType cast_type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_OBJECT_H__ */ diff --git a/gtk/gtkoptionmenu.c b/gtk/gtkoptionmenu.c new file mode 100644 index 0000000000..919aa26692 --- /dev/null +++ b/gtk/gtkoptionmenu.c @@ -0,0 +1,584 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtkoptionmenu.h" +#include "gtksignal.h" + + +#define CHILD_LEFT_SPACING 5 +#define CHILD_RIGHT_SPACING 1 +#define CHILD_TOP_SPACING 1 +#define CHILD_BOTTOM_SPACING 1 +#define OPTION_INDICATOR_WIDTH 12 +#define OPTION_INDICATOR_HEIGHT 8 +#define OPTION_INDICATOR_SPACING 2 + + +static void gtk_option_menu_class_init (GtkOptionMenuClass *klass); +static void gtk_option_menu_init (GtkOptionMenu *option_menu); +static void gtk_option_menu_destroy (GtkObject *object); +static void gtk_option_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_option_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_option_menu_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_option_menu_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_option_menu_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_option_menu_button_press (GtkWidget *widget, + GdkEventButton *event); +static void gtk_option_menu_deactivate (GtkMenuShell *menu_shell, + GtkOptionMenu *option_menu); +static void gtk_option_menu_update_contents (GtkOptionMenu *option_menu); +static void gtk_option_menu_remove_contents (GtkOptionMenu *option_menu); +static void gtk_option_menu_calc_size (GtkOptionMenu *option_menu); +static void gtk_option_menu_position (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data); + + +static GtkButtonClass *parent_class = NULL; + + +guint +gtk_option_menu_get_type () +{ + static guint option_menu_type = 0; + + if (!option_menu_type) + { + GtkTypeInfo option_menu_info = + { + "GtkOptionMenu", + sizeof (GtkOptionMenu), + sizeof (GtkOptionMenuClass), + (GtkClassInitFunc) gtk_option_menu_class_init, + (GtkObjectInitFunc) gtk_option_menu_init, + (GtkArgFunc) NULL, + }; + + option_menu_type = gtk_type_unique (gtk_button_get_type (), &option_menu_info); + } + + return option_menu_type; +} + +static void +gtk_option_menu_class_init (GtkOptionMenuClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkButtonClass *button_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + button_class = (GtkButtonClass*) class; + + parent_class = gtk_type_class (gtk_button_get_type ()); + + object_class->destroy = gtk_option_menu_destroy; + + widget_class->draw = gtk_option_menu_draw; + widget_class->draw_focus = NULL; + widget_class->size_request = gtk_option_menu_size_request; + widget_class->size_allocate = gtk_option_menu_size_allocate; + widget_class->expose_event = gtk_option_menu_expose; + widget_class->button_press_event = gtk_option_menu_button_press; +} + +static void +gtk_option_menu_init (GtkOptionMenu *option_menu) +{ + GTK_WIDGET_UNSET_FLAGS (option_menu, GTK_CAN_FOCUS); + + option_menu->menu = NULL; + option_menu->menu_item = NULL; + option_menu->width = 0; + option_menu->height = 0; +} + +GtkWidget* +gtk_option_menu_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_option_menu_get_type ())); +} + +GtkWidget* +gtk_option_menu_get_menu (GtkOptionMenu *option_menu) +{ + g_return_val_if_fail (option_menu != NULL, NULL); + g_return_val_if_fail (GTK_IS_OPTION_MENU (option_menu), NULL); + + return option_menu->menu; +} + +void +gtk_option_menu_set_menu (GtkOptionMenu *option_menu, + GtkWidget *menu) +{ + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + gtk_option_menu_remove_menu (option_menu); + + option_menu->menu = menu; + gtk_object_ref (GTK_OBJECT (option_menu->menu)); + + gtk_option_menu_calc_size (option_menu); + + gtk_signal_connect (GTK_OBJECT (option_menu->menu), "deactivate", + (GtkSignalFunc) gtk_option_menu_deactivate, + option_menu); + + if (GTK_WIDGET (option_menu)->parent) + gtk_widget_queue_resize (GTK_WIDGET (option_menu)); + + gtk_option_menu_update_contents (option_menu); +} + +void +gtk_option_menu_remove_menu (GtkOptionMenu *option_menu) +{ + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (option_menu->menu) + { + gtk_option_menu_remove_contents (option_menu); + gtk_signal_disconnect_by_data (GTK_OBJECT (option_menu->menu), + option_menu); + + gtk_object_unref (GTK_OBJECT (option_menu->menu)); + option_menu->menu = NULL; + } +} + +void +gtk_option_menu_set_history (GtkOptionMenu *option_menu, + gint index) +{ + GtkWidget *menu_item; + + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (option_menu->menu) + { + gtk_menu_set_active (GTK_MENU (option_menu->menu), index); + menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + + if (menu_item != option_menu->menu_item) + { + gtk_option_menu_remove_contents (option_menu); + gtk_option_menu_update_contents (option_menu); + } + } +} + + +static void +gtk_option_menu_destroy (GtkObject *object) +{ + GtkOptionMenu *option_menu; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (object)); + + option_menu = GTK_OPTION_MENU (object); + + gtk_option_menu_remove_contents (option_menu); + if (option_menu->menu) + { + gtk_object_unref (GTK_OBJECT (option_menu->menu)); + gtk_widget_destroy (option_menu->menu); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_option_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkOptionMenu *option_menu; + gint tmp; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (requisition != NULL); + + option_menu = GTK_OPTION_MENU (widget); + + requisition->width = ((GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness) * 2 + + option_menu->width + + OPTION_INDICATOR_WIDTH + + OPTION_INDICATOR_SPACING * 5 + + CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING); + requisition->height = ((GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->ythickness) * 2 + + option_menu->height + + CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING); + + tmp = (requisition->height - option_menu->height + + OPTION_INDICATOR_HEIGHT + OPTION_INDICATOR_SPACING * 2); + requisition->height = MAX (requisition->height, tmp); +} + +static void +gtk_option_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWidget *child; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + child = GTK_BUTTON (widget)->child; + if (child && GTK_WIDGET_VISIBLE (child)) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness); + child_allocation.y = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->ythickness); + child_allocation.width = (allocation->width - child_allocation.x * 2 - + OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 5 - + CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING); + child_allocation.height = (allocation->height - child_allocation.y * 2 - + CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING); + child_allocation.x += CHILD_LEFT_SPACING; + child_allocation.y += CHILD_RIGHT_SPACING; + + gtk_widget_size_allocate (child, &child_allocation); + } +} + +static void +gtk_option_menu_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GdkRectangle restrict_area; + GdkRectangle new_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + restrict_area.x = GTK_CONTAINER (widget)->border_width; + restrict_area.y = GTK_CONTAINER (widget)->border_width; + restrict_area.width = widget->allocation.width - restrict_area.x * 2; + restrict_area.height = widget->allocation.height - restrict_area.y * 2; + + if (gdk_rectangle_intersect (area, &restrict_area, &new_area)) + { + gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget)); + gdk_window_clear_area (widget->window, + new_area.x, new_area.y, + new_area.width, new_area.height); + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT, + restrict_area.x, restrict_area.y, + restrict_area.width, restrict_area.height); + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT, + restrict_area.x + restrict_area.width - restrict_area.x - + OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 4, + restrict_area.y + (restrict_area.height - OPTION_INDICATOR_HEIGHT) / 2, + OPTION_INDICATOR_WIDTH, OPTION_INDICATOR_HEIGHT); + } + } +} + +static void +gtk_option_menu_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkWidget *child; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_option_menu_paint (widget, area); + + child = GTK_BUTTON (widget)->child; + if (child && gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } +} + +static gint +gtk_option_menu_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkWidget *child; + GdkEventExpose child_event; + gint remove_child; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_option_menu_paint (widget, &event->area); + + remove_child = FALSE; + child = GTK_BUTTON (widget)->child; + + if (!child) + { + if (!GTK_OPTION_MENU (widget)->menu) + return FALSE; + gtk_option_menu_update_contents (GTK_OPTION_MENU (widget)); + child = GTK_BUTTON (widget)->child; + if (!child) + return FALSE; + remove_child = TRUE; + } + + child_event = *event; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + + if (remove_child) + gtk_option_menu_remove_contents (GTK_OPTION_MENU (widget)); + } + + return FALSE; +} + +static gint +gtk_option_menu_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkOptionMenu *option_menu; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if ((event->type == GDK_BUTTON_PRESS) && + (event->button == 1)) + { + option_menu = GTK_OPTION_MENU (widget); + gtk_option_menu_remove_contents (option_menu); + gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL, + gtk_option_menu_position, option_menu, + event->button, event->time); + } + + return FALSE; +} + +static void +gtk_option_menu_deactivate (GtkMenuShell *menu_shell, + GtkOptionMenu *option_menu) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + gtk_option_menu_update_contents (option_menu); +} + +static void +gtk_option_menu_update_contents (GtkOptionMenu *option_menu) +{ + GtkWidget *child; + + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (option_menu->menu) + { + gtk_option_menu_remove_contents (option_menu); + + option_menu->menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + if (option_menu->menu_item) + { + child = GTK_BIN (option_menu->menu_item)->child; + if (child) + { + gtk_container_block_resize (GTK_CONTAINER (option_menu)); + if (GTK_WIDGET (option_menu)->state != child->state) + gtk_widget_set_state (child, GTK_WIDGET (option_menu)->state); + gtk_widget_reparent (child, GTK_WIDGET (option_menu)); + gtk_container_unblock_resize (GTK_CONTAINER (option_menu)); + } + + gtk_widget_size_allocate (GTK_WIDGET (option_menu), + &(GTK_WIDGET (option_menu)->allocation)); + + if (GTK_WIDGET_DRAWABLE (option_menu)) + gtk_widget_queue_draw (GTK_WIDGET (option_menu)); + } + } +} + +static void +gtk_option_menu_remove_contents (GtkOptionMenu *option_menu) +{ + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (GTK_BUTTON (option_menu)->child) + { + gtk_container_block_resize (GTK_CONTAINER (option_menu)); + if (GTK_WIDGET (option_menu->menu_item)->state != GTK_BUTTON (option_menu)->child->state) + gtk_widget_set_state (GTK_BUTTON (option_menu)->child, + GTK_WIDGET (option_menu->menu_item)->state); + GTK_WIDGET_UNSET_FLAGS (GTK_BUTTON (option_menu)->child, GTK_MAPPED | GTK_REALIZED); + gtk_widget_reparent (GTK_BUTTON (option_menu)->child, option_menu->menu_item); + gtk_container_unblock_resize (GTK_CONTAINER (option_menu)); + option_menu->menu_item = NULL; + } +} + +static void +gtk_option_menu_calc_size (GtkOptionMenu *option_menu) +{ + GtkWidget *child; + GList *children; + + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + option_menu->width = 0; + option_menu->height = 0; + + if (option_menu->menu) + { + children = GTK_MENU_SHELL (option_menu->menu)->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + gtk_widget_size_request (child, &child->requisition); + + option_menu->width = MAX (option_menu->width, child->requisition.width); + option_menu->height = MAX (option_menu->height, child->requisition.height); + } + } + } +} + +static void +gtk_option_menu_position (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data) +{ + GtkOptionMenu *option_menu; + GtkWidget *active; + GtkWidget *child; + GList *children; + gint shift_menu; + gint screen_width; + gint screen_height; + gint menu_xpos; + gint menu_ypos; + gint width; + gint height; + + g_return_if_fail (user_data != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (user_data)); + + option_menu = GTK_OPTION_MENU (user_data); + + width = GTK_WIDGET (menu)->allocation.width; + height = GTK_WIDGET (menu)->allocation.height; + + active = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + children = GTK_MENU_SHELL (option_menu->menu)->children; + gdk_window_get_origin (GTK_WIDGET (option_menu)->window, &menu_xpos, &menu_ypos); + + menu_ypos += GTK_WIDGET (option_menu)->allocation.height / 2 - 2; + + if (active != NULL) + menu_ypos -= active->requisition.height / 2; + + while (children) + { + child = children->data; + + if (active == child) + break; + + menu_ypos -= child->allocation.height; + children = children->next; + } + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + shift_menu = FALSE; + if (menu_ypos < 0) + { + menu_ypos = 0; + shift_menu = TRUE; + } + else if ((menu_ypos + height) > screen_height) + { + menu_ypos -= ((menu_ypos + height) - screen_height); + shift_menu = TRUE; + } + + if (shift_menu) + { + if ((menu_xpos + GTK_WIDGET (option_menu)->allocation.width + width) <= screen_width) + menu_xpos += GTK_WIDGET (option_menu)->allocation.width; + else + menu_xpos -= width; + } + + if (menu_xpos < 0) + menu_xpos = 0; + else if ((menu_xpos + width) > screen_width) + menu_xpos -= ((menu_xpos + width) - screen_width); + + *x = menu_xpos; + *y = menu_ypos; +} diff --git a/gtk/gtkoptionmenu.h b/gtk/gtkoptionmenu.h new file mode 100644 index 0000000000..bbddf23097 --- /dev/null +++ b/gtk/gtkoptionmenu.h @@ -0,0 +1,71 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_OPTION_MENU_H__ +#define __GTK_OPTION_MENU_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbutton.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_OPTION_MENU(obj) GTK_CHECK_CAST (obj, gtk_option_menu_get_type (), GtkOptionMenu) +#define GTK_OPTION_MENU_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_option_menu_get_type (), GtkOptionMenuClass) +#define GTK_IS_OPTION_MENU(obj) GTK_CHECK_TYPE (obj, gtk_option_menu_get_type ()) + + +typedef struct _GtkOptionMenu GtkOptionMenu; +typedef struct _GtkOptionMenuClass GtkOptionMenuClass; + +struct _GtkOptionMenu +{ + GtkButton button; + + GtkWidget *menu; + GtkWidget *menu_item; + + guint16 width; + guint16 height; +}; + +struct _GtkOptionMenuClass +{ + GtkButtonClass parent_class; +}; + + +guint gtk_option_menu_get_type (void); +GtkWidget* gtk_option_menu_new (void); +GtkWidget* gtk_option_menu_get_menu (GtkOptionMenu *option_menu); +void gtk_option_menu_set_menu (GtkOptionMenu *option_menu, + GtkWidget *menu); +void gtk_option_menu_remove_menu (GtkOptionMenu *option_menu); +void gtk_option_menu_set_history (GtkOptionMenu *option_menu, + gint index); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_OPTION_MENU_H__ */ diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c new file mode 100644 index 0000000000..d6b53db3d4 --- /dev/null +++ b/gtk/gtkpaned.c @@ -0,0 +1,452 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkpaned.h" + + +static void gtk_paned_class_init (GtkPanedClass *klass); +static void gtk_paned_init (GtkPaned *paned); +static void gtk_paned_destroy (GtkObject *object); +static void gtk_paned_realize (GtkWidget *widget); +static void gtk_paned_map (GtkWidget *widget); +static void gtk_paned_unmap (GtkWidget *widget); +static void gtk_paned_unrealize (GtkWidget *widget); +static gint gtk_paned_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_paned_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_paned_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_paned_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_paned_get_type () +{ + static guint paned_type = 0; + + if (!paned_type) + { + GtkTypeInfo paned_info = + { + "GtkPaned", + sizeof (GtkPaned), + sizeof (GtkPanedClass), + (GtkClassInitFunc) gtk_paned_class_init, + (GtkObjectInitFunc) gtk_paned_init, + (GtkArgFunc) NULL, + }; + + paned_type = gtk_type_unique (gtk_container_get_type (), &paned_info); + } + + return paned_type; +} + +static void +gtk_paned_class_init (GtkPanedClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_paned_destroy; + + widget_class->realize = gtk_paned_realize; + widget_class->map = gtk_paned_map; + widget_class->unmap = gtk_paned_unmap; + widget_class->unrealize = gtk_paned_unrealize; + widget_class->expose_event = gtk_paned_expose; + + container_class->add = gtk_paned_add; + container_class->remove = gtk_paned_remove; + container_class->foreach = gtk_paned_foreach; +} + +static void +gtk_paned_init (GtkPaned *paned) +{ + GTK_WIDGET_SET_FLAGS (paned, GTK_NO_WINDOW); + + paned->child1 = NULL; + paned->child2 = NULL; + paned->handle = NULL; + paned->xor_gc = NULL; + + paned->handle_size = 10; + paned->gutter_size = 6; + paned->position_set = FALSE; + paned->in_drag = FALSE; + + paned->handle_xpos = -1; + paned->handle_ypos = -1; +} + + +static void +gtk_paned_destroy (GtkObject *object) +{ + GtkPaned *paned; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_PANED (object)); + + paned = GTK_PANED (object); + + if (paned->child1) + { + paned->child1->parent = NULL; + gtk_object_unref (GTK_OBJECT (paned->child1)); + gtk_widget_destroy (paned->child1); + } + if (paned->child2) + { + paned->child2->parent = NULL; + gtk_object_unref (GTK_OBJECT (paned->child2)); + gtk_widget_destroy (paned->child2); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_paned_realize (GtkWidget *widget) +{ + GtkPaned *paned; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + paned = GTK_PANED (widget); + + attributes.x = paned->handle_xpos; + attributes.y = paned->handle_ypos; + attributes.width = paned->handle_size; + attributes.height = paned->handle_size; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.cursor = gdk_cursor_new(GDK_CROSS); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | + GDK_WA_CURSOR; + + paned->handle = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (paned->handle, widget); + gdk_window_show (paned->handle); + gdk_window_raise (paned->handle); + + widget->window = widget->parent->window; + widget->style = gtk_style_attach (widget->style, widget->window); + + gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL); +} + +static void +gtk_paned_map (GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + paned = GTK_PANED (widget); + + gdk_window_show (paned->handle); + gtk_widget_queue_draw (widget); + + if (paned->child1 && + GTK_WIDGET_VISIBLE (paned->child1) && + !GTK_WIDGET_MAPPED (paned->child1)) + gtk_widget_map (paned->child1); + if (paned->child2 && + GTK_WIDGET_VISIBLE (paned->child2) && + !GTK_WIDGET_MAPPED (paned->child2)) + gtk_widget_map (paned->child2); +} + +static void +gtk_paned_unmap (GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + paned = GTK_PANED (widget); + + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + gdk_window_hide (paned->handle); + + if (paned->child1 && + GTK_WIDGET_VISIBLE (paned->child1) && + GTK_WIDGET_MAPPED (paned->child1)) + gtk_widget_unmap (paned->child1); + if (paned->child2 && + GTK_WIDGET_VISIBLE (paned->child2) && + GTK_WIDGET_MAPPED (paned->child2)) + gtk_widget_unmap (paned->child2); +} + +static void +gtk_paned_unrealize (GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED); + paned = GTK_PANED (widget); + + gtk_style_detach (widget->style); + + if (paned->xor_gc) + gdk_gc_destroy (paned->xor_gc); + if (paned->handle) + gdk_window_destroy (paned->handle); + + paned->handle = NULL; + widget->window = NULL; +} + +static gint +gtk_paned_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkPaned *paned; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + paned = GTK_PANED (widget); + + /* An expose event for the handle */ + if (event->window == paned->handle) + { + gdk_window_set_background (paned->handle, + &widget->style->bg[widget->state]); + gdk_window_clear (paned->handle); + gtk_draw_shadow (widget->style, paned->handle, + GTK_WIDGET_STATE(widget), + GTK_SHADOW_OUT, 0, 0, + paned->handle_size, paned->handle_size); + } + else + { + child_event = *event; + if (paned->child1 && + GTK_WIDGET_NO_WINDOW (paned->child1) && + gtk_widget_intersect (paned->child1, &event->area, &child_event.area)) + gtk_widget_event (paned->child1, (GdkEvent*) &child_event); + + if (paned->child2 && + GTK_WIDGET_NO_WINDOW (paned->child2) && + gtk_widget_intersect (paned->child2, &event->area, &child_event.area)) + gtk_widget_event (paned->child2, (GdkEvent*) &child_event); + + /* redraw the groove if necessary */ + child_event.area = paned->groove_rectangle; + if (gtk_widget_intersect (widget, &event->area, &child_event.area)) + gtk_widget_draw (widget, &child_event.area); + } + } + return FALSE; +} + +void +gtk_paned_add1 (GtkPaned *paned, + GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!paned->child1) + { + gtk_widget_set_parent (widget, GTK_WIDGET (paned)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + paned->child1 = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned)) + gtk_widget_queue_resize (widget); + } +} + +void +gtk_paned_add2 (GtkPaned *paned, + GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!paned->child2) + { + gtk_widget_set_parent (widget, GTK_WIDGET (paned)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + paned->child2 = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned)) + gtk_widget_queue_resize (widget); + } +} + +static void +gtk_paned_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_PANED (container)); + g_return_if_fail (widget != NULL); + + paned = GTK_PANED (container); + + if (!paned->child1) + gtk_paned_add1 (GTK_PANED (container),widget); + else if (!paned->child2) + gtk_paned_add2 (GTK_PANED (container),widget); +} + +static void +gtk_paned_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_PANED (container)); + g_return_if_fail (widget != NULL); + + paned = GTK_PANED (container); + + if (paned->child1 == widget) + { + gtk_widget_unparent (widget); + + paned->child1 = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } + else if (paned->child2 == widget) + { + gtk_widget_unparent (widget); + + paned->child2 = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +gtk_paned_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkPaned *paned; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_PANED (container)); + g_return_if_fail (callback != NULL); + + paned = GTK_PANED (container); + + if (paned->child1) + (* callback) (paned->child1, callback_data); + if (paned->child2) + (* callback) (paned->child2, callback_data); +} + +void +gtk_paned_handle_size (GtkPaned *paned, guint16 size) +{ + gint x,y; + + if (paned->handle) + { + gdk_window_get_geometry (paned->handle, &x, &y, NULL, NULL, NULL); + gdk_window_move_resize (paned->handle, + x + paned->handle_size / 2 - size / 2, + y + paned->handle_size / 2 - size / 2, + size, size); + } + + paned->handle_size = size; +} + +void +gtk_paned_gutter_size (GtkPaned *paned, guint16 size) +{ + paned->gutter_size = size; + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (paned))) + gtk_widget_queue_resize (GTK_WIDGET (paned)); +} diff --git a/gtk/gtkpaned.h b/gtk/gtkpaned.h new file mode 100644 index 0000000000..1b25263b0a --- /dev/null +++ b/gtk/gtkpaned.h @@ -0,0 +1,78 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_PANED_H__ +#define __GTK_PANED_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PANED(obj) GTK_CHECK_CAST (obj, gtk_paned_get_type (), GtkPaned) +#define GTK_PANED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_paned_get_type (), GtkPanedClass) +#define GTK_IS_PANED(obj) GTK_CHECK_TYPE (obj, gtk_paned_get_type ()) + + +typedef struct _GtkPaned GtkPaned; +typedef struct _GtkPanedClass GtkPanedClass; + +struct _GtkPaned +{ + GtkContainer container; + + GtkWidget *child1; + GtkWidget *child2; + + GdkWindow *handle; + GdkRectangle groove_rectangle; + GdkGC *xor_gc; + + guint16 handle_size; + guint16 gutter_size; + + gint child1_size; + guint position_set : 1; + guint in_drag : 1; + + gint16 handle_xpos; + gint16 handle_ypos; +}; + +struct _GtkPanedClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_paned_get_type (void); +void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child); +void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child); +void gtk_paned_handle_size (GtkPaned *paned, guint16 size); +void gtk_paned_gutter_size (GtkPaned *paned, guint16 size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PANED_H__ */ diff --git a/gtk/gtkpixmap.c b/gtk/gtkpixmap.c new file mode 100644 index 0000000000..ae640f81f1 --- /dev/null +++ b/gtk/gtkpixmap.c @@ -0,0 +1,176 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkcontainer.h" +#include "gtkpixmap.h" + + +static void gtk_pixmap_class_init (GtkPixmapClass *klass); +static void gtk_pixmap_init (GtkPixmap *pixmap); +static gint gtk_pixmap_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_pixmap_get_type () +{ + static guint pixmap_type = 0; + + if (!pixmap_type) + { + GtkTypeInfo pixmap_info = + { + "GtkPixmap", + sizeof (GtkPixmap), + sizeof (GtkPixmapClass), + (GtkClassInitFunc) gtk_pixmap_class_init, + (GtkObjectInitFunc) gtk_pixmap_init, + (GtkArgFunc) NULL, + }; + + pixmap_type = gtk_type_unique (gtk_misc_get_type (), &pixmap_info); + } + + return pixmap_type; +} + +static void +gtk_pixmap_class_init (GtkPixmapClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_pixmap_expose; +} + +static void +gtk_pixmap_init (GtkPixmap *pixmap) +{ + GTK_WIDGET_SET_FLAGS (pixmap, GTK_NO_WINDOW); + + pixmap->pixmap = NULL; + pixmap->mask = NULL; +} + +GtkWidget* +gtk_pixmap_new (GdkPixmap *val, + GdkBitmap *mask) +{ + GtkPixmap *pixmap; + + g_return_val_if_fail (val != NULL, NULL); + + pixmap = gtk_type_new (gtk_pixmap_get_type ()); + + gtk_pixmap_set (pixmap, val, mask); + + return GTK_WIDGET (pixmap); +} + +void +gtk_pixmap_set (GtkPixmap *pixmap, + GdkPixmap *val, + GdkBitmap *mask) +{ + gint width; + gint height; + + g_return_if_fail (pixmap != NULL); + g_return_if_fail (GTK_IS_PIXMAP (pixmap)); + g_return_if_fail (val != NULL); + + pixmap->pixmap = val; + pixmap->mask = mask; + + if (pixmap->pixmap) + { + gdk_window_get_size (pixmap->pixmap, &width, &height); + GTK_WIDGET (pixmap)->requisition.width = width + GTK_MISC (pixmap)->xpad * 2; + GTK_WIDGET (pixmap)->requisition.height = height + GTK_MISC (pixmap)->ypad * 2; + } + else + { + GTK_WIDGET (pixmap)->requisition.width = 0; + GTK_WIDGET (pixmap)->requisition.height = 0; + } + + if (GTK_WIDGET_VISIBLE (pixmap)) + gtk_widget_queue_resize (GTK_WIDGET (pixmap)); +} + +void +gtk_pixmap_get (GtkPixmap *pixmap, + GdkPixmap **val, + GdkBitmap **mask) +{ + g_return_if_fail (pixmap != NULL); + g_return_if_fail (GTK_IS_PIXMAP (pixmap)); + + if (val) + *val = pixmap->pixmap; + if (mask) + *mask = pixmap->mask; +} + + +static gint +gtk_pixmap_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkPixmap *pixmap; + GtkMisc *misc; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PIXMAP (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + pixmap = GTK_PIXMAP (widget); + misc = GTK_MISC (widget); + + x = (widget->allocation.x * (1.0 - misc->xalign) + + (widget->allocation.x + widget->allocation.width + - (widget->requisition.width - misc->xpad * 2)) * + misc->xalign) + 0.5; + y = (widget->allocation.y * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height + - (widget->requisition.height - misc->ypad * 2)) * + misc->yalign) + 0.5; + + if (pixmap->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, pixmap->mask); + gdk_gc_set_clip_origin (widget->style->black_gc, x, y); + } + + gdk_draw_pixmap (widget->window, + widget->style->black_gc, + pixmap->pixmap, + 0, 0, x, y, -1, -1); + + if (pixmap->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, NULL); + gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0); + } + } + + return FALSE; +} diff --git a/gtk/gtkpixmap.h b/gtk/gtkpixmap.h new file mode 100644 index 0000000000..970d4f40fc --- /dev/null +++ b/gtk/gtkpixmap.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_PIXMAP_H__ +#define __GTK_PIXMAP_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkmisc.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PIXMAP(obj) GTK_CHECK_CAST (obj, gtk_pixmap_get_type (), GtkPixmap) +#define GTK_PIXMAP_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_pixmap_get_type (), GtkPixmapClass) +#define GTK_IS_PIXMAP(obj) GTK_CHECK_TYPE (obj, gtk_pixmap_get_type ()) + + +typedef struct _GtkPixmap GtkPixmap; +typedef struct _GtkPixmapClass GtkPixmapClass; + +struct _GtkPixmap +{ + GtkMisc misc; + + GdkPixmap *pixmap; + GdkBitmap *mask; +}; + +struct _GtkPixmapClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_pixmap_get_type (void); +GtkWidget* gtk_pixmap_new (GdkPixmap *pixmap, + GdkBitmap *mask); +void gtk_pixmap_set (GtkPixmap *pixmap, + GdkPixmap *val, + GdkBitmap *mask); +void gtk_pixmap_get (GtkPixmap *pixmap, + GdkPixmap **val, + GdkBitmap **mask); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PIXMAP_H__ */ diff --git a/gtk/gtkpreview.c b/gtk/gtkpreview.c new file mode 100644 index 0000000000..4246a321ab --- /dev/null +++ b/gtk/gtkpreview.c @@ -0,0 +1,1571 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <math.h> +#include <string.h> +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include "gdk/gdkx.h" +#include "gtkpreview.h" +#include "gtksignal.h" + + +#define IMAGE_SIZE 256 +#define PREVIEW_CLASS(w) GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass) +#define COLOR_COMPOSE(r,g,b) (lookup_red[r] | lookup_green[g] | lookup_blue[b]) + + +typedef struct _GtkPreviewProp GtkPreviewProp; +typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count); + +struct _GtkPreviewProp +{ + guint16 ref_count; + guint16 nred_shades; + guint16 ngreen_shades; + guint16 nblue_shades; + guint16 ngray_shades; +}; + + +static void gtk_preview_class_init (GtkPreviewClass *klass); +static void gtk_preview_init (GtkPreview *preview); +static void gtk_preview_destroy (GtkObject *object); +static void gtk_preview_realize (GtkWidget *widget); +static void gtk_preview_unrealize (GtkWidget *widget); +static gint gtk_preview_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_preview_make_buffer (GtkPreview *preview); +static void gtk_preview_get_visuals (GtkPreviewClass *klass); +static void gtk_preview_get_cmaps (GtkPreviewClass *klass); +static void gtk_preview_dither_init (GtkPreviewClass *klass); +static void gtk_fill_lookup_array (gulong *array, + int depth, + int shift, + int prec); +static void gtk_trim_cmap (GtkPreviewClass *klass); +static void gtk_create_8_bit (GtkPreviewClass *klass); + +static void gtk_color_8 (guchar *src, + guchar *data, + gint x, + gint y, + gulong width); +static void gtk_color_16 (guchar *src, + guchar *data, + gulong width); +static void gtk_color_24 (guchar *src, + guchar *data, + gulong width); +static void gtk_grayscale_8 (guchar *src, + guchar *data, + gint x, + gint y, + gulong width); +static void gtk_grayscale_16 (guchar *src, + guchar *data, + gulong width); +static void gtk_grayscale_24 (guchar *src, + guchar *data, + gulong width); + +static gint gtk_get_preview_prop (guint *nred, + guint *nblue, + guint *ngreen, + guint *ngray); +static void gtk_set_preview_prop (guint nred, + guint ngreen, + guint nblue, + guint ngray); + +/* transfer functions: + * destination byte order/source bpp/destination bpp + */ +static void gtk_lsbmsb_1_1 (guchar *dest, + guchar *src, + gint count); +static void gtk_lsb_2_2 (guchar *dest, + guchar *src, + gint count); +static void gtk_msb_2_2 (guchar *dest, + guchar *src, + gint count); +static void gtk_lsb_3_3 (guchar *dest, + guchar *src, + gint count); +static void gtk_msb_3_3 (guchar *dest, + guchar *src, + gint count); +static void gtk_lsb_3_4 (guchar *dest, + guchar *src, + gint count); +static void gtk_msb_3_4 (guchar *dest, + guchar *src, + gint count); + + +static GtkWidgetClass *parent_class = NULL; +static GtkPreviewClass *preview_class = NULL; +static GtkPreviewInfo *preview_info = NULL; +static gint install_cmap = FALSE; + + +guint +gtk_preview_get_type () +{ + static guint preview_type = 0; + + if (!preview_type) + { + GtkTypeInfo preview_info = + { + "GtkPreview", + sizeof (GtkPreview), + sizeof (GtkPreviewClass), + (GtkClassInitFunc) gtk_preview_class_init, + (GtkObjectInitFunc) gtk_preview_init, + (GtkArgFunc) NULL, + }; + + preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info); + } + + return preview_type; +} + +static void +gtk_preview_class_init (GtkPreviewClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + preview_class = klass; + + object_class->destroy = gtk_preview_destroy; + + widget_class->realize = gtk_preview_realize; + widget_class->unrealize = gtk_preview_unrealize; + widget_class->expose_event = gtk_preview_expose; + + if (preview_info) + klass->info = *preview_info; + else + { + klass->info.visual = NULL; + klass->info.cmap = NULL; + + klass->info.color_pixels = NULL; + klass->info.gray_pixels = NULL; + klass->info.reserved_pixels = NULL; + + klass->info.lookup_red = NULL; + klass->info.lookup_green = NULL; + klass->info.lookup_blue = NULL; + + klass->info.dither_red = NULL; + klass->info.dither_green = NULL; + klass->info.dither_blue = NULL; + klass->info.dither_gray = NULL; + klass->info.dither_matrix = NULL; + + klass->info.nred_shades = 6; + klass->info.ngreen_shades = 6; + klass->info.nblue_shades = 4; + klass->info.ngray_shades = 24; + klass->info.nreserved = 0; + + klass->info.bpp = 0; + klass->info.cmap_alloced = FALSE; + klass->info.gamma = 1.0; + } + + klass->image = NULL; + + gtk_preview_get_visuals (klass); + gtk_preview_get_cmaps (klass); + gtk_preview_dither_init (klass); +} + +static void +gtk_preview_init (GtkPreview *preview) +{ + GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC); + + preview->buffer = NULL; + preview->buffer_width = 0; + preview->buffer_height = 0; + preview->expand = FALSE; +} + +void +gtk_preview_uninit () +{ + GtkPreviewProp *prop; + GdkAtom property; + + if (preview_class && !install_cmap && + (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) && + (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR)) + { + property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE); + + if (gdk_property_get (NULL, property, property, + 0, sizeof (GtkPreviewProp), FALSE, + NULL, NULL, NULL, (guchar**) &prop)) + { + prop->ref_count = ntohs (prop->ref_count) - 1; + if (prop->ref_count == 0) + { + gdk_property_delete (NULL, property); + } + else + { + prop->ref_count = htons (prop->ref_count); + gdk_property_change (NULL, property, property, 16, + GDK_PROP_MODE_REPLACE, + (guchar*) prop, 5); + } + } + } +} + +GtkWidget* +gtk_preview_new (GtkPreviewType type) +{ + GtkPreview *preview; + + preview = gtk_type_new (gtk_preview_get_type ()); + preview->type = type; + + return GTK_WIDGET (preview); +} + +void +gtk_preview_size (GtkPreview *preview, + gint width, + gint height) +{ + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + + if ((width != GTK_WIDGET (preview)->requisition.width) || + (height != GTK_WIDGET (preview)->requisition.height)) + { + GTK_WIDGET (preview)->requisition.width = width; + GTK_WIDGET (preview)->requisition.height = height; + + if (preview->buffer) + g_free (preview->buffer); + preview->buffer = NULL; + } +} + +void +gtk_preview_put (GtkPreview *preview, + GdkWindow *window, + GdkGC *gc, + gint srcx, + gint srcy, + gint destx, + gint desty, + gint width, + gint height) +{ + GtkWidget *widget; + GdkImage *image; + GdkRectangle r1, r2, r3; + GtkTransferFunc transfer_func; + guchar *image_mem; + guchar *src, *dest; + gint x, xe, x2; + gint y, ye, y2; + guint dest_rowstride; + guint src_bpp; + guint dest_bpp; + gint i; + + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + g_return_if_fail (window != NULL); + + if (!preview->buffer) + return; + + widget = GTK_WIDGET (preview); + + r1.x = srcx; + r1.y = srcy; + r1.width = preview->buffer_width; + r1.height = preview->buffer_height; + + r2.x = destx; + r2.y = desty; + r2.width = width; + r2.height = height; + + if (!gdk_rectangle_intersect (&r1, &r2, &r3)) + return; + + x2 = r3.x + r3.width; + y2 = r3.y + r3.height; + + if (!preview_class->image) + preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST, + preview_class->info.visual, + IMAGE_SIZE, IMAGE_SIZE); + image = preview_class->image; + src_bpp = preview_class->info.bpp; + + image_mem = image->mem; + dest_bpp = image->bpp; + dest_rowstride = image->bpl; + + transfer_func = NULL; + + switch (dest_bpp) + { + case 1: + switch (src_bpp) + { + case 1: + transfer_func = gtk_lsbmsb_1_1; + break; + } + break; + case 2: + switch (src_bpp) + { + case 2: + if (image->byte_order == GDK_MSB_FIRST) + transfer_func = gtk_msb_2_2; + else + transfer_func = gtk_lsb_2_2; + break; + case 3: + break; + } + break; + case 3: + switch (src_bpp) + { + case 3: + if (image->byte_order == GDK_MSB_FIRST) + transfer_func = gtk_msb_3_3; + else + transfer_func = gtk_lsb_3_3; + break; + } + break; + case 4: + switch (src_bpp) + { + case 3: + if (image->byte_order == GDK_MSB_FIRST) + transfer_func = gtk_msb_3_4; + else + transfer_func = gtk_lsb_3_4; + break; + } + break; + } + + if (!transfer_func) + { + g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d", + (image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp); + return; + } + + for (y = r3.y; y < y2; y += IMAGE_SIZE) + { + for (x = r3.x; x < x2; x += IMAGE_SIZE) + { + xe = x + IMAGE_SIZE; + if (xe > x2) + xe = x2; + + ye = y + IMAGE_SIZE; + if (ye > y2) + ye = y2; + + for (i = y; i < ye; i++) + { + src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) + + (x - r1.x)) * (gulong) src_bpp; + dest = image_mem + ((gulong) (i - y) * dest_rowstride); + + if (xe > x) + (* transfer_func) (dest, src, xe - x); + } + + gdk_draw_image (window, gc, + image, 0, 0, x, y, + xe - x, ye - y); + gdk_flush (); + } + } +} + +void +gtk_preview_put_row (GtkPreview *preview, + guchar *src, + guchar *dest, + gint x, + gint y, + gint w) +{ + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + g_return_if_fail (src != NULL); + g_return_if_fail (dest != NULL); + + switch (preview->type) + { + case GTK_PREVIEW_COLOR: + switch (preview_class->info.visual->depth) + { + case 8: + gtk_color_8 (src, dest, x, y, w); + break; + case 15: + case 16: + gtk_color_16 (src, dest, w); + break; + case 24: + case 32: + gtk_color_24 (src, dest, w); + break; + } + break; + case GTK_PREVIEW_GRAYSCALE: + switch (preview_class->info.visual->depth) + { + case 8: + gtk_grayscale_8 (src, dest, x, y, w); + break; + case 15: + case 16: + gtk_grayscale_16 (src, dest, w); + break; + case 24: + case 32: + gtk_grayscale_24 (src, dest, w); + break; + } + break; + } +} + +void +gtk_preview_draw_row (GtkPreview *preview, + guchar *data, + gint x, + gint y, + gint w) +{ + guchar *dest; + + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + g_return_if_fail (data != NULL); + + if ((w <= 0) || (y < 0)) + return; + + g_return_if_fail (data != NULL); + + gtk_preview_make_buffer (preview); + + if (y >= preview->buffer_height) + return; + + switch (preview->type) + { + case GTK_PREVIEW_COLOR: + switch (preview_class->info.visual->depth) + { + case 8: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x); + gtk_color_8 (data, dest, x, y, w); + break; + case 15: + case 16: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2; + gtk_color_16 (data, dest, w); + break; + case 24: + case 32: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3; + gtk_color_24 (data, dest, w); + break; + } + break; + case GTK_PREVIEW_GRAYSCALE: + switch (preview_class->info.visual->depth) + { + case 8: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x); + gtk_grayscale_8 (data, dest, x, y, w); + break; + case 15: + case 16: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2; + gtk_grayscale_16 (data, dest, w); + break; + case 24: + case 32: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3; + gtk_grayscale_24 (data, dest, w); + break; + } + break; + } +} + +void +gtk_preview_set_expand (GtkPreview *preview, + gint expand) +{ + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + + preview->expand = (expand != FALSE); +} + +void +gtk_preview_set_gamma (double _gamma) +{ + g_return_if_fail (preview_class == NULL); + + if (!preview_info) + { + preview_info = g_new0 (GtkPreviewInfo, 1); + preview_info->nred_shades = 6; + preview_info->ngreen_shades = 6; + preview_info->nblue_shades = 4; + preview_info->ngray_shades = 24; + } + + preview_info->gamma = _gamma; +} + +void +gtk_preview_set_color_cube (guint nred_shades, + guint ngreen_shades, + guint nblue_shades, + guint ngray_shades) +{ + g_return_if_fail (preview_class == NULL); + + if (!preview_info) + { + preview_info = g_new0 (GtkPreviewInfo, 1); + preview_info->gamma = 1.0; + } + + preview_info->nred_shades = nred_shades; + preview_info->ngreen_shades = ngreen_shades; + preview_info->nblue_shades = nblue_shades; + preview_info->ngray_shades = ngray_shades; +} + +void +gtk_preview_set_install_cmap (gint _install_cmap) +{ + /* g_return_if_fail (preview_class == NULL); */ + + install_cmap = _install_cmap; +} + +void +gtk_preview_set_reserved (gint nreserved) +{ + if (!preview_info) + preview_info = g_new0 (GtkPreviewInfo, 1); + + preview_info->nreserved = nreserved; +} + +GdkVisual* +gtk_preview_get_visual () +{ + if (!preview_class) + preview_class = gtk_type_class (gtk_preview_get_type ()); + + return preview_class->info.visual; +} + +GdkColormap* +gtk_preview_get_cmap () +{ + if (!preview_class) + preview_class = gtk_type_class (gtk_preview_get_type ()); + + return preview_class->info.cmap; +} + +GtkPreviewInfo* +gtk_preview_get_info () +{ + if (!preview_class) + preview_class = gtk_type_class (gtk_preview_get_type ()); + + return &preview_class->info; +} + + +static void +gtk_preview_destroy (GtkObject *object) +{ + GtkPreview *preview; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_PREVIEW (object)); + + preview = GTK_PREVIEW (object); + if (preview->buffer) + g_free (preview->buffer); + preview->type = (GtkPreviewType) -1; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_preview_realize (GtkWidget *widget) +{ + GtkPreview *preview; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PREVIEW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + preview = GTK_PREVIEW (widget); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_preview_unrealize (GtkWidget *widget) +{ + GtkPreview *preview; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PREVIEW (widget)); + + preview = GTK_PREVIEW (widget); + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static gint +gtk_preview_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkPreview *preview; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + preview = GTK_PREVIEW (widget); + + gtk_preview_put (GTK_PREVIEW (widget), + widget->window, widget->style->black_gc, + (widget->allocation.width - preview->buffer_width) / 2, + (widget->allocation.height - preview->buffer_height) / 2, + event->area.x, event->area.y, + event->area.width, event->area.height); + } + + return FALSE; +} + +static void +gtk_preview_make_buffer (GtkPreview *preview) +{ + GtkWidget *widget; + gint width; + gint height; + + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + + widget = GTK_WIDGET (preview); + + if (preview->expand && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + { + width = widget->allocation.width; + height = widget->allocation.height; + } + else + { + width = widget->requisition.width; + height = widget->requisition.height; + } + + if (!preview->buffer || + (preview->buffer_width != width) || + (preview->buffer_height != height)) + { + if (preview->buffer) + g_free (preview->buffer); + + preview->buffer_width = width; + preview->buffer_height = height; + + preview->buffer = g_new0 (guchar, + preview->buffer_width * + preview->buffer_height * + preview_class->info.bpp); + } +} + +static void +gtk_preview_get_visuals (GtkPreviewClass *klass) +{ + static GdkVisualType types[] = + { + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_PSEUDO_COLOR + }; + static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 }; + static gint nvisual_types = sizeof (types) / sizeof (types[0]); + + int i; + + g_return_if_fail (klass != NULL); + + if (!klass->info.visual) + for (i = 0; i < nvisual_types; i++) + if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i]))) + { + if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) || + (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR)) + { + klass->info.lookup_red = g_new (gulong, 256); + klass->info.lookup_green = g_new (gulong, 256); + klass->info.lookup_blue = g_new (gulong, 256); + + gtk_fill_lookup_array (klass->info.lookup_red, + klass->info.visual->depth, + klass->info.visual->red_shift, + 8 - klass->info.visual->red_prec); + gtk_fill_lookup_array (klass->info.lookup_green, + klass->info.visual->depth, + klass->info.visual->green_shift, + 8 - klass->info.visual->green_prec); + gtk_fill_lookup_array (klass->info.lookup_blue, + klass->info.visual->depth, + klass->info.visual->blue_shift, + 8 - klass->info.visual->blue_prec); + } + break; + } + + if (!klass->info.visual) + { + g_warning ("unable to find a suitable visual for color image display.\n"); + return; + } + + switch (klass->info.visual->depth) + { + case 8: + klass->info.bpp = 1; + break; + case 15: + case 16: + klass->info.bpp = 2; + break; + case 24: + case 32: + klass->info.bpp = 3; + break; + } +} + +static void +gtk_preview_get_cmaps (GtkPreviewClass *klass) +{ + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->info.visual != NULL); + + if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) && + (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR)) + { + if (install_cmap) + { + klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE); + klass->info.cmap_alloced = install_cmap; + + gtk_trim_cmap (klass); + gtk_create_8_bit (klass); + } + else + { + guint nred; + guint ngreen; + guint nblue; + guint ngray; + gint set_prop; + + klass->info.cmap = gdk_colormap_get_system (); + + set_prop = TRUE; + if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray)) + { + set_prop = FALSE; + + klass->info.nred_shades = nred; + klass->info.ngreen_shades = ngreen; + klass->info.nblue_shades = nblue; + klass->info.ngray_shades = ngray; + + if (klass->info.nreserved) + { + klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved); + if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, + klass->info.reserved_pixels, + klass->info.nreserved)) + { + g_free (klass->info.reserved_pixels); + klass->info.reserved_pixels = NULL; + } + } + } + else + { + gtk_trim_cmap (klass); + } + + gtk_create_8_bit (klass); + + if (set_prop) + gtk_set_preview_prop (klass->info.nred_shades, + klass->info.ngreen_shades, + klass->info.nblue_shades, + klass->info.ngray_shades); + } + } + else + { + if (klass->info.visual == gdk_visual_get_system ()) + klass->info.cmap = gdk_colormap_get_system (); + else + klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE); + klass->info.cmap_alloced = TRUE; + + klass->info.nred_shades = 0; + klass->info.ngreen_shades = 0; + klass->info.nblue_shades = 0; + klass->info.ngray_shades = 0; + } +} + +static void +gtk_preview_dither_init (GtkPreviewClass *klass) +{ + int i, j, k; + unsigned char low_shade, high_shade; + unsigned short index; + long red_mult, green_mult; + double red_matrix_width; + double green_matrix_width; + double blue_matrix_width; + double gray_matrix_width; + double red_colors_per_shade; + double green_colors_per_shade; + double blue_colors_per_shade; + double gray_colors_per_shade; + gulong *gray_pixels; + gint shades_r, shades_g, shades_b, shades_gray; + GtkDitherInfo *red_ordered_dither; + GtkDitherInfo *green_ordered_dither; + GtkDitherInfo *blue_ordered_dither; + GtkDitherInfo *gray_ordered_dither; + guchar ***dither_matrix; + guchar DM[8][8] = + { + { 0, 32, 8, 40, 2, 34, 10, 42 }, + { 48, 16, 56, 24, 50, 18, 58, 26 }, + { 12, 44, 4, 36, 14, 46, 6, 38 }, + { 60, 28, 52, 20, 62, 30, 54, 22 }, + { 3, 35, 11, 43, 1, 33, 9, 41 }, + { 51, 19, 59, 27, 49, 17, 57, 25 }, + { 15, 47, 7, 39, 13, 45, 5, 37 }, + { 63, 31, 55, 23, 61, 29, 53, 21 } + }; + + if (klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR) + return; + + shades_r = klass->info.nred_shades; + shades_g = klass->info.ngreen_shades; + shades_b = klass->info.nblue_shades; + shades_gray = klass->info.ngray_shades; + + red_mult = shades_g * shades_b; + green_mult = shades_b; + + red_colors_per_shade = 255.0 / (shades_r - 1); + red_matrix_width = red_colors_per_shade / 64; + + green_colors_per_shade = 255.0 / (shades_g - 1); + green_matrix_width = green_colors_per_shade / 64; + + blue_colors_per_shade = 255.0 / (shades_b - 1); + blue_matrix_width = blue_colors_per_shade / 64; + + gray_colors_per_shade = 255.0 / (shades_gray - 1); + gray_matrix_width = gray_colors_per_shade / 64; + + /* alloc the ordered dither arrays for accelerated dithering */ + + klass->info.dither_red = g_new (GtkDitherInfo, 256); + klass->info.dither_green = g_new (GtkDitherInfo, 256); + klass->info.dither_blue = g_new (GtkDitherInfo, 256); + klass->info.dither_gray = g_new (GtkDitherInfo, 256); + + red_ordered_dither = klass->info.dither_red; + green_ordered_dither = klass->info.dither_green; + blue_ordered_dither = klass->info.dither_blue; + gray_ordered_dither = klass->info.dither_gray; + + dither_matrix = g_new (guchar**, 8); + for (i = 0; i < 8; i++) + { + dither_matrix[i] = g_new (guchar*, 8); + for (j = 0; j < 8; j++) + dither_matrix[i][j] = g_new (guchar, 65); + } + + klass->info.dither_matrix = dither_matrix; + + /* setup the ordered_dither_matrices */ + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + for (k = 0; k <= 64; k++) + dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0; + + /* setup arrays containing three bytes of information for red, green, & blue */ + /* the arrays contain : + * 1st byte: low end shade value + * 2nd byte: high end shade value + * 3rd & 4th bytes: ordered dither matrix index + */ + + gray_pixels = klass->info.gray_pixels; + + for (i = 0; i < 256; i++) + { + + /* setup the red information */ + { + low_shade = (unsigned char) (i / red_colors_per_shade); + if (low_shade == (shades_r - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * red_colors_per_shade) / + red_matrix_width); + + low_shade *= red_mult; + high_shade *= red_mult; + + red_ordered_dither[i].s[1] = index; + red_ordered_dither[i].c[0] = low_shade; + red_ordered_dither[i].c[1] = high_shade; + } + + + /* setup the green information */ + { + low_shade = (unsigned char) (i / green_colors_per_shade); + if (low_shade == (shades_g - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * green_colors_per_shade) / + green_matrix_width); + + low_shade *= green_mult; + high_shade *= green_mult; + + green_ordered_dither[i].s[1] = index; + green_ordered_dither[i].c[0] = low_shade; + green_ordered_dither[i].c[1] = high_shade; + } + + + /* setup the blue information */ + { + low_shade = (unsigned char) (i / blue_colors_per_shade); + if (low_shade == (shades_b - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * blue_colors_per_shade) / + blue_matrix_width); + + blue_ordered_dither[i].s[1] = index; + blue_ordered_dither[i].c[0] = low_shade; + blue_ordered_dither[i].c[1] = high_shade; + } + + + /* setup the gray information */ + { + low_shade = (unsigned char) (i / gray_colors_per_shade); + if (low_shade == (shades_gray - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * gray_colors_per_shade) / + gray_matrix_width); + + gray_ordered_dither[i].s[1] = index; + gray_ordered_dither[i].c[0] = gray_pixels[low_shade]; + gray_ordered_dither[i].c[1] = gray_pixels[high_shade]; + } + } +} + +static void +gtk_fill_lookup_array (gulong *array, + int depth, + int shift, + int prec) +{ + double one_over_gamma; + double ind; + int val; + int i; + + if (preview_class->info.gamma != 0.0) + one_over_gamma = 1.0 / preview_class->info.gamma; + else + one_over_gamma = 1.0; + + for (i = 0; i < 256; i++) + { + if (one_over_gamma == 1.0) + array[i] = ((i >> prec) << shift); + else + { + ind = (double) i / 255.0; + val = (int) (255 * pow (ind, one_over_gamma)); + array[i] = ((val >> prec) << shift); + } + } +} + +static void +gtk_trim_cmap (GtkPreviewClass *klass) +{ + gulong pixels[256]; + guint nred; + guint ngreen; + guint nblue; + guint ngray; + guint nreserved; + guint total; + guint tmp; + gint success; + + nred = klass->info.nred_shades; + ngreen = klass->info.ngreen_shades; + nblue = klass->info.nblue_shades; + ngray = klass->info.ngray_shades; + nreserved = klass->info.nreserved; + + success = FALSE; + while (!success) + { + total = nred * ngreen * nblue + ngray + nreserved; + + if (total <= 256) + { + if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2)) + success = TRUE; + else + { + success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total); + if (success) + { + if (nreserved > 0) + { + klass->info.reserved_pixels = g_new (gulong, nreserved); + memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved); + gdk_colors_free (klass->info.cmap, &pixels[nreserved], + total - nreserved, 0); + } + else + { + gdk_colors_free (klass->info.cmap, pixels, total, 0); + } + } + } + } + + if (!success) + { + if ((nblue >= nred) && (nblue >= ngreen)) + nblue = nblue - 1; + else if ((nred >= ngreen) && (nred >= nblue)) + nred = nred - 1; + else + { + tmp = log (ngray) / log (2); + + if (ngreen >= tmp) + ngreen = ngreen - 1; + else + ngray -= 1; + } + } + } + + if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2)) + { + g_print ("Unable to allocate sufficient colormap entries.\n"); + g_print ("Try exiting other color intensive applications.\n"); + return; + } + + /* If any of the shade values has changed, issue a warning */ + if ((nred != klass->info.nred_shades) || + (ngreen != klass->info.ngreen_shades) || + (nblue != klass->info.nblue_shades) || + (ngray != klass->info.ngray_shades)) + { + g_print ("Not enough colors to satisfy requested color cube.\n"); + g_print ("Reduced color cube shades from\n"); + g_print ("[%d of Red, %d of Green, %d of Blue, %d of Gray] ==> [%d of Red, %d of Green, %d of Blue, %d of Gray]\n", + klass->info.nred_shades, klass->info.ngreen_shades, + klass->info.nblue_shades, klass->info.ngray_shades, + nred, ngreen, nblue, ngray); + } + + klass->info.nred_shades = nred; + klass->info.ngreen_shades = ngreen; + klass->info.nblue_shades = nblue; + klass->info.ngray_shades = ngray; +} + +static void +gtk_create_8_bit (GtkPreviewClass *klass) +{ + unsigned int r, g, b; + unsigned int rv, gv, bv; + unsigned int dr, dg, db, dgray; + GdkColor color; + gulong *pixels; + double one_over_gamma; + int i; + + if (!klass->info.color_pixels) + klass->info.color_pixels = g_new (gulong, 256); + + if (!klass->info.gray_pixels) + klass->info.gray_pixels = g_new (gulong, 256); + + if (klass->info.gamma != 0.0) + one_over_gamma = 1.0 / klass->info.gamma; + else + one_over_gamma = 1.0; + + dr = klass->info.nred_shades - 1; + dg = klass->info.ngreen_shades - 1; + db = klass->info.nblue_shades - 1; + dgray = klass->info.ngray_shades - 1; + + pixels = klass->info.color_pixels; + + for (r = 0, i = 0; r <= dr; r++) + for (g = 0; g <= dg; g++) + for (b = 0; b <= db; b++, i++) + { + rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr); + gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg); + bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db); + color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257; + color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257; + color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257; + + if (!gdk_color_alloc (klass->info.cmap, &color)) + { + g_error ("could not initialize 8-bit combined colormap"); + return; + } + + pixels[i] = color.pixel; + } + + pixels = klass->info.gray_pixels; + + for (i = 0; i < (int) klass->info.ngray_shades; i++) + { + color.red = (i * klass->info.visual->colormap_size) / dgray; + color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257; + color.green = color.red; + color.blue = color.red; + + if (!gdk_color_alloc (klass->info.cmap, &color)) + { + g_error ("could not initialize 8-bit combined colormap"); + return; + } + + pixels[i] = color.pixel; + } +} + + +static void +gtk_color_8 (guchar *src, + guchar *dest, + gint x, + gint y, + gulong width) +{ + gulong *colors; + GtkDitherInfo *dither_red; + GtkDitherInfo *dither_green; + GtkDitherInfo *dither_blue; + GtkDitherInfo r, g, b; + guchar **dither_matrix; + guchar *matrix; + + colors = preview_class->info.color_pixels; + dither_red = preview_class->info.dither_red; + dither_green = preview_class->info.dither_green; + dither_blue = preview_class->info.dither_blue; + dither_matrix = preview_class->info.dither_matrix[y & 0x7]; + + while (width--) + { + r = dither_red[src[0]]; + g = dither_green[src[1]]; + b = dither_blue[src[2]]; + src += 3; + + matrix = dither_matrix[x++ & 0x7]; + *dest++ = colors[(r.c[matrix[r.s[1]]] + + g.c[matrix[g.s[1]]] + + b.c[matrix[b.s[1]]])]; + } +} + +static void +gtk_color_16 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (src[0], src[1], src[2]); + dest[0] = val; + dest[1] = val >> 8; + dest += 2; + src += 3; + } +} + +static void +gtk_color_24 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (src[0], src[1], src[2]); + dest[0] = val; + dest[1] = val >> 8; + dest[2] = val >> 16; + dest += 3; + src += 3; + } +} + +static void +gtk_grayscale_8 (guchar *src, + guchar *dest, + gint x, + gint y, + gulong width) +{ + GtkDitherInfo *dither_gray; + GtkDitherInfo gray; + guchar **dither_matrix; + guchar *matrix; + + dither_gray = preview_class->info.dither_gray; + dither_matrix = preview_class->info.dither_matrix[y & 0x7]; + + while (width--) + { + gray = dither_gray[*src++]; + matrix = dither_matrix[x++ & 0x7]; + *dest++ = gray.c[matrix[gray.s[1]]]; + } +} + +static void +gtk_grayscale_16 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (*src, *src, *src); + dest[0] = val; + dest[1] = val >> 8; + dest += 2; + src += 1; + } +} + +static void +gtk_grayscale_24 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (*src, *src, *src); + dest[0] = val; + dest[1] = val >> 8; + dest[2] = val >> 16; + dest += 3; + src += 1; + } +} + + +static gint +gtk_get_preview_prop (guint *nred, + guint *ngreen, + guint *nblue, + guint *ngray) +{ + GtkPreviewProp *prop; + GdkAtom property; + + property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE); + + if (gdk_property_get (NULL, property, property, + 0, sizeof (GtkPreviewProp), FALSE, + NULL, NULL, NULL, (guchar**) &prop)) + { + *nred = ntohs (prop->nred_shades); + *ngreen = ntohs (prop->ngreen_shades); + *nblue = ntohs (prop->nblue_shades); + *ngray = ntohs (prop->ngray_shades); + + prop->ref_count = htons (ntohs (prop->ref_count) + 1); + gdk_property_change (NULL, property, property, 16, + GDK_PROP_MODE_REPLACE, + (guchar*) prop, 5); + + return TRUE; + } + + return FALSE; +} + +static void +gtk_set_preview_prop (guint nred, + guint ngreen, + guint nblue, + guint ngray) +{ + GtkPreviewProp prop; + GdkAtom property; + + property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE); + + prop.ref_count = htons (1); + prop.nred_shades = htons (nred); + prop.ngreen_shades = htons (ngreen); + prop.nblue_shades = htons (nblue); + prop.ngray_shades = htons (ngray); + + gdk_property_change (NULL, property, property, 16, + GDK_PROP_MODE_REPLACE, + (guchar*) &prop, 5); +} + + +static void +gtk_lsbmsb_1_1 (guchar *dest, + guchar *src, + gint count) +{ + memcpy (dest, src, count); +} + +static void +gtk_lsb_2_2 (guchar *dest, + guchar *src, + gint count) +{ + memcpy (dest, src, count * 2); +} + +static void +gtk_msb_2_2 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[0] = src[1]; + dest[1] = src[0]; + dest += 2; + src += 2; + } +} + +static void +gtk_lsb_3_3 (guchar *dest, + guchar *src, + gint count) +{ + memcpy (dest, src, count * 3); +} + +static void +gtk_msb_3_3 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[0] = src[2]; + dest[1] = src[1]; + dest[2] = src[0]; + dest += 3; + src += 3; + } +} + +static void +gtk_lsb_3_4 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest += 4; + src += 3; + } +} + +static void +gtk_msb_3_4 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[1] = src[2]; + dest[2] = src[1]; + dest[3] = src[0]; + dest += 4; + src += 3; + } +} diff --git a/gtk/gtkpreview.h b/gtk/gtkpreview.h new file mode 100644 index 0000000000..2fe6ad5e08 --- /dev/null +++ b/gtk/gtkpreview.h @@ -0,0 +1,144 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_PREVIEW_H__ +#define __GTK_PREVIEW_H__ + + +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PREVIEW(obj) GTK_CHECK_CAST (obj, gtk_preview_get_type (), GtkPreview) +#define GTK_PREVIEW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_preview_get_type (), GtkPreviewClass) +#define GTK_IS_PREVIEW(obj) GTK_CHECK_TYPE (obj, gtk_preview_get_type ()) + + +typedef struct _GtkPreview GtkPreview; +typedef struct _GtkPreviewInfo GtkPreviewInfo; +typedef union _GtkDitherInfo GtkDitherInfo; +typedef struct _GtkPreviewClass GtkPreviewClass; + +struct _GtkPreview +{ + GtkWidget widget; + + guchar *buffer; + guint16 buffer_width; + guint16 buffer_height; + + guint type : 1; + guint expand : 1; +}; + +struct _GtkPreviewInfo +{ + GdkVisual *visual; + GdkColormap *cmap; + + gulong *color_pixels; + gulong *gray_pixels; + gulong *reserved_pixels; + + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + + GtkDitherInfo *dither_red; + GtkDitherInfo *dither_green; + GtkDitherInfo *dither_blue; + GtkDitherInfo *dither_gray; + guchar ***dither_matrix; + + guint nred_shades; + guint ngreen_shades; + guint nblue_shades; + guint ngray_shades; + guint nreserved; + + guint bpp; + gint cmap_alloced; + gdouble gamma; +}; + +union _GtkDitherInfo +{ + gushort s[2]; + guchar c[4]; +}; + +struct _GtkPreviewClass +{ + GtkWidgetClass parent_class; + + GtkPreviewInfo info; + + GdkImage *image; +}; + + +guint gtk_preview_get_type (void); +void gtk_preview_uninit (void); +GtkWidget* gtk_preview_new (GtkPreviewType type); +void gtk_preview_size (GtkPreview *preview, + gint width, + gint height); +void gtk_preview_put (GtkPreview *preview, + GdkWindow *window, + GdkGC *gc, + gint srcx, + gint srcy, + gint destx, + gint desty, + gint width, + gint height); +void gtk_preview_put_row (GtkPreview *preview, + guchar *src, + guchar *dest, + gint x, + gint y, + gint w); +void gtk_preview_draw_row (GtkPreview *preview, + guchar *data, + gint x, + gint y, + gint w); +void gtk_preview_set_expand (GtkPreview *preview, + gint expand); + +void gtk_preview_set_gamma (double gamma); +void gtk_preview_set_color_cube (guint nred_shades, + guint ngreen_shades, + guint nblue_shades, + guint ngray_shades); +void gtk_preview_set_install_cmap (gint install_cmap); +void gtk_preview_set_reserved (gint nreserved); +GdkVisual* gtk_preview_get_visual (void); +GdkColormap* gtk_preview_get_cmap (void); +GtkPreviewInfo* gtk_preview_get_info (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PREVIEW_H__ */ diff --git a/gtk/gtkprogressbar.c b/gtk/gtkprogressbar.c new file mode 100644 index 0000000000..8db560ba0c --- /dev/null +++ b/gtk/gtkprogressbar.c @@ -0,0 +1,259 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkprogressbar.h" + + +#define MIN_WIDTH 200 +#define MIN_HEIGHT 20 + + +static void gtk_progress_bar_class_init (GtkProgressBarClass *klass); +static void gtk_progress_bar_init (GtkProgressBar *pbar); +static void gtk_progress_bar_realize (GtkWidget *widget); +static void gtk_progress_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_progress_bar_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_progress_bar_make_pixmap (GtkProgressBar *pbar); +static void gtk_progress_bar_paint (GtkProgressBar *pbar); + + +guint +gtk_progress_bar_get_type () +{ + static guint progress_bar_type = 0; + + if (!progress_bar_type) + { + GtkTypeInfo progress_bar_info = + { + "GtkProgressBar", + sizeof (GtkProgressBar), + sizeof (GtkProgressBarClass), + (GtkClassInitFunc) gtk_progress_bar_class_init, + (GtkObjectInitFunc) gtk_progress_bar_init, + (GtkArgFunc) NULL, + }; + + progress_bar_type = gtk_type_unique (gtk_widget_get_type (), &progress_bar_info); + } + + return progress_bar_type; +} + +static void +gtk_progress_bar_class_init (GtkProgressBarClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_progress_bar_realize; + widget_class->size_allocate = gtk_progress_bar_size_allocate; + widget_class->expose_event = gtk_progress_bar_expose; +} + +static void +gtk_progress_bar_init (GtkProgressBar *pbar) +{ + GTK_WIDGET_SET_FLAGS (pbar, GTK_BASIC); + + GTK_WIDGET (pbar)->requisition.width = MIN_WIDTH; + GTK_WIDGET (pbar)->requisition.height = MIN_HEIGHT; + pbar->offscreen_pixmap = NULL; + pbar->percentage = 0; +} + + +GtkWidget* +gtk_progress_bar_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_progress_bar_get_type ())); +} + +void +gtk_progress_bar_update (GtkProgressBar *pbar, + gfloat percentage) +{ + g_return_if_fail (pbar != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); + + if (percentage < 0.0) + percentage = 0.0; + else if (percentage > 1.0) + percentage = 1.0; + + if (pbar->percentage != percentage) + { + pbar->percentage = percentage; + gtk_progress_bar_paint (pbar); + gtk_widget_queue_draw (GTK_WIDGET (pbar)); + } +} + +static void +gtk_progress_bar_realize (GtkWidget *widget) +{ + GtkProgressBar *pbar; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (widget)); + + pbar = GTK_PROGRESS_BAR (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, pbar); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); + + gtk_progress_bar_make_pixmap (pbar); +} + +static void +gtk_progress_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_progress_bar_make_pixmap (GTK_PROGRESS_BAR (widget)); + } +} + +static gint +gtk_progress_bar_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkProgressBar *pbar; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PROGRESS_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + pbar = GTK_PROGRESS_BAR (widget); + + gdk_draw_pixmap (widget->window, + widget->style->black_gc, + pbar->offscreen_pixmap, + 0, 0, 0, 0, + widget->allocation.width, + widget->allocation.height); + } + + return FALSE; +} + +static void +gtk_progress_bar_make_pixmap (GtkProgressBar *pbar) +{ + GtkWidget *widget; + + g_return_if_fail (pbar != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); + + if (GTK_WIDGET_REALIZED (pbar)) + { + widget = GTK_WIDGET (pbar); + + if (pbar->offscreen_pixmap) + gdk_pixmap_destroy (pbar->offscreen_pixmap); + + pbar->offscreen_pixmap = gdk_pixmap_new (widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + + gtk_progress_bar_paint (pbar); + } +} + +static void +gtk_progress_bar_paint (GtkProgressBar *pbar) +{ + GtkWidget *widget; + int amount; + + g_return_if_fail (pbar != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); + + if (pbar->offscreen_pixmap) + { + widget = GTK_WIDGET (pbar); + + gtk_draw_shadow (widget->style, + pbar->offscreen_pixmap, + GTK_STATE_NORMAL, GTK_SHADOW_IN, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gdk_draw_rectangle (pbar->offscreen_pixmap, + widget->style->bg_gc[GTK_STATE_ACTIVE], TRUE, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + widget->allocation.width - widget->style->klass->xthickness * 2, + widget->allocation.height - widget->style->klass->ythickness * 2); + + + amount = pbar->percentage * (widget->allocation.width - widget->style->klass->xthickness * 2); + if (amount > 0) + { + gdk_draw_rectangle (pbar->offscreen_pixmap, + widget->style->bg_gc[GTK_STATE_PRELIGHT], TRUE, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + amount, + widget->allocation.height - widget->style->klass->ythickness * 2); + + gtk_draw_shadow (widget->style, + pbar->offscreen_pixmap, + GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + amount, + widget->allocation.height - widget->style->klass->ythickness * 2); + } + } +} diff --git a/gtk/gtkprogressbar.h b/gtk/gtkprogressbar.h new file mode 100644 index 0000000000..e831dfb97a --- /dev/null +++ b/gtk/gtkprogressbar.h @@ -0,0 +1,64 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_PROGRESS_BAR_H__ +#define __GTK_PROGRESS_BAR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PROGRESS_BAR(obj) GTK_CHECK_CAST (obj, gtk_progress_bar_get_type (), GtkProgressBar) +#define GTK_PROGRESS_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_progress_bar_get_type (), GtkProgressBarClass) +#define GTK_IS_PROGRESS_BAR(obj) GTK_CHECK_TYPE (obj, gtk_progress_bar_get_type ()) + + +typedef struct _GtkProgressBar GtkProgressBar; +typedef struct _GtkProgressBarClass GtkProgressBarClass; + +struct _GtkProgressBar +{ + GtkWidget widget; + + GdkPixmap *offscreen_pixmap; + gfloat percentage; +}; + +struct _GtkProgressBarClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_progress_bar_get_type (void); +GtkWidget* gtk_progress_bar_new (void); +void gtk_progress_bar_update (GtkProgressBar *pbar, + gfloat percentage); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PROGRESS_BAR_H__ */ diff --git a/gtk/gtkradiobutton.c b/gtk/gtkradiobutton.c new file mode 100644 index 0000000000..0c52836e96 --- /dev/null +++ b/gtk/gtkradiobutton.c @@ -0,0 +1,321 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtklabel.h" +#include "gtkradiobutton.h" +#include "gtksignal.h" + + +#define CHECK_BUTTON_CLASS(w) GTK_CHECK_BUTTON_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_radio_button_class_init (GtkRadioButtonClass *klass); +static void gtk_radio_button_init (GtkRadioButton *radio_button); +static void gtk_radio_button_destroy (GtkObject *object); +static void gtk_radio_button_clicked (GtkButton *button); +static void gtk_radio_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area); + + +static GtkCheckButtonClass *parent_class = NULL; + + +guint +gtk_radio_button_get_type () +{ + static guint radio_button_type = 0; + + if (!radio_button_type) + { + GtkTypeInfo radio_button_info = + { + "GtkRadioButton", + sizeof (GtkRadioButton), + sizeof (GtkRadioButtonClass), + (GtkClassInitFunc) gtk_radio_button_class_init, + (GtkObjectInitFunc) gtk_radio_button_init, + (GtkArgFunc) NULL, + }; + + radio_button_type = gtk_type_unique (gtk_check_button_get_type (), &radio_button_info); + } + + return radio_button_type; +} + +static void +gtk_radio_button_class_init (GtkRadioButtonClass *class) +{ + GtkObjectClass *object_class; + GtkButtonClass *button_class; + GtkCheckButtonClass *check_button_class; + + object_class = (GtkObjectClass*) class; + button_class = (GtkButtonClass*) class; + check_button_class = (GtkCheckButtonClass*) class; + + parent_class = gtk_type_class (gtk_check_button_get_type ()); + + object_class->destroy = gtk_radio_button_destroy; + + button_class->clicked = gtk_radio_button_clicked; + + check_button_class->draw_indicator = gtk_radio_button_draw_indicator; +} + +static void +gtk_radio_button_init (GtkRadioButton *radio_button) +{ + radio_button->group = NULL; +} + +GtkWidget* +gtk_radio_button_new (GSList *group) +{ + GtkRadioButton *radio_button; + GtkRadioButton *tmp_button; + GSList *tmp_list; + + radio_button = gtk_type_new (gtk_radio_button_get_type ()); + + tmp_list = group; + radio_button->group = g_slist_prepend (group, radio_button); + + if (tmp_list) + { + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + tmp_button->group = radio_button->group; + } + } + else + { + GTK_TOGGLE_BUTTON (radio_button)->active = TRUE; + gtk_widget_set_state (GTK_WIDGET (radio_button), GTK_STATE_ACTIVE); + } + + return GTK_WIDGET (radio_button); +} + +GtkWidget* +gtk_radio_button_new_with_label (GSList *group, + const gchar *label) +{ + GtkWidget *radio_button; + GtkWidget *label_widget; + + radio_button = gtk_radio_button_new (group); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (radio_button), label_widget); + gtk_widget_show (label_widget); + + return radio_button; +} + +GtkWidget* +gtk_radio_button_new_from_widget (GtkRadioButton *group) +{ + GSList *l = NULL; + if (group) + l = gtk_radio_button_group (group); + return gtk_radio_button_new (l); +} + + +GtkWidget* +gtk_radio_button_new_with_label_from_widget (GtkRadioButton *group, + const gchar *label) +{ + GSList *l = NULL; + if (group) + l = gtk_radio_button_group (group); + return gtk_radio_button_new_with_label (l, label); +} + +GSList* +gtk_radio_button_group (GtkRadioButton *radio_button) +{ + g_return_val_if_fail (radio_button != NULL, NULL); + g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_button), NULL); + + return radio_button->group; +} + + +static void +gtk_radio_button_destroy (GtkObject *object) +{ + GtkRadioButton *radio_button; + GtkRadioButton *tmp_button; + GSList *tmp_list; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_RADIO_BUTTON (object)); + + radio_button = GTK_RADIO_BUTTON (object); + + radio_button->group = g_slist_remove (radio_button->group, radio_button); + tmp_list = radio_button->group; + + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + tmp_button->group = radio_button->group; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_radio_button_clicked (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkRadioButton *radio_button; + GtkToggleButton *tmp_button; + GtkStateType new_state; + GSList *tmp_list; + gint toggled; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_RADIO_BUTTON (button)); + + radio_button = GTK_RADIO_BUTTON (button); + toggle_button = GTK_TOGGLE_BUTTON (button); + toggled = FALSE; + + if (toggle_button->active) + { + tmp_button = NULL; + tmp_list = radio_button->group; + + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_button->active && (tmp_button != toggle_button)) + break; + + tmp_button = NULL; + } + + if (!tmp_button) + { + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + } + else + { + toggled = TRUE; + toggle_button->active = !toggle_button->active; + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + } + } + else + { + toggled = TRUE; + toggle_button->active = !toggle_button->active; + + tmp_list = radio_button->group; + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_button->active && (tmp_button != toggle_button)) + { + gtk_button_clicked (GTK_BUTTON (tmp_button)); + break; + } + } + + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + } + + if (GTK_WIDGET_STATE (button) != new_state) + gtk_widget_set_state (GTK_WIDGET (button), new_state); + if (toggled) + gtk_toggle_button_toggled (toggle_button); + gtk_widget_queue_draw (GTK_WIDGET (button)); +} + +static void +gtk_radio_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkButton *button; + GtkToggleButton *toggle_button; + GtkStateType state_type; + GtkShadowType shadow_type; + GdkPoint pts[4]; + gint width, height; + gint x, y; + + g_return_if_fail (check_button != NULL); + g_return_if_fail (GTK_IS_RADIO_BUTTON (check_button)); + + if (GTK_WIDGET_VISIBLE (check_button) && GTK_WIDGET_MAPPED (check_button)) + { + widget = GTK_WIDGET (check_button); + button = GTK_BUTTON (check_button); + toggle_button = GTK_TOGGLE_BUTTON (check_button); + + state_type = GTK_WIDGET_STATE (widget); + if ((state_type != GTK_STATE_NORMAL) && + (state_type != GTK_STATE_PRELIGHT)) + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (widget->style, widget->window, state_type); + gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); + + x = CHECK_BUTTON_CLASS (widget)->indicator_spacing + GTK_CONTAINER (widget)->border_width; + y = (widget->allocation.height - CHECK_BUTTON_CLASS (widget)->indicator_size) / 2; + width = CHECK_BUTTON_CLASS (widget)->indicator_size; + height = CHECK_BUTTON_CLASS (widget)->indicator_size; + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) && toggle_button->active) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + pts[0].x = x + width / 2; + pts[0].y = y; + pts[1].x = x + width; + pts[1].y = y + height / 2; + pts[2].x = pts[0].x; + pts[2].y = y + height; + pts[3].x = x; + pts[3].y = pts[1].y; + + gdk_draw_polygon (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], + TRUE, pts, 4); + gtk_draw_diamond (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x, y, width, height); + } +} diff --git a/gtk/gtkradiobutton.h b/gtk/gtkradiobutton.h new file mode 100644 index 0000000000..bf346c27eb --- /dev/null +++ b/gtk/gtkradiobutton.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_RADIO_BUTTON_H__ +#define __GTK_RADIO_BUTTON_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcheckbutton.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RADIO_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_radio_button_get_type (), GtkRadioButton) +#define GTK_RADIO_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_radio_button_get_type (), GtkRadioButtonClass) +#define GTK_IS_RADIO_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_radio_button_get_type ()) + + +typedef struct _GtkRadioButton GtkRadioButton; +typedef struct _GtkRadioButtonClass GtkRadioButtonClass; + +struct _GtkRadioButton +{ + GtkCheckButton check_button; + + GSList *group; +}; + +struct _GtkRadioButtonClass +{ + GtkCheckButtonClass parent_class; +}; + + +guint gtk_radio_button_get_type (void); +GtkWidget* gtk_radio_button_new (GSList *group); +GtkWidget* gtk_radio_button_new_from_widget (GtkRadioButton *group); +GtkWidget* gtk_radio_button_new_with_label (GSList *group, + const gchar *label); +GtkWidget* gtk_radio_button_new_interp (GtkRadioButton *group); +GtkWidget* gtk_radio_button_new_with_label_interp + (GtkRadioButton *group, + const gchar *label); +GSList* gtk_radio_button_group (GtkRadioButton *radio_button); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RADIO_BUTTON_H__ */ diff --git a/gtk/gtkradiomenuitem.c b/gtk/gtkradiomenuitem.c new file mode 100644 index 0000000000..edfcff6733 --- /dev/null +++ b/gtk/gtkradiomenuitem.c @@ -0,0 +1,240 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtklabel.h" +#include "gtkradiomenuitem.h" + + +static void gtk_radio_menu_item_class_init (GtkRadioMenuItemClass *klass); +static void gtk_radio_menu_item_init (GtkRadioMenuItem *radio_menu_item); +static void gtk_radio_menu_item_activate (GtkMenuItem *menu_item); +static void gtk_radio_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); + + +guint +gtk_radio_menu_item_get_type () +{ + static guint radio_menu_item_type = 0; + + if (!radio_menu_item_type) + { + GtkTypeInfo radio_menu_item_info = + { + "GtkRadioMenuItem", + sizeof (GtkRadioMenuItem), + sizeof (GtkRadioMenuItemClass), + (GtkClassInitFunc) gtk_radio_menu_item_class_init, + (GtkObjectInitFunc) gtk_radio_menu_item_init, + (GtkArgFunc) NULL, + }; + + radio_menu_item_type = gtk_type_unique (gtk_check_menu_item_get_type (), &radio_menu_item_info); + } + + return radio_menu_item_type; +} + +GtkWidget* +gtk_radio_menu_item_new (GSList *group) +{ + GtkRadioMenuItem *radio_menu_item; + GtkRadioMenuItem *tmp_menu_item; + GSList *tmp_list; + + radio_menu_item = gtk_type_new (gtk_radio_menu_item_get_type ()); + + tmp_list = group; + radio_menu_item->group = g_slist_prepend (group, radio_menu_item); + + if (tmp_list) + { + while (tmp_list) + { + tmp_menu_item = tmp_list->data; + tmp_list = tmp_list->next; + + tmp_menu_item->group = radio_menu_item->group; + } + } + else + { + GTK_CHECK_MENU_ITEM (radio_menu_item)->active = TRUE; + } + + return GTK_WIDGET (radio_menu_item); +} + +GtkWidget* +gtk_radio_menu_item_new_with_label (GSList *group, + const gchar *label) +{ + GtkWidget *radio_menu_item; + GtkWidget *label_widget; + + radio_menu_item = gtk_radio_menu_item_new (group); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (radio_menu_item), label_widget); + gtk_widget_show (label_widget); + + return radio_menu_item; +} + +GSList* +gtk_radio_menu_item_group (GtkRadioMenuItem *radio_menu_item) +{ + g_return_val_if_fail (radio_menu_item != NULL, NULL); + g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (radio_menu_item), NULL); + + return radio_menu_item->group; +} + + +static void +gtk_radio_menu_item_class_init (GtkRadioMenuItemClass *klass) +{ + GtkMenuItemClass *menu_item_class; + GtkCheckMenuItemClass *check_menu_item_class; + + menu_item_class = (GtkMenuItemClass*) klass; + check_menu_item_class = (GtkCheckMenuItemClass*) klass; + + menu_item_class->activate = gtk_radio_menu_item_activate; + + check_menu_item_class->draw_indicator = gtk_radio_menu_item_draw_indicator; +} + +static void +gtk_radio_menu_item_init (GtkRadioMenuItem *radio_menu_item) +{ + radio_menu_item->group = NULL; +} + +static void +gtk_radio_menu_item_activate (GtkMenuItem *menu_item) +{ + GtkRadioMenuItem *radio_menu_item; + GtkCheckMenuItem *check_menu_item; + GtkCheckMenuItem *tmp_menu_item; + GSList *tmp_list; + gint toggled; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (menu_item)); + + radio_menu_item = GTK_RADIO_MENU_ITEM (menu_item); + check_menu_item = GTK_CHECK_MENU_ITEM (menu_item); + toggled = FALSE; + + if (check_menu_item->active) + { + tmp_menu_item = NULL; + tmp_list = radio_menu_item->group; + + while (tmp_list) + { + tmp_menu_item = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_menu_item->active && (tmp_menu_item != check_menu_item)) + break; + + tmp_menu_item = NULL; + } + + if (tmp_menu_item) + { + toggled = TRUE; + check_menu_item->active = !check_menu_item->active; + } + } + else + { + toggled = TRUE; + check_menu_item->active = !check_menu_item->active; + + tmp_list = radio_menu_item->group; + while (tmp_list) + { + tmp_menu_item = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_menu_item->active && (tmp_menu_item != check_menu_item)) + { + gtk_menu_item_activate (GTK_MENU_ITEM (tmp_menu_item)); + break; + } + } + } + + if (toggled) + gtk_check_menu_item_toggled (check_menu_item); + gtk_widget_queue_draw (GTK_WIDGET (radio_menu_item)); +} + +static void +gtk_radio_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkStateType state_type; + GtkShadowType shadow_type; + GdkPoint pts[4]; + gint width, height; + gint x, y; + + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (check_menu_item)); + + if (GTK_WIDGET_DRAWABLE (check_menu_item)) + { + widget = GTK_WIDGET (check_menu_item); + + width = 8; + height = 8; + x = (GTK_CONTAINER (check_menu_item)->border_width + + widget->style->klass->xthickness + 2); + y = (widget->allocation.height - height) / 2; + + gdk_window_clear_area (widget->window, x, y, width, height); + + if (check_menu_item->active || + (GTK_WIDGET_STATE (check_menu_item) == GTK_STATE_PRELIGHT)) + { + state_type = GTK_WIDGET_STATE (widget); + shadow_type = GTK_SHADOW_IN; + + pts[0].x = x + width / 2; + pts[0].y = y; + pts[1].x = x + width; + pts[1].y = y + height / 2; + pts[2].x = pts[0].x; + pts[2].y = y + height; + pts[3].x = x; + pts[3].y = pts[1].y; + + gdk_draw_polygon (widget->window, + widget->style->bg_gc[state_type], + TRUE, pts, 4); + gtk_draw_diamond (widget->style, widget->window, + state_type, shadow_type, + x, y, width, height); + } + } +} diff --git a/gtk/gtkradiomenuitem.h b/gtk/gtkradiomenuitem.h new file mode 100644 index 0000000000..28abafc6b5 --- /dev/null +++ b/gtk/gtkradiomenuitem.h @@ -0,0 +1,64 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_RADIO_MENU_ITEM_H__ +#define __GTK_RADIO_MENU_ITEM_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcheckmenuitem.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RADIO_MENU_ITEM(obj) GTK_CHECK_CAST (obj, gtk_radio_menu_item_get_type (), GtkRadioMenuItem) +#define GTK_RADIO_MENU_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_radio_menu_item_get_type (), GtkRadioMenuItemClass) +#define GTK_IS_RADIO_MENU_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_radio_menu_item_get_type ()) + + +typedef struct _GtkRadioMenuItem GtkRadioMenuItem; +typedef struct _GtkRadioMenuItemClass GtkRadioMenuItemClass; + +struct _GtkRadioMenuItem +{ + GtkCheckMenuItem check_menu_item; + + GSList *group; +}; + +struct _GtkRadioMenuItemClass +{ + GtkCheckMenuItemClass parent_class; +}; + + +guint gtk_radio_menu_item_get_type (void); +GtkWidget* gtk_radio_menu_item_new (GSList *group); +GtkWidget* gtk_radio_menu_item_new_with_label (GSList *group, + const gchar *label); +GSList* gtk_radio_menu_item_group (GtkRadioMenuItem *radio_menu_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RADIO_MENU_ITEM_H__ */ diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c new file mode 100644 index 0000000000..f00bbf6838 --- /dev/null +++ b/gtk/gtkrange.c @@ -0,0 +1,1369 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include "gtkmain.h" +#include "gtkrange.h" +#include "gtksignal.h" + + +#define SCROLL_TIMER_LENGTH 20 +#define SCROLL_INITIAL_DELAY 100 +#define SCROLL_DELAY_LENGTH 300 + +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_range_class_init (GtkRangeClass *klass); +static void gtk_range_init (GtkRange *range); +static void gtk_range_destroy (GtkObject *object); +static void gtk_range_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_range_draw_focus (GtkWidget *widget); +static void gtk_range_unrealize (GtkWidget *widget); +static gint gtk_range_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_range_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_range_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_range_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_range_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_range_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_range_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_range_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_range_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_real_range_draw_trough (GtkRange *range); +static void gtk_real_range_draw_slider (GtkRange *range); +static gint gtk_real_range_timer (GtkRange *range); +static gint gtk_range_scroll (GtkRange *range); + +static void gtk_range_add_timer (GtkRange *range); +static void gtk_range_remove_timer (GtkRange *range); + +static void gtk_range_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); + +static void gtk_range_trough_hdims (GtkRange *range, + gint *left, + gint *right); +static void gtk_range_trough_vdims (GtkRange *range, + gint *top, + gint *bottom); + +static GtkWidgetClass *parent_class = NULL; + + +guint +gtk_range_get_type () +{ + static guint range_type = 0; + + if (!range_type) + { + GtkTypeInfo range_info = + { + "GtkRange", + sizeof (GtkRange), + sizeof (GtkRangeClass), + (GtkClassInitFunc) gtk_range_class_init, + (GtkObjectInitFunc) gtk_range_init, + (GtkArgFunc) NULL, + }; + + range_type = gtk_type_unique (gtk_widget_get_type (), &range_info); + } + + return range_type; +} + +static void +gtk_range_class_init (GtkRangeClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = gtk_range_destroy; + + widget_class->draw = gtk_range_draw; + widget_class->draw_focus = gtk_range_draw_focus; + widget_class->unrealize = gtk_range_unrealize; + widget_class->expose_event = gtk_range_expose; + widget_class->button_press_event = gtk_range_button_press; + widget_class->button_release_event = gtk_range_button_release; + widget_class->motion_notify_event = gtk_range_motion_notify; + widget_class->key_press_event = gtk_range_key_press; + widget_class->enter_notify_event = gtk_range_enter_notify; + widget_class->leave_notify_event = gtk_range_leave_notify; + widget_class->focus_in_event = gtk_range_focus_in; + widget_class->focus_out_event = gtk_range_focus_out; + + class->slider_width = 11; + class->stepper_size = 11; + class->stepper_slider_spacing = 1; + class->min_slider_size = 7; + class->trough = 1; + class->slider = 2; + class->step_forw = 3; + class->step_back = 4; + class->draw_background = NULL; + class->draw_trough = gtk_real_range_draw_trough; + class->draw_slider = gtk_real_range_draw_slider; + class->draw_step_forw = NULL; + class->draw_step_back = NULL; + class->trough_click = NULL; + class->trough_keys = NULL; + class->motion = NULL; + class->timer = gtk_real_range_timer; +} + +static void +gtk_range_init (GtkRange *range) +{ + range->trough = NULL; + range->slider = NULL; + range->step_forw = NULL; + range->step_back = NULL; + + range->x_click_point = 0; + range->y_click_point = 0; + range->button = 0; + range->digits = -1; + range->policy = GTK_UPDATE_CONTINUOUS; + range->scroll_type = GTK_SCROLL_NONE; + range->in_child = 0; + range->click_child = 0; + range->need_timer = FALSE; + range->timer = 0; + range->old_value = 0.0; + range->old_lower = 0.0; + range->old_upper = 0.0; + range->old_page_size = 0.0; + range->adjustment = NULL; +} + +GtkAdjustment* +gtk_range_get_adjustment (GtkRange *range) +{ + g_return_val_if_fail (range != NULL, NULL); + g_return_val_if_fail (GTK_IS_RANGE (range), NULL); + + return range->adjustment; +} + +void +gtk_range_set_update_policy (GtkRange *range, + GtkUpdateType policy) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + range->policy = policy; +} + +void +gtk_range_set_adjustment (GtkRange *range, + GtkAdjustment *adjustment) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->adjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment), (gpointer) range); + gtk_object_unref (GTK_OBJECT (range->adjustment)); + } + + range->adjustment = adjustment; + gtk_object_ref (GTK_OBJECT (range->adjustment)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_range_adjustment_changed, + (gpointer) range); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_range_adjustment_value_changed, + (gpointer) range); + + range->old_value = adjustment->value; + range->old_lower = adjustment->lower; + range->old_upper = adjustment->upper; + range->old_page_size = adjustment->page_size; + + gtk_range_adjustment_changed (range->adjustment, (gpointer) range); +} + +void +gtk_range_draw_background (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->trough && RANGE_CLASS (range)->draw_background) + (* RANGE_CLASS (range)->draw_background) (range); +} + +void +gtk_range_draw_trough (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->trough && RANGE_CLASS (range)->draw_trough) + (* RANGE_CLASS (range)->draw_trough) (range); +} + +void +gtk_range_draw_slider (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->slider && RANGE_CLASS (range)->draw_slider) + (* RANGE_CLASS (range)->draw_slider) (range); +} + +void +gtk_range_draw_step_forw (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->step_forw && RANGE_CLASS (range)->draw_step_forw) + (* RANGE_CLASS (range)->draw_step_forw) (range); +} + +void +gtk_range_draw_step_back (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->step_back && RANGE_CLASS (range)->draw_step_back) + (* RANGE_CLASS (range)->draw_step_back) (range); +} + +void +gtk_range_slider_update (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (RANGE_CLASS (range)->slider_update) + (* RANGE_CLASS (range)->slider_update) (range); +} + +gint +gtk_range_trough_click (GtkRange *range, + gint x, + gint y) +{ + g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); + g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + + if (RANGE_CLASS (range)->trough_click) + return (* RANGE_CLASS (range)->trough_click) (range, x, y); + + return GTK_TROUGH_NONE; +} + +void +gtk_range_default_hslider_update (GtkRange *range) +{ + gint left; + gint right; + gint x; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (GTK_WIDGET_REALIZED (range)) + { + gtk_range_trough_hdims (range, &left, &right); + x = left; + + if (range->adjustment->value < range->adjustment->lower) + { + range->adjustment->value = range->adjustment->lower; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else if (range->adjustment->value > range->adjustment->upper) + { + range->adjustment->value = range->adjustment->upper; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + + if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) + x += ((right - left) * (range->adjustment->value - range->adjustment->lower) / + (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); + + if (x < left) + x = left; + else if (x > right) + x = right; + + gdk_window_move (range->slider, x, GTK_WIDGET (range)->style->klass->ythickness); + } +} + +void +gtk_range_default_vslider_update (GtkRange *range) +{ + gint top; + gint bottom; + gint y; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (GTK_WIDGET_REALIZED (range)) + { + gtk_range_trough_vdims (range, &top, &bottom); + y = top; + + if (range->adjustment->value < range->adjustment->lower) + { + range->adjustment->value = range->adjustment->lower; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else if (range->adjustment->value > range->adjustment->upper) + { + range->adjustment->value = range->adjustment->upper; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + + if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) + y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) / + (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); + + if (y < top) + y = top; + else if (y > bottom) + y = bottom; + + gdk_window_move (range->slider, GTK_WIDGET (range)->style->klass->ythickness, y); + } +} + +gint +gtk_range_default_htrough_click (GtkRange *range, + gint x, + gint y) +{ + gint xthickness; + gint ythickness; + gint trough_width; + gint trough_height; + gint slider_x; + + g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); + g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + + xthickness = GTK_WIDGET (range)->style->klass->xthickness; + ythickness = GTK_WIDGET (range)->style->klass->ythickness; + + if ((x > xthickness) && (y > ythickness)) + { + gdk_window_get_size (range->trough, &trough_width, &trough_height); + + if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness)))) + { + gdk_window_get_position (range->slider, &slider_x, NULL); + + if (x < slider_x) + return GTK_TROUGH_START; + else + return GTK_TROUGH_END; + } + } + + return GTK_TROUGH_NONE; +} + +gint +gtk_range_default_vtrough_click (GtkRange *range, + gint x, + gint y) +{ + gint xthickness; + gint ythickness; + gint trough_width; + gint trough_height; + gint slider_y; + + g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); + g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + + xthickness = GTK_WIDGET (range)->style->klass->xthickness; + ythickness = GTK_WIDGET (range)->style->klass->ythickness; + + if ((x > xthickness) && (y > ythickness)) + { + gdk_window_get_size (range->trough, &trough_width, &trough_height); + + if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness)))) + { + gdk_window_get_position (range->slider, NULL, &slider_y); + + if (y < slider_y) + return GTK_TROUGH_START; + else + return GTK_TROUGH_END; + } + } + + return GTK_TROUGH_NONE; +} + +void +gtk_range_default_hmotion (GtkRange *range, + gint xdelta, + gint ydelta) +{ + gdouble old_value; + gint left, right; + gint slider_x, slider_y; + gint new_pos; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + range = GTK_RANGE (range); + + gdk_window_get_position (range->slider, &slider_x, &slider_y); + gtk_range_trough_hdims (range, &left, &right); + + if (left == right) + return; + + new_pos = slider_x + xdelta; + + if (new_pos < left) + new_pos = left; + else if (new_pos > right) + new_pos = right; + + old_value = range->adjustment->value; + range->adjustment->value = ((range->adjustment->upper - + range->adjustment->lower - + range->adjustment->page_size) * + (new_pos - left) / (right - left) + + range->adjustment->lower); + + if (range->digits >= 0) + { + char buffer[64]; + + sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); + sscanf (buffer, "%f", &range->adjustment->value); + } + + if (old_value != range->adjustment->value) + { + if (range->policy == GTK_UPDATE_CONTINUOUS) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + if (range->policy == GTK_UPDATE_DELAYED) + { + gtk_range_remove_timer (range); + range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + } + } + } +} + +void +gtk_range_default_vmotion (GtkRange *range, + gint xdelta, + gint ydelta) +{ + gdouble old_value; + gint top, bottom; + gint slider_x, slider_y; + gint new_pos; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + range = GTK_RANGE (range); + + gdk_window_get_position (range->slider, &slider_x, &slider_y); + gtk_range_trough_vdims (range, &top, &bottom); + + if (bottom == top) + return; + + new_pos = slider_y + ydelta; + + if (new_pos < top) + new_pos = top; + else if (new_pos > bottom) + new_pos = bottom; + + old_value = range->adjustment->value; + range->adjustment->value = ((range->adjustment->upper - + range->adjustment->lower - + range->adjustment->page_size) * + (new_pos - top) / (bottom - top) + + range->adjustment->lower); + + if (range->digits >= 0) + { + char buffer[64]; + + sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); + sscanf (buffer, "%f", &range->adjustment->value); + } + + if (old_value != range->adjustment->value) + { + if (range->policy == GTK_UPDATE_CONTINUOUS) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + if (range->policy == GTK_UPDATE_DELAYED) + { + gtk_range_remove_timer (range); + range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + } + } + } +} + +gfloat +gtk_range_calc_value (GtkRange *range, + gint position) +{ + return 0.0; +} + + +static void +gtk_range_destroy (GtkObject *object) +{ + GtkRange *range; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_RANGE (object)); + + range = GTK_RANGE (object); + + if (range->adjustment) + gtk_object_unref (GTK_OBJECT (range->adjustment)); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_range_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + range = GTK_RANGE (widget); + + gtk_range_draw_background (range); + gtk_range_draw_trough (range); + gtk_range_draw_slider (range); + gtk_range_draw_step_forw (range); + gtk_range_draw_step_back (range); + } +} + +static void +gtk_range_draw_focus (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_range_draw_trough (GTK_RANGE (widget)); +} + +static void +gtk_range_unrealize (GtkWidget *widget) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + gtk_style_detach (widget->style); + + if (range->slider) + gdk_window_destroy (range->slider); + if (range->trough) + gdk_window_destroy (range->trough); + if (range->step_forw) + gdk_window_destroy (range->step_forw); + if (range->step_back) + gdk_window_destroy (range->step_back); + if (widget->window) + gdk_window_destroy (widget->window); + + range->slider = NULL; + range->trough = NULL; + range->step_forw = NULL; + range->step_back = NULL; + widget->window = NULL; +} + +static gint +gtk_range_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (event->window == range->trough) + { + gtk_range_draw_trough (range); + } + else if (event->window == widget->window) + { + gtk_range_draw_background (range); + } + else if (event->window == range->slider) + { + gtk_range_draw_slider (range); + } + else if (event->window == range->step_forw) + { + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + gtk_range_draw_step_back (range); + } + return FALSE; +} + +static gint +gtk_range_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkRange *range; + gint trough_part; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + range = GTK_RANGE (widget); + if (!range->button) + { + gtk_grab_add (widget); + + range->button = event->button; + range->x_click_point = event->x; + range->y_click_point = event->y; + + if (event->window == range->trough) + { + range->click_child = RANGE_CLASS (range)->trough; + + trough_part = gtk_range_trough_click (range, event->x, event->y); + + range->scroll_type = GTK_SCROLL_NONE; + if (trough_part == GTK_TROUGH_START) + range->scroll_type = GTK_SCROLL_PAGE_BACKWARD; + else if (trough_part == GTK_TROUGH_END) + range->scroll_type = GTK_SCROLL_PAGE_FORWARD; + + if (range->scroll_type != GTK_SCROLL_NONE) + { + gtk_range_scroll (range); + gtk_range_add_timer (range); + } + } + else if (event->window == range->slider) + { + range->click_child = RANGE_CLASS (range)->slider; + range->scroll_type = GTK_SCROLL_NONE; + } + else if (event->window == range->step_forw) + { + range->click_child = RANGE_CLASS (range)->step_forw; + range->scroll_type = GTK_SCROLL_STEP_FORWARD; + + gtk_range_scroll (range); + gtk_range_add_timer (range); + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + range->click_child = RANGE_CLASS (range)->step_back; + range->scroll_type = GTK_SCROLL_STEP_BACKWARD; + + gtk_range_scroll (range); + gtk_range_add_timer (range); + gtk_range_draw_step_back (range); + } + } + + return FALSE; +} + +static gint +gtk_range_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (range->button == event->button) + { + gtk_grab_remove (widget); + + range->button = 0; + range->x_click_point = -1; + range->y_click_point = -1; + + if (range->click_child == RANGE_CLASS (range)->slider) + { + if (range->policy == GTK_UPDATE_DELAYED) + gtk_range_remove_timer (range); + + if ((range->policy != GTK_UPDATE_CONTINUOUS) && + (range->old_value != range->adjustment->value)) + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else if ((range->click_child == RANGE_CLASS (range)->trough) || + (range->click_child == RANGE_CLASS (range)->step_forw) || + (range->click_child == RANGE_CLASS (range)->step_back)) + { + gtk_range_remove_timer (range); + + if ((range->policy != GTK_UPDATE_CONTINUOUS) && + (range->old_value != range->adjustment->value)) + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + + if (range->click_child == RANGE_CLASS (range)->step_forw) + { + range->click_child = 0; + gtk_range_draw_step_forw (range); + } + else if (range->click_child == RANGE_CLASS (range)->step_back) + { + range->click_child = 0; + gtk_range_draw_step_back (range); + } + } + + range->click_child = 0; + } + + return FALSE; +} + +static gint +gtk_range_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkRange *range; + GdkModifierType mods; + gint x, y, mask; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (range->click_child == RANGE_CLASS (range)->slider) + { + x = event->x; + y = event->y; + + if (event->is_hint || (event->window != range->slider)) + gdk_window_get_pointer (range->slider, &x, &y, &mods); + + switch (range->button) + { + case 1: + mask = GDK_BUTTON1_MASK; + break; + case 2: + mask = GDK_BUTTON2_MASK; + break; + case 3: + mask = GDK_BUTTON3_MASK; + break; + default: + mask = 0; + break; + } + + if (mods & mask) + { + if (RANGE_CLASS (range)->motion) + (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point); + } + } + + return FALSE; +} + +static gint +gtk_range_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkRange *range; + gint return_val; + GtkScrollType scroll = GTK_SCROLL_NONE; + GtkTroughType pos = GTK_TROUGH_NONE; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + return_val = FALSE; + + if (RANGE_CLASS (range)->trough_keys) + return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos); + + if (return_val) + { + if (scroll != GTK_SCROLL_NONE) + { + range->scroll_type = scroll; + gtk_range_scroll (range); + if (range->old_value != range->adjustment->value) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + switch (range->scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + gtk_range_draw_step_back (range); + break; + case GTK_SCROLL_STEP_FORWARD: + gtk_range_draw_step_forw (range); + break; + } + } + } + if (pos != GTK_TROUGH_NONE) + { + if (pos == GTK_TROUGH_START) + range->adjustment->value = range->adjustment->lower; + else + range->adjustment->value = + range->adjustment->upper - range->adjustment->page_size; + + if (range->old_value != range->adjustment->value) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), + "value_changed"); + + gtk_range_slider_update (range); + gtk_range_draw_background (range); + } + } + } + return return_val; +} + +static gint +gtk_range_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (event->window == range->trough) + { + range->in_child = RANGE_CLASS (range)->trough; + } + else if (event->window == range->slider) + { + range->in_child = RANGE_CLASS (range)->slider; + + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_slider (range); + } + else if (event->window == range->step_forw) + { + range->in_child = RANGE_CLASS (range)->step_forw; + + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + range->in_child = RANGE_CLASS (range)->step_back; + + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_back (range); + } + + return FALSE; +} + +static gint +gtk_range_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + range->in_child = 0; + + if (event->window == range->trough) + { + } + else if (event->window == range->slider) + { + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_slider (range); + } + else if (event->window == range->step_forw) + { + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_back (range); + } + + return FALSE; +} + +static gint +gtk_range_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_range_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static void +gtk_real_range_draw_trough (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->trough) + { + gtk_draw_shadow (GTK_WIDGET (range)->style, range->trough, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + 0, 0, -1, -1); + + if (GTK_WIDGET_HAS_FOCUS (range)) + gdk_draw_rectangle (GTK_WIDGET (range)->window, + GTK_WIDGET (range)->style->black_gc, + FALSE, 0, 0, + GTK_WIDGET (range)->allocation.width - 1, + GTK_WIDGET (range)->allocation.height - 1); + else if (range->trough != GTK_WIDGET (range)->window) + gdk_draw_rectangle (GTK_WIDGET (range)->window, + GTK_WIDGET (range)->style->bg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, + GTK_WIDGET (range)->allocation.width - 1, + GTK_WIDGET (range)->allocation.height - 1); + } +} + +static void +gtk_real_range_draw_slider (GtkRange *range) +{ + GtkStateType state_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->slider) + { + if ((range->in_child == RANGE_CLASS (range)->slider) || + (range->click_child == RANGE_CLASS (range)->slider)) + state_type = GTK_STATE_PRELIGHT; + else + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type); + gdk_window_clear (range->slider); + + gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider, + state_type, GTK_SHADOW_OUT, + 0, 0, -1, -1); + } +} + +static gint +gtk_real_range_timer (GtkRange *range) +{ + gint return_val; + + g_return_val_if_fail (range != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (range), FALSE); + + return_val = TRUE; + if (range->click_child == RANGE_CLASS (range)->slider) + { + if (range->policy == GTK_UPDATE_DELAYED) + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + return_val = FALSE; + } + else + { + if (!range->timer) + { + return_val = FALSE; + if (range->need_timer) + range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + else + return FALSE; + range->need_timer = FALSE; + } + + if (gtk_range_scroll (range)) + return return_val; + } + + return return_val; +} + +static gint +gtk_range_scroll (GtkRange *range) +{ + gfloat new_value; + gint return_val; + + g_return_val_if_fail (range != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (range), FALSE); + + new_value = range->adjustment->value; + return_val = TRUE; + + switch (range->scroll_type) + { + case GTK_SCROLL_NONE: + break; + + case GTK_SCROLL_STEP_BACKWARD: + new_value -= range->adjustment->step_increment; + if (new_value <= range->adjustment->lower) + { + new_value = range->adjustment->lower; + return_val = FALSE; + range->timer = 0; + } + break; + + case GTK_SCROLL_STEP_FORWARD: + new_value += range->adjustment->step_increment; + if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) + { + new_value = range->adjustment->upper - range->adjustment->page_size; + return_val = FALSE; + range->timer = 0; + } + break; + + case GTK_SCROLL_PAGE_BACKWARD: + new_value -= range->adjustment->page_increment; + if (new_value <= range->adjustment->lower) + { + new_value = range->adjustment->lower; + return_val = FALSE; + range->timer = 0; + } + break; + + case GTK_SCROLL_PAGE_FORWARD: + new_value += range->adjustment->page_increment; + if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) + { + new_value = range->adjustment->upper - range->adjustment->page_size; + return_val = FALSE; + range->timer = 0; + } + break; + } + + if (new_value != range->adjustment->value) + { + range->adjustment->value = new_value; + + if ((range->policy == GTK_UPDATE_CONTINUOUS) || + (!return_val && (range->policy == GTK_UPDATE_DELAYED))) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + } + } + + return return_val; +} + + +static void +gtk_range_add_timer (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (!range->timer) + { + range->need_timer = TRUE; + range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + } +} + +static void +gtk_range_remove_timer (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->timer) + { + gtk_timeout_remove (range->timer); + range->timer = 0; + } + range->need_timer = FALSE; +} + +static void +gtk_range_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkRange *range; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + range = GTK_RANGE (data); + + if (((range->old_lower != adjustment->lower) || + (range->old_upper != adjustment->upper) || + (range->old_page_size != adjustment->page_size)) && + (range->old_value == adjustment->value)) + { + if ((adjustment->lower == adjustment->upper) || + (range->old_lower == (range->old_upper - range->old_page_size))) + { + adjustment->value = adjustment->lower; + gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed"); + } + } + + if ((range->old_value != adjustment->value) || + (range->old_lower != adjustment->lower) || + (range->old_upper != adjustment->upper) || + (range->old_page_size != adjustment->page_size)) + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + range->old_value = adjustment->value; + range->old_lower = adjustment->lower; + range->old_upper = adjustment->upper; + range->old_page_size = adjustment->page_size; + } +} + +static void +gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkRange *range; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + range = GTK_RANGE (data); + + if (range->old_value != adjustment->value) + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + range->old_value = adjustment->value; + } +} + + +static void +gtk_range_trough_hdims (GtkRange *range, + gint *left, + gint *right) +{ + gint trough_width; + gint slider_length; + gint tmp_width; + gint tleft; + gint tright; + + g_return_if_fail (range != NULL); + + gdk_window_get_size (range->trough, &trough_width, NULL); + gdk_window_get_size (range->slider, &slider_length, NULL); + + tleft = GTK_WIDGET (range)->style->klass->xthickness; + tright = trough_width - slider_length - GTK_WIDGET (range)->style->klass->xthickness; + + if (range->step_back) + { + gdk_window_get_size (range->step_back, &tmp_width, NULL); + tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (range->step_forw) + { + gdk_window_get_size (range->step_forw, &tmp_width, NULL); + tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (left) + *left = tleft; + if (right) + *right = tright; +} + +static void +gtk_range_trough_vdims (GtkRange *range, + gint *top, + gint *bottom) +{ + gint trough_height; + gint slider_length; + gint tmp_height; + gint ttop; + gint tbottom; + + g_return_if_fail (range != NULL); + + gdk_window_get_size (range->trough, NULL, &trough_height); + gdk_window_get_size (range->slider, NULL, &slider_length); + + ttop = GTK_WIDGET (range)->style->klass->xthickness; + tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->klass->ythickness; + + if (range->step_back) + { + gdk_window_get_size (range->step_back, NULL, &tmp_height); + ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (range->step_forw) + { + gdk_window_get_size (range->step_forw, NULL, &tmp_height); + tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (top) + *top = ttop; + if (bottom) + *bottom = tbottom; +} diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h new file mode 100644 index 0000000000..47ff50a36c --- /dev/null +++ b/gtk/gtkrange.h @@ -0,0 +1,144 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_RANGE_H__ +#define __GTK_RANGE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkadjustment.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RANGE(obj) GTK_CHECK_CAST (obj, gtk_range_get_type (), GtkRange) +#define GTK_RANGE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_range_get_type (), GtkRangeClass) +#define GTK_IS_RANGE(obj) GTK_CHECK_TYPE (obj, gtk_range_get_type ()) + + +typedef struct _GtkRange GtkRange; +typedef struct _GtkRangeClass GtkRangeClass; + +struct _GtkRange +{ + GtkWidget widget; + + GdkWindow *trough; + GdkWindow *slider; + GdkWindow *step_forw; + GdkWindow *step_back; + + gint16 x_click_point; + gint16 y_click_point; + + guint8 button; + gint8 digits; + guint policy : 2; + guint scroll_type : 3; + guint in_child : 3; + guint click_child : 3; + guint need_timer : 1; + + guint32 timer; + + gfloat old_value; + gfloat old_lower; + gfloat old_upper; + gfloat old_page_size; + + GtkAdjustment *adjustment; +}; + +struct _GtkRangeClass +{ + GtkWidgetClass parent_class; + + gint slider_width; + gint stepper_size; + gint stepper_slider_spacing; + gint min_slider_size; + + guint8 trough; + guint8 slider; + guint8 step_forw; + guint8 step_back; + + void (* draw_background) (GtkRange *range); + void (* draw_trough) (GtkRange *range); + void (* draw_slider) (GtkRange *range); + void (* draw_step_forw) (GtkRange *range); + void (* draw_step_back) (GtkRange *range); + void (* slider_update) (GtkRange *range); + gint (* trough_click) (GtkRange *range, + gint x, + gint y); + gint (* trough_keys) (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *trough); + void (* motion) (GtkRange *range, + gint xdelta, + gint ydelta); + gint (* timer) (GtkRange *range); +}; + + +guint gtk_range_get_type (void); +GtkAdjustment* gtk_range_get_adjustment (GtkRange *range); +void gtk_range_set_update_policy (GtkRange *range, + GtkUpdateType policy); +void gtk_range_set_adjustment (GtkRange *range, + GtkAdjustment *adjustment); + +void gtk_range_draw_background (GtkRange *range); +void gtk_range_draw_trough (GtkRange *range); +void gtk_range_draw_slider (GtkRange *range); +void gtk_range_draw_step_forw (GtkRange *range); +void gtk_range_draw_step_back (GtkRange *range); +void gtk_range_slider_update (GtkRange *range); +gint gtk_range_trough_click (GtkRange *range, + gint x, + gint y); + +void gtk_range_default_hslider_update (GtkRange *range); +void gtk_range_default_vslider_update (GtkRange *range); +gint gtk_range_default_htrough_click (GtkRange *range, + gint x, + gint y); +gint gtk_range_default_vtrough_click (GtkRange *range, + gint x, + gint y); +void gtk_range_default_hmotion (GtkRange *range, + gint xdelta, + gint ydelta); +void gtk_range_default_vmotion (GtkRange *range, + gint xdelta, + gint ydelta); +gfloat gtk_range_calc_value (GtkRange *range, + gint position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RANGE_H__ */ diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c new file mode 100644 index 0000000000..86bc20121b --- /dev/null +++ b/gtk/gtkrc.c @@ -0,0 +1,1489 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "gtkrc.h" + + +enum { + TOKEN_EOF, + TOKEN_LEFT_CURLY, + TOKEN_RIGHT_CURLY, + TOKEN_LEFT_BRACE, + TOKEN_RIGHT_BRACE, + TOKEN_EQUAL_SIGN, + TOKEN_COMMA, + TOKEN_INTEGER, + TOKEN_FLOAT, + TOKEN_STRING, + TOKEN_SYMBOL, + TOKEN_ACTIVE, + TOKEN_BASE, + TOKEN_BG, + TOKEN_BG_PIXMAP, + TOKEN_FG, + TOKEN_FONT, + TOKEN_FONTSET, + TOKEN_INSENSITIVE, + TOKEN_NORMAL, + TOKEN_PIXMAP_PATH, + TOKEN_PRELIGHT, + TOKEN_SELECTED, + TOKEN_STYLE, + TOKEN_TEXT, + TOKEN_WIDGET, + TOKEN_WIDGET_CLASS +}; + +enum { + PARSE_OK, + PARSE_ERROR, + PARSE_SYNTAX +}; + +enum { + PARSE_START, + PARSE_COMMENT, + PARSE_STRING, + PARSE_SYMBOL, + PARSE_NUMBER +}; + + +typedef struct _GtkRcStyle GtkRcStyle; +typedef struct _GtkRcSet GtkRcSet; + +struct _GtkRcStyle +{ + int initialize; + char *name; + char *font_name; + char *fontset_name; + char *bg_pixmap_name[5]; + GtkStyle *style; +}; + +struct _GtkRcSet +{ + char *set; + GtkRcStyle *rc_style; +}; + + +static guint gtk_rc_style_hash (const char *name); +static gint gtk_rc_style_compare (const char *a, + const char *b); +static GtkRcStyle* gtk_rc_style_find (const char *name); +static GtkRcStyle* gtk_rc_styles_match (GSList *sets, + const char *path); +static gint gtk_rc_style_match (const char *set, + const char *path); +static void gtk_rc_style_init (GtkRcStyle *rc_style); +static gint gtk_rc_get_token (void); +static gint gtk_rc_simple_token (char ch); +static gint gtk_rc_symbol_token (const char *sym); +static gint gtk_rc_get_next_token (void); +static gint gtk_rc_peek_next_token (void); +static gint gtk_rc_parse_statement (void); +static gint gtk_rc_parse_style (void); +static gint gtk_rc_parse_style_option (GtkRcStyle *rc_style); +static gint gtk_rc_parse_base (GtkStyle *style); +static gint gtk_rc_parse_bg (GtkStyle *style); +static gint gtk_rc_parse_fg (GtkStyle *style); +static gint gtk_rc_parse_bg_pixmap (GtkRcStyle *rc_style); +static gint gtk_rc_parse_font (GtkRcStyle *rc_style); +static gint gtk_rc_parse_fontset (GtkRcStyle *rc_style); +static gint gtk_rc_parse_state (GtkStateType *state); +static gint gtk_rc_parse_color (GdkColor *color); +static gint gtk_rc_parse_pixmap_path (void); +static void gtk_rc_parse_pixmap_path_string (gchar *pix_path); +static char* gtk_rc_find_pixmap_in_path (gchar *pixmap_file); +static gint gtk_rc_parse_widget_style (void); +static gint gtk_rc_parse_widget_class_style (void); +static char* gtk_rc_widget_path (GtkWidget *widget); +static char* gtk_rc_widget_class_path (GtkWidget *widget); + + +static struct +{ + char *name; + int token; +} symbols[] = + { + { "ACTIVE", TOKEN_ACTIVE }, + { "base", TOKEN_BASE }, + { "bg", TOKEN_BG }, + { "bg_pixmap", TOKEN_BG_PIXMAP }, + { "fg", TOKEN_FG }, + { "font", TOKEN_FONT }, + { "fontset", TOKEN_FONTSET }, + { "INSENSITIVE", TOKEN_INSENSITIVE }, + { "NORMAL", TOKEN_NORMAL }, + { "pixmap_path", TOKEN_PIXMAP_PATH }, + { "PRELIGHT", TOKEN_PRELIGHT }, + { "SELECTED", TOKEN_SELECTED }, + { "style", TOKEN_STYLE }, + { "text", TOKEN_TEXT }, + { "widget", TOKEN_WIDGET }, + { "widget_class", TOKEN_WIDGET_CLASS }, + }; + +static int nsymbols = sizeof (symbols) / sizeof (symbols[0]); + +static struct +{ + char ch; + int token; +} simple_tokens[] = + { + { '{', TOKEN_LEFT_CURLY }, + { '}', TOKEN_RIGHT_CURLY }, + { '[', TOKEN_LEFT_BRACE }, + { ']', TOKEN_RIGHT_BRACE }, + { '=', TOKEN_EQUAL_SIGN }, + { ',', TOKEN_COMMA }, + }; + +static int nsimple_tokens = sizeof (simple_tokens) / sizeof (simple_tokens[0]); + +static FILE *input_fp = NULL; +static char *buffer = NULL; +static char *tokenbuf = NULL; +static int position = 0; +static int linenum = 1; +static int buffer_size = 1024; +static int tokenbuf_size = 1024; + +static int done; +static int cur_token; +static int next_token; + +static char *token_str; +static double token_float; +static int token_int; + +static GHashTable *rc_style_ht = NULL; +static GSList *widget_sets = NULL; +static GSList *widget_class_sets = NULL; + +#define GTK_RC_MAX_PIXMAP_PATHS 128 +static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS]; + + +void +gtk_rc_init () +{ + rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash, + (GCompareFunc) gtk_rc_style_compare); +} + +void +gtk_rc_parse (const char *filename) +{ + input_fp = fopen (filename, "r"); + if (!input_fp) + return; + + buffer = g_new (char, buffer_size + tokenbuf_size); + tokenbuf = buffer + buffer_size; + position = 0; + linenum = 1; + + cur_token = -1; + next_token = -1; + done = FALSE; + + while (!done) + { + if (gtk_rc_parse_statement () != PARSE_OK) + { + g_warning ("rc file parse error: \"%s\" line %d", + filename, linenum); + done = TRUE; + } + } + + fclose (input_fp); + + g_free (buffer); + + buffer = NULL; + tokenbuf = NULL; + position = 0; + linenum = 1; +} + +GtkStyle* +gtk_rc_get_style (GtkWidget *widget) +{ + GtkRcStyle *rc_style; + char *path; + + if (widget_sets) + { + path = gtk_rc_widget_path (widget); + if (path) + { + rc_style = gtk_rc_styles_match (widget_sets, path); + g_free (path); + + if (rc_style) + { + gtk_rc_style_init (rc_style); + return rc_style->style; + } + } + } + + if (widget_class_sets) + { + path = gtk_rc_widget_class_path (widget); + if (path) + { + rc_style = gtk_rc_styles_match (widget_class_sets, path); + g_free (path); + + if (rc_style) + { + gtk_rc_style_init (rc_style); + return rc_style->style; + } + } + } + + return widget->style; +} + +void +gtk_rc_add_widget_name_style (GtkStyle *style, + const char *pattern) +{ + GtkRcStyle *rc_style; + GtkRcSet *rc_set; + int i; + + gtk_style_ref (style); + + rc_style = g_new (GtkRcStyle, 1); + rc_style->initialize = FALSE; + rc_style->name = NULL; + rc_style->font_name = NULL; + rc_style->fontset_name = NULL; + + for (i = 0; i < 5; i++) + rc_style->bg_pixmap_name[i] = NULL; + + rc_style->style = style; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (pattern); + rc_set->rc_style = rc_style; + + widget_sets = g_slist_append (widget_sets, rc_set); +} + +void +gtk_rc_add_widget_class_style (GtkStyle *style, + const char *pattern) +{ + GtkRcStyle *rc_style; + GtkRcSet *rc_set; + int i; + + gtk_style_ref (style); + + rc_style = g_new (GtkRcStyle, 1); + rc_style->initialize = FALSE; + rc_style->name = NULL; + rc_style->font_name = NULL; + rc_style->fontset_name = NULL; + + for (i = 0; i < 5; i++) + rc_style->bg_pixmap_name[i] = NULL; + + rc_style->style = style; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (pattern); + rc_set->rc_style = rc_style; + + widget_class_sets = g_slist_append (widget_class_sets, rc_set); +} + + +static guint +gtk_rc_style_hash (const char *name) +{ + guint result; + + result = 0; + while (*name) + result += (result << 3) + *name++; + + return result; +} + +static gint +gtk_rc_style_compare (const char *a, + const char *b) +{ + return (strcmp (a, b) == 0); +} + +static GtkRcStyle* +gtk_rc_style_find (const char *name) +{ + GtkRcStyle *rc_style; + + rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name); + + return rc_style; +} + +static GtkRcStyle* +gtk_rc_styles_match (GSList *sets, + const char *path) +{ + GtkRcSet *rc_set; + + while (sets) + { + rc_set = sets->data; + sets = sets->next; + + if (gtk_rc_style_match (rc_set->set, path)) + return rc_set->rc_style; + } + + return NULL; +} + +static gint +gtk_rc_style_match (const char *set, + const char *path) +{ + char ch; + + while (1) + { + ch = *set++; + if (ch == '\0') + return (*path == '\0'); + + switch (ch) + { + case '*': + while (*set == '*') + set++; + + ch = *set++; + if (ch == '\0') + return TRUE; + + while (*path) + { + while (*path && (ch != *path)) + path++; + + if (!(*path)) + return FALSE; + + path++; + if (gtk_rc_style_match (set, path)) + return TRUE; + } + break; + + case '?': + break; + + default: + if (ch == *path) + path++; + else + return FALSE; + break; + } + } + + return TRUE; +} + +static void +gtk_rc_style_init (GtkRcStyle *rc_style) +{ + GdkFont *old_font; + gint i; + + if (rc_style->initialize) + { + rc_style->initialize = FALSE; + + if (rc_style->fontset_name) + { + old_font = rc_style->style->font; + rc_style->style->font = gdk_fontset_load (rc_style->fontset_name); + if (rc_style->style->font) + gdk_fontset_free (old_font); + else + rc_style->style->font = old_font; + } + else if (rc_style->font_name) + { + old_font = rc_style->style->font; + rc_style->style->font = gdk_font_load (rc_style->font_name); + if (rc_style->style->font) + gdk_font_free (old_font); + else + rc_style->style->font = old_font; + } + + for (i = 0; i < 5; i++) + if (rc_style->bg_pixmap_name[i]) + { + if (strcmp (rc_style->bg_pixmap_name[i], "<parent>") == 0) + rc_style->style->bg_pixmap[i] = (GdkPixmap*) GDK_PARENT_RELATIVE; + else + rc_style->style->bg_pixmap[i] = gdk_pixmap_create_from_xpm (NULL, NULL, + &rc_style->style->bg[i], + rc_style->bg_pixmap_name[i]); + } + } +} + +static gint +gtk_rc_get_token () +{ + int tokenpos; + int state; + int count; + int token; + int hex_number = FALSE; + int float_number = FALSE; + char ch; + + tokenpos = 0; + state = PARSE_START; + + while (1) + { + if (position >= (buffer_size - 1)) + position = 0; + if (!position || (buffer[position] == '\0')) + { + count = fread (buffer, sizeof (char), buffer_size - 1, input_fp); + if ((count == 0) && feof (input_fp)) + return TOKEN_EOF; + buffer[count] = '\0'; + } + + ch = buffer[position++]; + if (ch == '\n') + linenum += 1; + + switch (state) + { + case PARSE_START: + token = gtk_rc_simple_token (ch); + + if (token) + return token; + else if (ch == '#') + state = PARSE_COMMENT; + else if (ch == '"') + state = PARSE_STRING; + else if ((ch == ' ') || (ch == '\t') || (ch == '\n')) + break; + else if (ch == '.') + { + hex_number = FALSE; + float_number = TRUE; + tokenbuf[tokenpos++] = ch; + state = PARSE_NUMBER; + } + else if ((ch == '$') || (ch == '#')) + { + hex_number = TRUE; + float_number = FALSE; + state = PARSE_NUMBER; + } + else if (isdigit (ch)) + { + hex_number = FALSE; + float_number = FALSE; + tokenbuf[tokenpos++] = ch; + state = PARSE_NUMBER; + } + else + { + tokenbuf[tokenpos++] = ch; + state = PARSE_SYMBOL; + } + break; + + case PARSE_COMMENT: + if (ch == '\n') + state = PARSE_START; + break; + + case PARSE_STRING: + if (ch != '"') + { + tokenbuf[tokenpos++] = ch; + } + else + { + tokenbuf[tokenpos] = '\0'; + token_str = tokenbuf; + return TOKEN_STRING; + } + break; + + case PARSE_SYMBOL: + if ((ch != ' ') && (ch != '\t') && (ch != '\n') && + (gtk_rc_simple_token (ch) == 0)) + { + tokenbuf[tokenpos++] = ch; + } + else + { + position -= 1; + tokenbuf[tokenpos] = '\0'; + token_str = tokenbuf; + return gtk_rc_symbol_token (tokenbuf); + } + break; + + case PARSE_NUMBER: + if (isdigit (ch) || (hex_number && isxdigit (ch))) + { + tokenbuf[tokenpos++] = ch; + } + else if (!hex_number && !float_number && (ch == '.')) + { + float_number = TRUE; + tokenbuf[tokenpos++] = ch; + } + else if (!float_number && + (ch == 'x') && (tokenpos == 1) && + (tokenbuf[0] == '0')) + { + hex_number = TRUE; + tokenpos = 0; + } + else + { + position -= 1; + tokenbuf[tokenpos] = '\0'; + if (float_number) + { + sscanf (tokenbuf, "%lf", &token_float); + return TOKEN_FLOAT; + } + else + { + sscanf (tokenbuf, (hex_number ? "%x" : "%d"), &token_int); + return TOKEN_INTEGER; + } + } + break; + } + } +} + +static gint +gtk_rc_simple_token (char ch) +{ + gint i; + + for (i = 0; i < nsimple_tokens; i++) + if (simple_tokens[i].ch == ch) + return simple_tokens[i].token; + + return 0; +} + +static gint +gtk_rc_symbol_token (const char *sym) +{ + gint i; + + for (i = 0; i < nsymbols; i++) + if (strcmp (symbols[i].name, sym) == 0) + return symbols[i].token; + + return TOKEN_STRING; +} + +static gint +gtk_rc_get_next_token () +{ + if (next_token != -1) + { + cur_token = next_token; + next_token = -1; + } + else + { + cur_token = gtk_rc_get_token (); + } + + return cur_token; +} + +static gint +gtk_rc_peek_next_token () +{ + if (next_token == -1) + next_token = gtk_rc_get_token (); + + return next_token; +} + +static gint +gtk_rc_parse_statement () +{ + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + { + done = TRUE; + return PARSE_OK; + } + + error = gtk_rc_parse_style (); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_pixmap_path (); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_widget_style (); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_widget_class_style (); + + return error; +} + +static gint +gtk_rc_parse_style () +{ + GtkRcStyle *rc_style; + GtkRcStyle *parent_style; + gint token; + gint error; + gint insert; + gint i; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_STYLE) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + insert = FALSE; + rc_style = g_hash_table_lookup (rc_style_ht, token_str); + + if (!rc_style) + { + insert = TRUE; + rc_style = g_new (GtkRcStyle, 1); + rc_style->initialize = TRUE; + rc_style->name = g_strdup (token_str); + rc_style->font_name = NULL; + rc_style->fontset_name = NULL; + + for (i = 0; i < 5; i++) + rc_style->bg_pixmap_name[i] = NULL; + + rc_style->style = gtk_style_new (); + gtk_style_ref (rc_style->style); + } + + token = gtk_rc_peek_next_token (); + if (token == TOKEN_EQUAL_SIGN) + { + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + { + if (insert) + { + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return PARSE_ERROR; + } + + parent_style = g_hash_table_lookup (rc_style_ht, token_str); + if (parent_style) + { + for (i = 0; i < 5; i++) + { + rc_style->style->fg[i] = parent_style->style->fg[i]; + rc_style->style->bg[i] = parent_style->style->bg[i]; + rc_style->style->light[i] = parent_style->style->light[i]; + rc_style->style->dark[i] = parent_style->style->dark[i]; + rc_style->style->mid[i] = parent_style->style->mid[i]; + rc_style->style->text[i] = parent_style->style->text[i]; + rc_style->style->base[i] = parent_style->style->base[i]; + } + + rc_style->style->black = parent_style->style->black; + rc_style->style->white = parent_style->style->white; + + if (rc_style->fontset_name) + { + g_free (rc_style->fontset_name); + rc_style->fontset_name = g_strdup (parent_style->fontset_name); + } + else if (rc_style->font_name) + { + g_free (rc_style->font_name); + rc_style->font_name = g_strdup (parent_style->font_name); + } + + for (i = 0; i < 5; i++) + { + if (rc_style->bg_pixmap_name[i]) + g_free (rc_style->bg_pixmap_name[i]); + rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]); + } + } + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_LEFT_CURLY)) + { + if (insert) + { + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return PARSE_ERROR; + } + + while (1) + { + error = gtk_rc_parse_style_option (rc_style); + if (error == PARSE_SYNTAX) + break; + if (error == PARSE_ERROR) + { + if (insert) + { + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return error; + } + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_RIGHT_CURLY)) + { + if (insert) + { + if (rc_style->fontset_name) + g_free (rc_style->fontset_name); + else if (rc_style->font_name) + g_free (rc_style->font_name); + + for (i = 0; i < 5; i++) + if (rc_style->bg_pixmap_name[i]) + g_free (rc_style->bg_pixmap_name[i]); + + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return PARSE_ERROR; + } + + if (insert) + g_hash_table_insert (rc_style_ht, rc_style->name, rc_style); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_style_option (GtkRcStyle *rc_style) +{ + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + + error = gtk_rc_parse_base (rc_style->style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_bg (rc_style->style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_fg (rc_style->style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_bg_pixmap (rc_style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_font (rc_style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_fontset (rc_style); + + return error; +} + +static gint +gtk_rc_parse_base (GtkStyle *style) +{ + GtkStateType state; + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_BASE) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + error = gtk_rc_parse_color (&style->base[state]); + + return error; +} + +static gint +gtk_rc_parse_bg (GtkStyle *style) +{ + GtkStateType state; + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_BG) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + error = gtk_rc_parse_color (&style->bg[state]); + + return error; +} + +static gint +gtk_rc_parse_fg (GtkStyle *style) +{ + GtkStateType state; + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_FG) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + error = gtk_rc_parse_color (&style->fg[state]); + + return error; +} + +static gint +gtk_rc_parse_bg_pixmap (GtkRcStyle *rc_style) +{ + GtkStateType state; + gint token; + gint error; + gchar *pixmap_file; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_BG_PIXMAP) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + if (strcmp (token_str, "<parent>")) + pixmap_file = gtk_rc_find_pixmap_in_path (token_str); + else + pixmap_file = g_strdup(token_str); + + if (pixmap_file) + { + if (rc_style->bg_pixmap_name[state]) + g_free (rc_style->bg_pixmap_name[state]); + rc_style->bg_pixmap_name[state] = pixmap_file; + } + + return PARSE_OK; +} + +static char* +gtk_rc_find_pixmap_in_path (gchar *pixmap_file) +{ + gint i; + FILE *fp; + gchar *buf; + + for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++) + { + buf = g_malloc (strlen (pixmap_path[i]) + strlen (pixmap_file) + 2); + sprintf (buf, "%s%c%s", pixmap_path[i], '/', pixmap_file); + + fp = fopen (buf, "r"); + if (fp) + { + fclose (fp); + return buf; + } + + g_free (buf); + } + + g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d", + pixmap_file, linenum); + + return NULL; +} + +static gint +gtk_rc_parse_font (GtkRcStyle *rc_style) +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_FONT) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + if (rc_style->font_name) + g_free (rc_style->font_name); + rc_style->font_name = g_strdup (token_str); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_fontset (GtkRcStyle *rc_style) +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_FONTSET) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + if (rc_style->fontset_name) + g_free (rc_style->fontset_name); + rc_style->fontset_name = g_strdup (token_str); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_state (GtkStateType *state) +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_LEFT_BRACE) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (token == TOKEN_ACTIVE) + *state = GTK_STATE_ACTIVE; + else if (token == TOKEN_INSENSITIVE) + *state = GTK_STATE_INSENSITIVE; + else if (token == TOKEN_NORMAL) + *state = GTK_STATE_NORMAL; + else if (token == TOKEN_PRELIGHT) + *state = GTK_STATE_PRELIGHT; + else if (token == TOKEN_SELECTED) + *state = GTK_STATE_SELECTED; + else + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_RIGHT_BRACE)) + return PARSE_ERROR; + + return PARSE_OK; +} + +static gint +gtk_rc_parse_color (GdkColor *color) +{ + gint token; + gint length; + gint temp; + gchar buf[9]; + gint i, j; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + + switch (token) + { + case TOKEN_LEFT_CURLY: + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT))) + return PARSE_ERROR; + + if (token == TOKEN_FLOAT) + token_int = token_float * 65535.0; + if (token_int < 0) + token_int = 0; + if (token_int > 65535) + token_int = 65535; + + color->red = token_int; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_COMMA)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT))) + return PARSE_ERROR; + + if (token == TOKEN_FLOAT) + token_int = token_float * 65535.0; + if (token_int < 0) + token_int = 0; + if (token_int > 65535) + token_int = 65535; + + color->green = token_int; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_COMMA)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT))) + return PARSE_ERROR; + + if (token == TOKEN_FLOAT) + token_int = token_float * 65535.0; + if (token_int < 0) + token_int = 0; + if (token_int > 65535) + token_int = 65535; + + color->blue = token_int; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_RIGHT_CURLY)) + return PARSE_ERROR; + break; + + case TOKEN_STRING: + token = gtk_rc_get_next_token (); + + if (token_str[0] != '#') + return PARSE_ERROR; + + length = strlen (token_str) - 1; + if (((length % 3) != 0) || (length > 12)) + return PARSE_ERROR; + length /= 3; + + for (i = 0, j = 1; i < length; i++, j++) + buf[i] = token_str[j]; + buf[i] = '\0'; + + sscanf (buf, "%x", &temp); + color->red = temp; + + for (i = 0; i < length; i++, j++) + buf[i] = token_str[j]; + buf[i] = '\0'; + + sscanf (buf, "%x", &temp); + color->green = temp; + + for (i = 0; i < length; i++, j++) + buf[i] = token_str[j]; + buf[i] = '\0'; + + sscanf (buf, "%x", &temp); + color->blue = temp; + + if (length == 1) + { + color->red *= 4369; + color->green *= 4369; + color->blue *= 4369; + } + else if (length == 2) + { + color->red *= 257; + color->green *= 257; + color->blue *= 257; + } + else if (length == 3) + { + color->red *= 16; + color->green *= 16; + color->blue *= 16; + } + break; + + default: + return PARSE_SYNTAX; + } + + return PARSE_OK; +} + +static gint +gtk_rc_parse_pixmap_path () +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_PIXMAP_PATH) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + gtk_rc_parse_pixmap_path_string(token_str); + + return PARSE_OK; +} + +static void gtk_rc_parse_pixmap_path_string(gchar *pix_path) +{ + gchar *buf; + gint end_offset; + gint start_offset = 0; + gint path_len; + gint path_num; + + /* free the old one, or just add to the old one ? */ + for (path_num=0; pixmap_path[path_num]; path_num++) + { + g_free(pixmap_path[path_num]); + pixmap_path[path_num] = NULL; + } + + path_num = 0; + + path_len = strlen(pix_path); + + buf = g_strdup(pix_path); + + for(end_offset = 0; end_offset <= path_len; end_offset++) + { + if ( (buf[end_offset] == ':') || (end_offset == path_len) ) + { + buf[end_offset] = '\0'; + pixmap_path[path_num] = g_strdup(buf + start_offset); + path_num++; + pixmap_path[path_num] = NULL; + start_offset = end_offset + 1; + g_free(buf); + buf = g_strdup(pix_path); + } + } + g_free(buf); +} + +static gint +gtk_rc_parse_widget_style () +{ + GtkRcSet *rc_set; + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_WIDGET) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (token_str); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STYLE)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + rc_set->rc_style = gtk_rc_style_find (token_str); + if (!rc_set->rc_style) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + widget_sets = g_slist_append (widget_sets, rc_set); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_widget_class_style () +{ + GtkRcSet *rc_set; + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_WIDGET_CLASS) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (token_str); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STYLE)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + rc_set->rc_style = gtk_rc_style_find (token_str); + if (!rc_set->rc_style) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + widget_class_sets = g_slist_append (widget_class_sets, rc_set); + + return PARSE_OK; +} + +static char* +gtk_rc_widget_path (GtkWidget *widget) +{ + GtkWidget *tmp_widget; + char *path; + char *name; + int pathlength; + int namelength; + + path = NULL; + pathlength = 0; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_widget_get_name (tmp_widget); + pathlength += strlen (name); + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + pathlength += 1; + } + + path = g_new (char, pathlength + 1); + path[pathlength] = '\0'; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_widget_get_name (tmp_widget); + namelength = strlen (name); + + strncpy (&path[pathlength - namelength], name, namelength); + pathlength -= namelength; + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + { + pathlength -= 1; + path[pathlength] = '.'; + } + } + + return path; +} + +static char* +gtk_rc_widget_class_path (GtkWidget *widget) +{ + GtkWidget *tmp_widget; + char *path; + char *name; + int pathlength; + int namelength; + + path = NULL; + pathlength = 0; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget)); + pathlength += strlen (name); + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + pathlength += 1; + } + + path = g_new (char, pathlength + 1); + path[pathlength] = '\0'; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget)); + namelength = strlen (name); + + strncpy (&path[pathlength - namelength], name, namelength); + pathlength -= namelength; + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + { + pathlength -= 1; + path[pathlength] = '.'; + } + } + + return path; +} diff --git a/gtk/gtkrc.h b/gtk/gtkrc.h new file mode 100644 index 0000000000..8c761bb9e6 --- /dev/null +++ b/gtk/gtkrc.h @@ -0,0 +1,45 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_RC_H__ +#define __GTK_RC_H__ + + +#include <gtk/gtkstyle.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +void gtk_rc_init (void); +void gtk_rc_parse (const char *filename); +GtkStyle* gtk_rc_get_style (GtkWidget *widget); +void gtk_rc_add_widget_name_style (GtkStyle *style, + const char *pattern); +void gtk_rc_add_widget_class_style (GtkStyle *style, + const char *pattern); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RC_H__ */ diff --git a/gtk/gtkruler.c b/gtk/gtkruler.c new file mode 100644 index 0000000000..dad0e11f64 --- /dev/null +++ b/gtk/gtkruler.c @@ -0,0 +1,305 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkruler.h" + + +static void gtk_ruler_class_init (GtkRulerClass *klass); +static void gtk_ruler_init (GtkRuler *ruler); +static void gtk_ruler_realize (GtkWidget *widget); +static void gtk_ruler_unrealize (GtkWidget *widget); +static void gtk_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_ruler_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_ruler_make_pixmap (GtkRuler *ruler); + + +static GtkRulerMetric ruler_metrics[] = +{ + {"Pixels", "Pi", 1.0, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, + {"Inches", "In", 72.0, { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }, { 1, 2, 4, 8, 16 }}, + {"Centimeters", "Cn", 28.35, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, +}; + + +guint +gtk_ruler_get_type () +{ + static guint ruler_type = 0; + + if (!ruler_type) + { + GtkTypeInfo ruler_info = + { + "GtkRuler", + sizeof (GtkRuler), + sizeof (GtkRulerClass), + (GtkClassInitFunc) gtk_ruler_class_init, + (GtkObjectInitFunc) gtk_ruler_init, + (GtkArgFunc) NULL, + }; + + ruler_type = gtk_type_unique (gtk_widget_get_type (), &ruler_info); + } + + return ruler_type; +} + +static void +gtk_ruler_class_init (GtkRulerClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_ruler_realize; + widget_class->unrealize = gtk_ruler_unrealize; + widget_class->size_allocate = gtk_ruler_size_allocate; + widget_class->expose_event = gtk_ruler_expose; + + class->draw_ticks = NULL; + class->draw_pos = NULL; +} + +static void +gtk_ruler_init (GtkRuler *ruler) +{ + ruler->backing_store = NULL; + ruler->non_gr_exp_gc = NULL; + ruler->xsrc = 0; + ruler->ysrc = 0; + ruler->slider_size = 0; + ruler->lower = 0; + ruler->upper = 0; + ruler->position = 0; + ruler->max_size = 0; + + gtk_ruler_set_metric (ruler, GTK_PIXELS); +} + +void +gtk_ruler_set_metric (GtkRuler *ruler, + GtkMetricType metric) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + ruler->metric = &ruler_metrics[metric]; + + if (GTK_WIDGET_DRAWABLE (ruler)) + gtk_widget_queue_draw (GTK_WIDGET (ruler)); +} + +void +gtk_ruler_set_range (GtkRuler *ruler, + gfloat lower, + gfloat upper, + gfloat position, + gfloat max_size) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + ruler->lower = lower; + ruler->upper = upper; + ruler->position = position; + ruler->max_size = max_size; + + if (GTK_WIDGET_DRAWABLE (ruler)) + gtk_widget_queue_draw (GTK_WIDGET (ruler)); +} + +void +gtk_ruler_draw_ticks (GtkRuler *ruler) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + if (GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_ticks) + (* GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_ticks) (ruler); +} + +void +gtk_ruler_draw_pos (GtkRuler *ruler) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + if (GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_pos) + (* GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_pos) (ruler); +} + + +static void +gtk_ruler_realize (GtkWidget *widget) +{ + GtkRuler *ruler; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RULER (widget)); + + ruler = GTK_RULER (widget); + GTK_WIDGET_SET_FLAGS (ruler, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, ruler); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); + + gtk_ruler_make_pixmap (ruler); +} + +static void +gtk_ruler_unrealize (GtkWidget *widget) +{ + GtkRuler *ruler; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RULER (widget)); + + ruler = GTK_RULER (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + widget->window = NULL; + + if (ruler->backing_store) + gdk_pixmap_destroy (ruler->backing_store); + if (ruler->non_gr_exp_gc) + gdk_gc_destroy (ruler->non_gr_exp_gc); + + ruler->backing_store = NULL; + ruler->non_gr_exp_gc = NULL; +} + +static void +gtk_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRuler *ruler; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RULER (widget)); + + ruler = GTK_RULER (widget); + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_ruler_make_pixmap (ruler); + } +} + +static gint +gtk_ruler_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkRuler *ruler; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RULER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + ruler = GTK_RULER (widget); + + gdk_draw_rectangle (ruler->backing_store, + widget->style->bg_gc[GTK_STATE_NORMAL], + TRUE, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gtk_ruler_draw_ticks (ruler); + + gtk_draw_shadow (widget->style, ruler->backing_store, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gdk_draw_pixmap (widget->window, + ruler->non_gr_exp_gc, + ruler->backing_store, + 0, 0, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gtk_ruler_draw_pos (ruler); + } + + return FALSE; +} + +static void +gtk_ruler_make_pixmap (GtkRuler *ruler) +{ + GtkWidget *widget; + gint width; + gint height; + + widget = GTK_WIDGET (ruler); + + if (ruler->backing_store) + { + gdk_window_get_size (ruler->backing_store, &width, &height); + if ((width == widget->allocation.width) && + (height == widget->allocation.height)) + return; + + gdk_pixmap_destroy (ruler->backing_store); + } + + ruler->backing_store = gdk_pixmap_new (widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + + ruler->xsrc = 0; + ruler->ysrc = 0; + + if (!ruler->non_gr_exp_gc) + { + ruler->non_gr_exp_gc = gdk_gc_new (widget->window); + gdk_gc_set_exposures (ruler->non_gr_exp_gc, FALSE); + } +} diff --git a/gtk/gtkruler.h b/gtk/gtkruler.h new file mode 100644 index 0000000000..c74b203212 --- /dev/null +++ b/gtk/gtkruler.h @@ -0,0 +1,91 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_RULER_H__ +#define __GTK_RULER_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RULER(obj) GTK_CHECK_CAST (obj, gtk_ruler_get_type (), GtkRuler) +#define GTK_RULER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_ruler_get_type (), GtkRulerClass) +#define GTK_IS_RULER(obj) GTK_CHECK_TYPE (obj, gtk_ruler_get_type ()) + + +typedef struct _GtkRuler GtkRuler; +typedef struct _GtkRulerClass GtkRulerClass; +typedef struct _GtkRulerMetric GtkRulerMetric; + +struct _GtkRuler +{ + GtkWidget widget; + + GdkPixmap *backing_store; + GdkGC *non_gr_exp_gc; + GtkRulerMetric *metric; + gint xsrc, ysrc; + gint slider_size; + + gfloat lower; + gfloat upper; + gfloat position; + gfloat max_size; +}; + +struct _GtkRulerClass +{ + GtkWidgetClass parent_class; + + void (* draw_ticks) (GtkRuler *ruler); + void (* draw_pos) (GtkRuler *ruler); +}; + +struct _GtkRulerMetric +{ + gchar *metric_name; + gchar *abbrev; + gfloat pixels_per_unit; + gfloat ruler_scale[10]; + gint subdivide[5]; /* five possible modes of subdivision */ +}; + + +guint gtk_ruler_get_type (void); +void gtk_ruler_set_metric (GtkRuler *ruler, + GtkMetricType metric); +void gtk_ruler_set_range (GtkRuler *ruler, + gfloat lower, + gfloat upper, + gfloat position, + gfloat max_size); +void gtk_ruler_draw_ticks (GtkRuler *ruler); +void gtk_ruler_draw_pos (GtkRuler *ruler); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RULER_H__ */ diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c new file mode 100644 index 0000000000..ba2f186168 --- /dev/null +++ b/gtk/gtkscale.c @@ -0,0 +1,229 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <math.h> +#include "gtkcontainer.h" +#include "gtkscale.h" + + +#define SCALE_CLASS(w) GTK_SCALE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_scale_class_init (GtkScaleClass *klass); +static void gtk_scale_init (GtkScale *scale); +static void gtk_scale_destroy (GtkObject *object); +static void gtk_scale_draw_background (GtkRange *range); + + +static GtkRangeClass *parent_class = NULL; + + +guint +gtk_scale_get_type () +{ + static guint scale_type = 0; + + if (!scale_type) + { + GtkTypeInfo scale_info = + { + "GtkScale", + sizeof (GtkScale), + sizeof (GtkScaleClass), + (GtkClassInitFunc) gtk_scale_class_init, + (GtkObjectInitFunc) gtk_scale_init, + (GtkArgFunc) NULL, + }; + + scale_type = gtk_type_unique (gtk_range_get_type (), &scale_info); + } + + return scale_type; +} + +static void +gtk_scale_class_init (GtkScaleClass *class) +{ + GtkObjectClass *object_class; + GtkRangeClass *range_class; + + object_class = (GtkObjectClass*) class; + range_class = (GtkRangeClass*) class; + + parent_class = gtk_type_class (gtk_range_get_type ()); + + object_class->destroy = gtk_scale_destroy; + + range_class->draw_background = gtk_scale_draw_background; + + class->slider_length = 31; + class->value_spacing = 2; + class->draw_value = NULL; +} + +static void +gtk_scale_init (GtkScale *scale) +{ + GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS); + GTK_RANGE (scale)->digits = 1; + scale->draw_value = TRUE; + scale->value_pos = GTK_POS_TOP; +} + +void +gtk_scale_set_digits (GtkScale *scale, + gint digits) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (GTK_RANGE (scale)->digits != digits) + { + GTK_RANGE (scale)->digits = digits; + + if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale)) + gtk_widget_queue_resize (GTK_WIDGET (scale)); + } +} + +void +gtk_scale_set_draw_value (GtkScale *scale, + gint draw_value) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (scale->draw_value != draw_value) + { + scale->draw_value = (draw_value != 0); + + if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale)) + gtk_widget_queue_resize (GTK_WIDGET (scale)); + } +} + +void +gtk_scale_set_value_pos (GtkScale *scale, + GtkPositionType pos) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (scale->value_pos != pos) + { + scale->value_pos = pos; + + if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale)) + gtk_widget_queue_resize (GTK_WIDGET (scale)); + } +} + +gint +gtk_scale_value_width (GtkScale *scale) +{ + GtkRange *range; + gchar buffer[128]; + gfloat value; + gint temp; + gint return_val; + gint digits; + gint i, j; + + g_return_val_if_fail (scale != NULL, 0); + g_return_val_if_fail (GTK_IS_SCALE (scale), 0); + + return_val = 0; + if (scale->draw_value) + { + range = GTK_RANGE (scale); + + value = ABS (range->adjustment->lower); + if (value == 0) value = 1; + digits = log10 (value) + 1; + if (digits > 13) + digits = 13; + + i = 0; + if (range->adjustment->lower < 0) + buffer[i++] = '-'; + for (j = 0; j < digits; j++) + buffer[i++] = '0'; + if (GTK_RANGE (scale)->digits) + buffer[i++] = '.'; + for (j = 0; j < GTK_RANGE (scale)->digits; j++) + buffer[i++] = '0'; + buffer[i] = '\0'; + + return_val = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + + value = ABS (range->adjustment->upper); + if (value == 0) value = 1; + digits = log10 (value) + 1; + if (digits > 13) + digits = 13; + + i = 0; + if (range->adjustment->lower < 0) + buffer[i++] = '-'; + for (j = 0; j < digits; j++) + buffer[i++] = '0'; + if (GTK_RANGE (scale)->digits) + buffer[i++] = '.'; + for (j = 0; j < GTK_RANGE (scale)->digits; j++) + buffer[i++] = '0'; + buffer[i] = '\0'; + + temp = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + return_val = MAX (return_val, temp); + } + + return return_val; +} + +void +gtk_scale_draw_value (GtkScale *scale) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (SCALE_CLASS (scale)->draw_value) + (* SCALE_CLASS (scale)->draw_value) (scale); +} + + +static void +gtk_scale_destroy (GtkObject *object) +{ + GtkRange *range; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_SCALE (object)); + + range = GTK_RANGE (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_scale_draw_background (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_SCALE (range)); + + gtk_scale_draw_value (GTK_SCALE (range)); +} diff --git a/gtk/gtkscale.h b/gtk/gtkscale.h new file mode 100644 index 0000000000..6fe2e4925e --- /dev/null +++ b/gtk/gtkscale.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_SCALE_H__ +#define __GTK_SCALE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkrange.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SCALE(obj) GTK_CHECK_CAST (obj, gtk_scale_get_type (), GtkScale) +#define GTK_SCALE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_scale_get_type (), GtkScaleClass) +#define GTK_IS_SCALE(obj) GTK_CHECK_TYPE (obj, gtk_scale_get_type ()) + + +typedef struct _GtkScale GtkScale; +typedef struct _GtkScaleClass GtkScaleClass; + +struct _GtkScale +{ + GtkRange range; + + guint draw_value : 1; + guint value_pos : 2; +}; + +struct _GtkScaleClass +{ + GtkRangeClass parent_class; + + gint slider_length; + gint value_spacing; + + void (* draw_value) (GtkScale *scale); +}; + + +guint gtk_scale_get_type (void); +void gtk_scale_set_digits (GtkScale *scale, + gint digits); +void gtk_scale_set_draw_value (GtkScale *scale, + gint draw_value); +void gtk_scale_set_value_pos (GtkScale *scale, + GtkPositionType pos); +gint gtk_scale_value_width (GtkScale *scale); + +void gtk_scale_draw_value (GtkScale *scale); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SCALE_H__ */ diff --git a/gtk/gtkscrollbar.c b/gtk/gtkscrollbar.c new file mode 100644 index 0000000000..3f5088b446 --- /dev/null +++ b/gtk/gtkscrollbar.c @@ -0,0 +1,54 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkscrollbar.h" + +static void gtk_scrollbar_class_init (GtkScrollbarClass *klass); +static void gtk_scrollbar_init (GtkScrollbar *scrollbar); + +guint +gtk_scrollbar_get_type () +{ + static guint scrollbar_type = 0; + + if (!scrollbar_type) + { + GtkTypeInfo scrollbar_info = + { + "GtkScrollbar", + sizeof (GtkScrollbar), + sizeof (GtkScrollbarClass), + (GtkClassInitFunc) gtk_scrollbar_class_init, + (GtkObjectInitFunc) gtk_scrollbar_init, + (GtkArgFunc) NULL, + }; + + scrollbar_type = gtk_type_unique (gtk_range_get_type (), &scrollbar_info); + } + + return scrollbar_type; +} + +static void +gtk_scrollbar_class_init (GtkScrollbarClass *class) +{ +} + +static void +gtk_scrollbar_init (GtkScrollbar *scrollbar) +{ +} diff --git a/gtk/gtkscrollbar.h b/gtk/gtkscrollbar.h new file mode 100644 index 0000000000..14aadad1ae --- /dev/null +++ b/gtk/gtkscrollbar.h @@ -0,0 +1,58 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_SCROLLBAR_H__ +#define __GTK_SCROLLBAR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkrange.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SCROLLBAR(obj) GTK_CHECK_CAST (obj, gtk_scrollbar_get_type (), GtkScrollbar) +#define GTK_SCROLLBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_scrollbar_get_type (), GtkScrollbarClass) +#define GTK_IS_SCROLLBAR(obj) GTK_CHECK_TYPE (obj, gtk_scrollbar_get_type ()) + + +typedef struct _GtkScrollbar GtkScrollbar; +typedef struct _GtkScrollbarClass GtkScrollbarClass; + +struct _GtkScrollbar +{ + GtkRange range; +}; + +struct _GtkScrollbarClass +{ + GtkRangeClass parent_class; +}; + + +guint gtk_scrollbar_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SCROLLBAR_H__ */ diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c new file mode 100644 index 0000000000..79cc67aaf6 --- /dev/null +++ b/gtk/gtkscrolledwindow.c @@ -0,0 +1,510 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkscrolledwindow.h" +#include "gtksignal.h" + + +#define SCROLLBAR_SPACING 5 + + +static void gtk_scrolled_window_class_init (GtkScrolledWindowClass *klass); +static void gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window); +static void gtk_scrolled_window_destroy (GtkObject *object); +static void gtk_scrolled_window_map (GtkWidget *widget); +static void gtk_scrolled_window_unmap (GtkWidget *widget); +static void gtk_scrolled_window_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_scrolled_window_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_scrolled_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_scrolled_window_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_scrolled_window_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_scrolled_window_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_scrolled_window_viewport_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_scrolled_window_get_type () +{ + static guint scrolled_window_type = 0; + + if (!scrolled_window_type) + { + GtkTypeInfo scrolled_window_info = + { + "GtkScrolledWindow", + sizeof (GtkScrolledWindow), + sizeof (GtkScrolledWindowClass), + (GtkClassInitFunc) gtk_scrolled_window_class_init, + (GtkObjectInitFunc) gtk_scrolled_window_init, + (GtkArgFunc) NULL, + }; + + scrolled_window_type = gtk_type_unique (gtk_container_get_type (), &scrolled_window_info); + } + + return scrolled_window_type; +} + +static void +gtk_scrolled_window_class_init (GtkScrolledWindowClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_scrolled_window_destroy; + + widget_class->map = gtk_scrolled_window_map; + widget_class->unmap = gtk_scrolled_window_unmap; + widget_class->draw = gtk_scrolled_window_draw; + widget_class->size_request = gtk_scrolled_window_size_request; + widget_class->size_allocate = gtk_scrolled_window_size_allocate; + + container_class->add = gtk_scrolled_window_add; + container_class->remove = gtk_scrolled_window_remove; + container_class->foreach = gtk_scrolled_window_foreach; +} + +static void +gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) +{ + GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW); + + scrolled_window->hscrollbar = NULL; + scrolled_window->vscrollbar = NULL; + scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS; + scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS; +} + +GtkWidget* +gtk_scrolled_window_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment) +{ + GtkScrolledWindow *scrolled_window; + + scrolled_window = gtk_type_new (gtk_scrolled_window_get_type ()); + + scrolled_window->viewport = gtk_viewport_new (hadjustment, vadjustment); + hadjustment = gtk_viewport_get_hadjustment (GTK_VIEWPORT (scrolled_window->viewport)); + vadjustment = gtk_viewport_get_vadjustment (GTK_VIEWPORT (scrolled_window->viewport)); + + gtk_signal_connect (GTK_OBJECT (hadjustment), "changed", + (GtkSignalFunc) gtk_scrolled_window_adjustment_changed, + (gpointer) scrolled_window); + gtk_signal_connect (GTK_OBJECT (vadjustment), "changed", + (GtkSignalFunc) gtk_scrolled_window_adjustment_changed, + (gpointer) scrolled_window); + + scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment); + scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment); + + gtk_widget_set_parent (scrolled_window->viewport, GTK_WIDGET (scrolled_window)); + gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window)); + gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window)); + + gtk_widget_show (scrolled_window->viewport); + gtk_widget_show (scrolled_window->hscrollbar); + gtk_widget_show (scrolled_window->vscrollbar); + + return GTK_WIDGET (scrolled_window); +} + +GtkAdjustment* +gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window) +{ + g_return_val_if_fail (scrolled_window != NULL, NULL); + g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL); + + return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)); +} + +GtkAdjustment* +gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window) +{ + g_return_val_if_fail (scrolled_window != NULL, NULL); + g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL); + + return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)); +} + +void +gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window, + GtkPolicyType hscrollbar_policy, + GtkPolicyType vscrollbar_policy) +{ + g_return_if_fail (scrolled_window != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window)); + + if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) || + (scrolled_window->vscrollbar_policy != vscrollbar_policy)) + { + scrolled_window->hscrollbar_policy = hscrollbar_policy; + scrolled_window->vscrollbar_policy = vscrollbar_policy; + + if (GTK_WIDGET (scrolled_window)->parent) + gtk_widget_queue_resize (GTK_WIDGET (scrolled_window)); + } +} + + +static void +gtk_scrolled_window_destroy (GtkObject *object) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object)); + + scrolled_window = GTK_SCROLLED_WINDOW (object); + + gtk_widget_destroy (scrolled_window->viewport); + gtk_widget_destroy (scrolled_window->hscrollbar); + gtk_widget_destroy (scrolled_window->vscrollbar); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_scrolled_window_map (GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + + if (!GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + if (GTK_WIDGET_VISIBLE (scrolled_window->viewport) && + !GTK_WIDGET_MAPPED (scrolled_window->viewport)) + gtk_widget_map (scrolled_window->viewport); + + if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) && + !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar)) + gtk_widget_map (scrolled_window->hscrollbar); + + if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) && + !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar)) + gtk_widget_map (scrolled_window->vscrollbar); + } +} + +static void +gtk_scrolled_window_unmap (GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + + if (GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + if (GTK_WIDGET_MAPPED (scrolled_window->viewport)) + gtk_widget_unmap (scrolled_window->viewport); + + if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar)) + gtk_widget_unmap (scrolled_window->hscrollbar); + + if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar)) + gtk_widget_unmap (scrolled_window->vscrollbar); + } +} + +static void +gtk_scrolled_window_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkScrolledWindow *scrolled_window; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + if (gtk_widget_intersect (scrolled_window->viewport, area, &child_area)) + gtk_widget_draw (scrolled_window->viewport, &child_area); + + if (gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area)) + gtk_widget_draw (scrolled_window->hscrollbar, &child_area); + + if (gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area)) + gtk_widget_draw (scrolled_window->vscrollbar, &child_area); + } +} + +static void +gtk_scrolled_window_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkScrolledWindow *scrolled_window; + gint extra_height; + gint extra_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + g_return_if_fail (requisition != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + requisition->width = 0; + requisition->height = 0; + + if (GTK_WIDGET_VISIBLE (scrolled_window->viewport)) + { + gtk_widget_size_request (scrolled_window->viewport, &scrolled_window->viewport->requisition); + + requisition->width += scrolled_window->viewport->requisition.width; + requisition->height += scrolled_window->viewport->requisition.height; + } + + extra_width = 0; + extra_height = 0; + + if ((scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) + { + gtk_widget_size_request (scrolled_window->hscrollbar, + &scrolled_window->hscrollbar->requisition); + + requisition->width = MAX (requisition->width, scrolled_window->hscrollbar->requisition.width); + extra_height = SCROLLBAR_SPACING + scrolled_window->hscrollbar->requisition.height; + } + + if ((scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar)) + { + gtk_widget_size_request (scrolled_window->vscrollbar, + &scrolled_window->vscrollbar->requisition); + + requisition->height = MAX (requisition->height, scrolled_window->vscrollbar->requisition.height); + extra_width = SCROLLBAR_SPACING + scrolled_window->vscrollbar->requisition.width; + } + + requisition->width += GTK_CONTAINER (widget)->border_width * 2 + extra_width; + requisition->height += GTK_CONTAINER (widget)->border_width * 2 + extra_height; +} + +static void +gtk_scrolled_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkScrolledWindow *scrolled_window; + GtkAllocation viewport_allocation; + GtkAllocation child_allocation; + guint previous_hvis; + guint previous_vvis; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + g_return_if_fail (allocation != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (widget); + widget->allocation = *allocation; + + gtk_scrolled_window_viewport_allocate (widget, &viewport_allocation); + + gtk_container_disable_resize (GTK_CONTAINER (scrolled_window)); + + if (GTK_WIDGET_VISIBLE (scrolled_window->viewport)) + { + do { + gtk_scrolled_window_viewport_allocate (widget, &viewport_allocation); + + child_allocation.x = viewport_allocation.x + allocation->x; + child_allocation.y = viewport_allocation.y + allocation->y; + child_allocation.width = viewport_allocation.width; + child_allocation.height = viewport_allocation.height; + + previous_hvis = GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar); + previous_vvis = GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar); + + gtk_widget_size_allocate (scrolled_window->viewport, &child_allocation); + } while ((previous_hvis != GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) || + (previous_vvis != GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))); + } + + if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) + { + child_allocation.x = viewport_allocation.x; + child_allocation.y = viewport_allocation.y + viewport_allocation.height + SCROLLBAR_SPACING; + child_allocation.width = viewport_allocation.width; + child_allocation.height = scrolled_window->hscrollbar->requisition.height; + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + + gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation); + } + + if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar)) + { + child_allocation.x = viewport_allocation.x + viewport_allocation.width + SCROLLBAR_SPACING; + child_allocation.y = viewport_allocation.y; + child_allocation.width = scrolled_window->vscrollbar->requisition.width; + child_allocation.height = viewport_allocation.height; + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + + gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation); + } + + gtk_container_enable_resize (GTK_CONTAINER (scrolled_window)); +} + +static void +gtk_scrolled_window_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container)); + g_return_if_fail (widget != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (container); + gtk_container_add (GTK_CONTAINER (scrolled_window->viewport), widget); +} + +static void +gtk_scrolled_window_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container)); + g_return_if_fail (widget != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (container); + gtk_container_remove (GTK_CONTAINER (scrolled_window->viewport), widget); +} + +static void +gtk_scrolled_window_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container)); + g_return_if_fail (callback != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (container); + + (* callback) (scrolled_window->viewport, callback_data); +} + +static void +gtk_scrolled_window_viewport_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (allocation != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + allocation->x = GTK_CONTAINER (widget)->border_width; + allocation->y = GTK_CONTAINER (widget)->border_width; + allocation->width = widget->allocation.width - allocation->x * 2; + allocation->height = widget->allocation.height - allocation->y * 2; + + if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar)) + allocation->width -= scrolled_window->vscrollbar->requisition.width + SCROLLBAR_SPACING; + if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) + allocation->height -= scrolled_window->hscrollbar->requisition.height + SCROLLBAR_SPACING; +} + +static void +gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkScrolledWindow *scrolled_win; + GtkWidget *scrollbar; + gint hide_scrollbar; + gint policy; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + scrolled_win = GTK_SCROLLED_WINDOW (data); + + if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar))) + { + scrollbar = scrolled_win->hscrollbar; + policy = scrolled_win->hscrollbar_policy; + } + else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar))) + { + scrollbar = scrolled_win->vscrollbar; + policy = scrolled_win->vscrollbar_policy; + } + else + { + g_warning ("could not determine which adjustment scrollbar received change signal for"); + return; + } + + if (policy == GTK_POLICY_AUTOMATIC) + { + hide_scrollbar = FALSE; + + if ((adjustment->upper - adjustment->lower) <= adjustment->page_size) + hide_scrollbar = TRUE; + + if (hide_scrollbar) + { + if (GTK_WIDGET_VISIBLE (scrollbar)) + gtk_widget_hide (scrollbar); + } + else + { + if (!GTK_WIDGET_VISIBLE (scrollbar)) + gtk_widget_show (scrollbar); + } + } +} diff --git a/gtk/gtkscrolledwindow.h b/gtk/gtkscrolledwindow.h new file mode 100644 index 0000000000..34a01ef6cf --- /dev/null +++ b/gtk/gtkscrolledwindow.h @@ -0,0 +1,74 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_SCROLLED_WINDOW_H__ +#define __GTK_SCROLLED_WINDOW_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkhscrollbar.h> +#include <gtk/gtkvscrollbar.h> +#include <gtk/gtkviewport.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SCROLLED_WINDOW(obj) GTK_CHECK_CAST (obj, gtk_scrolled_window_get_type (), GtkScrolledWindow) +#define GTK_SCROLLED_WINDOW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_scrolled_window_get_type (), GtkScrolledWindowClass) +#define GTK_IS_SCROLLED_WINDOW(obj) GTK_CHECK_TYPE (obj, gtk_scrolled_window_get_type ()) + + +typedef struct _GtkScrolledWindow GtkScrolledWindow; +typedef struct _GtkScrolledWindowClass GtkScrolledWindowClass; + +struct _GtkScrolledWindow +{ + GtkContainer container; + + GtkWidget *viewport; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + + guint8 hscrollbar_policy; + guint8 vscrollbar_policy; +}; + +struct _GtkScrolledWindowClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_scrolled_window_get_type (void); +GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +GtkAdjustment* gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window); +GtkAdjustment* gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window); +void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window, + GtkPolicyType hscrollbar_policy, + GtkPolicyType vscrollbar_policy); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SCROLLED_WINDOW_H__ */ diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c new file mode 100644 index 0000000000..ca6f5742f4 --- /dev/null +++ b/gtk/gtkselection.c @@ -0,0 +1,1388 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ + +/* This file implements most of the work of the ICCM selection protocol. + * The code was written after an intensive study of the equivalent part + * of John Ousterhout's Tk toolkit, and does many things in much the + * same way. + * + * The one thing in the ICCM that isn't fully supported here (or in Tk) + * is side effects targets. For these to be handled properly, MULTIPLE + * targets need to be done in the order specified. This cannot be + * guaranteed with the way we do things, since if we are doing INCR + * transfers, the order will depend on the timing of the requestor. + * + * By Owen Taylor <owt1@cornell.edu> 8/16/97 + */ + +/* Terminology note: when not otherwise specified, the term "incr" below + * refers to the _sending_ part of the INCR protocol. The receiving + * portion is referred to just as "retrieval". (Terminology borrowed + * from Tk, because there is no good opposite to "retrieval" in English. + * "send" can't be made into a noun gracefully and we're already using + * "emission" for something else ....) + */ + +/* The MOTIF entry widget seems to ask for the TARGETS target, then + (regardless of the reply) ask for the TEXT target. It's slightly + possible though that it somehow thinks we are responding negatively + to the TARGETS request, though I don't really think so ... */ + +#include <stdarg.h> +#include <gdk/gdkx.h> +/* we need this for gdk_window_lookup() */ +#include "gtkmain.h" +#include "gtkselection.h" +#include "gtksignal.h" + +/* #define DEBUG_SELECTION */ + +/* Maximum size of a sent chunk, in bytes. Also the default size of + our buffers */ +#define GTK_SELECTION_MAX_SIZE 4000 + +enum { + INCR, + MULTIPLE, + TARGETS, + TIMESTAMP, + LAST_ATOM +}; + +typedef struct _GtkSelectionInfo GtkSelectionInfo; +typedef struct _GtkIncrConversion GtkIncrConversion; +typedef struct _GtkIncrInfo GtkIncrInfo; +typedef struct _GtkRetrievalInfo GtkRetrievalInfo; +typedef struct _GtkSelectionHandler GtkSelectionHandler; + +struct _GtkSelectionInfo +{ + GdkAtom selection; + GtkWidget *widget; /* widget that owns selection */ + guint32 time; /* time used to acquire selection */ +}; + +struct _GtkIncrConversion +{ + GdkAtom target; /* Requested target */ + GdkAtom property; /* Property to store in */ + GtkSelectionData data; /* The data being supplied */ + gint offset; /* Current offset in sent selection. + * -1 => All done + * -2 => Only the final (empty) portion + * left to send */ +}; + +struct _GtkIncrInfo +{ + GtkWidget *widget; /* Selection owner */ + GdkWindow *requestor; /* Requestor window - we create a GdkWindow + so we can receive events */ + GdkAtom selection; /* Selection we're sending */ + + GtkIncrConversion *conversions; /* Information about requested conversions - + * With MULTIPLE requests (benighted 1980's + * hardware idea), there can be more than + * one */ + gint num_conversions; + gint num_incrs; /* number of remaining INCR style transactions */ + guint32 idle_time; +}; + + +struct _GtkRetrievalInfo +{ + GtkWidget *widget; + GdkAtom selection; /* Selection being retrieved. */ + GdkAtom target; /* Form of selection that we requested */ + guint32 idle_time; /* Number of seconds since we last heard + from selection owner */ + guchar *buffer; /* Buffer in which to accumulate results */ + gint offset; /* Current offset in buffer, -1 indicates + not yet started */ +}; + +struct _GtkSelectionHandler +{ + GdkAtom selection; /* selection thats handled */ + GdkAtom target; /* target thats handled */ + GtkSelectionFunction function; /* callback function */ + GtkRemoveFunction remove_func; /* called when callback is removed */ + gpointer data; /* callback data */ +}; + +/* Local Functions */ +static void gtk_selection_init (void); +static gint gtk_selection_incr_timeout (GtkIncrInfo *info); +static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info); +static void gtk_selection_retrieval_report (GtkRetrievalInfo *info, + GdkAtom type, gint format, + guchar *buffer, gint length); +static GtkSelectionHandler *gtk_selection_find_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target); +static void gtk_selection_default_handler (GtkWidget *widget, + GtkSelectionData *data); + +/* Local Data */ +static gint initialize = TRUE; +static GList *current_retrievals = NULL; +static GList *current_incrs = NULL; +static GList *current_selections = NULL; + +static GdkAtom gtk_selection_atoms[LAST_ATOM]; +static const char *gtk_selection_handler_key = "selection_handlers"; + +/************************************************************* + * gtk_selection_owner_set: + * Claim ownership of a selection. + * arguments: + * widget: new selection owner + * selection: which selection + * time: time (use GDK_CURRENT_TIME only if necessary) + * + * results: + *************************************************************/ + +gint +gtk_selection_owner_set (GtkWidget *widget, + GdkAtom selection, + guint32 time) +{ + GList *tmp_list; + GtkWidget *old_owner; + GtkSelectionInfo *selection_info; + GdkWindow *window; + + if (widget == NULL) + window = NULL; + else + { + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + window = widget->window; + } + + tmp_list = current_selections; + while (tmp_list) + { + selection_info = (GtkSelectionInfo *)tmp_list->data; + + if (selection_info->selection == selection) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL) + selection_info = NULL; + else + if (selection_info->widget == widget) + return TRUE; + + if (gdk_selection_owner_set (window, selection, time, TRUE)) + { + old_owner = NULL; + + if (widget == NULL) + { + if (selection_info) + { + old_owner = selection_info->widget; + current_selections = g_list_remove_link (current_selections, + tmp_list); + g_list_free (tmp_list); + g_free (selection_info); + } + } + else + { + if (selection_info == NULL) + { + selection_info = g_new (GtkSelectionInfo, 1); + selection_info->selection = selection; + selection_info->widget = widget; + selection_info->time = time; + current_selections = g_list_append (current_selections, + selection_info); + } + else + { + old_owner = selection_info->widget; + selection_info->widget = widget; + selection_info->time = time; + } + } + /* If another widget in the application lost the selection, + * send it a GDK_SELECTION_CLEAR event, unless we're setting + * the owner to None, in which case an event will be sent */ + if (old_owner && (widget != NULL)) + { + GdkEventSelection event; + + event.type = GDK_SELECTION_CLEAR; + event.window = old_owner->window; + event.selection = selection; + event.time = time; + + gtk_widget_event (widget, (GdkEvent *) &event); + } + return TRUE; + } + else + return FALSE; +} + +/************************************************************* + * gtk_selection_add_handler: + * Add a handler for a specified selection/target pair + * + * arguments: + * widget: The widget the handler applies to + * selection: + * target: + * format: Format in which this handler will return data + * function: Callback function (can be NULL) + * data: User data for callback + * + * results: + *************************************************************/ + +void +gtk_selection_add_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + GtkSelectionFunction function, + GtkRemoveFunction remove_func, + gpointer data) +{ + GList *selection_handlers; + GList *tmp_list; + GtkSelectionHandler *handler; + + g_return_if_fail (widget != NULL); + if (initialize) + gtk_selection_init (); + + selection_handlers = gtk_object_get_data (GTK_OBJECT (widget), + gtk_selection_handler_key); + + /* Reuse old handler structure, if present */ + tmp_list = selection_handlers; + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + if ((handler->selection == selection) && (handler->target == target)) + { + if (handler->remove_func) + (*handler->remove_func)(handler->data); + if (function) + { + handler->function = function; + handler->remove_func = remove_func; + handler->data = data; + } + else + { + selection_handlers = g_list_remove_link (selection_handlers, + tmp_list); + g_list_free (tmp_list); + g_free (handler); + } + return; + } + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL && function) + { + handler = g_new (GtkSelectionHandler, 1); + handler->selection = selection; + handler->target = target; + handler->function = function; + handler->remove_func = remove_func; + handler->data = data; + selection_handlers = g_list_append (selection_handlers, handler); + } + + gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, + selection_handlers); +} + +/************************************************************* + * gtk_selection_remove_all: + * Removes all handlers and unsets ownership of all + * selections for a widget. Called when widget is being + * destroyed + * + * arguments: + * widget: The widget + * results: + *************************************************************/ + +void +gtk_selection_remove_all (GtkWidget *widget) +{ + GList *tmp_list; + GList *next; + GtkSelectionInfo *selection_info; + GList *selection_handlers; + GtkSelectionHandler *handler; + + /* Remove pending requests/incrs for this widget */ + + tmp_list = current_incrs; + while (tmp_list) + { + next = tmp_list->next; + if (((GtkIncrInfo *)tmp_list->data)->widget == widget) + { + current_incrs = g_list_remove_link (current_incrs, tmp_list); + /* structure will be freed in timeout */ + g_list_free (tmp_list); + } + tmp_list = next; + } + + tmp_list = current_retrievals; + while (tmp_list) + { + next = tmp_list->next; + if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget) + { + current_retrievals = g_list_remove_link (current_retrievals, + tmp_list); + /* structure will be freed in timeout */ + g_list_free (tmp_list); + } + tmp_list = next; + } + + /* Disclaim ownership of any selections */ + + tmp_list = current_selections; + while (tmp_list) + { + next = tmp_list->next; + selection_info = (GtkSelectionInfo *)tmp_list->data; + + if (selection_info->widget == widget) + { + gdk_selection_owner_set (NULL, + selection_info->selection, + GDK_CURRENT_TIME, FALSE); + current_selections = g_list_remove_link (current_selections, + tmp_list); + g_list_free (tmp_list); + g_free (selection_info); + } + + tmp_list = next; + } + + /* Now remove all handlers */ + + selection_handlers = gtk_object_get_data (GTK_OBJECT (widget), + gtk_selection_handler_key); + + tmp_list = selection_handlers; + while (tmp_list) + { + next = tmp_list->next; + handler = (GtkSelectionHandler *)tmp_list->data; + + if (handler->remove_func) + (*handler->remove_func)(handler->data); + + g_free (handler); + + tmp_list = next; + } + + g_list_free (selection_handlers); +} + +/************************************************************* + * gtk_selection_convert: + * Request the contents of a selection. When received, + * a "selection_received" signal will be generated. + * + * arguments: + * widget: The widget which acts as requestor + * selection: Which selection to get + * target: Form of information desired (e.g., STRING) + * time: Time of request (usually of triggering event) + * In emergency, you could use GDK_CURRENT_TIME + * + * results: + * TRUE if requested succeeded. FALSE if we could not process + * request. (e.g., there was already a request in process for + * this widget). + *************************************************************/ + +gint +gtk_selection_convert (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GtkRetrievalInfo *info; + GList *tmp_list; + GdkWindow *owner_window; + + g_return_val_if_fail (widget != NULL, FALSE); + + if (initialize) + gtk_selection_init (); + + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + /* Check to see if there are already any retrievals in progress for + this widget. If we changed GDK to use the selection for the + window property in which to store the retrieved information, then + we could support multiple retrievals for different selections. + This might be useful for DND. */ + + tmp_list = current_retrievals; + while (tmp_list) + { + info = (GtkRetrievalInfo *)tmp_list->data; + if (info->widget == widget) + return FALSE; + tmp_list = tmp_list->next; + } + + info = g_new (GtkRetrievalInfo, 1); + + info->widget = widget; + info->selection = selection; + info->target = target; + info->buffer = NULL; + info->offset = -1; + + /* Check if this process has current owner. If so, call handler + procedure directly to avoid deadlocks with INCR. */ + + owner_window = gdk_selection_owner_get (selection); + + if (owner_window != NULL) + { + GtkWidget *owner_widget; + GtkSelectionHandler *handler; + GtkSelectionData selection_data; + + selection_data.selection = selection; + selection_data.target = target; + selection_data.data = NULL; + selection_data.length = -1; + + gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget); + + if (owner_widget != NULL) + { + handler = gtk_selection_find_handler (owner_widget, selection, target); + if (handler) + (* handler->function)(owner_widget, + &selection_data, + handler->data); + else /* try the default handler */ + gtk_selection_default_handler (owner_widget, + &selection_data); + + gtk_selection_retrieval_report (info, + selection_data.type, + selection_data.format, + selection_data.data, + selection_data.length); + + g_free (selection_data.data); + + g_free (info); + return TRUE; + } + } + + /* Otherwise, we need to go through X */ + + current_retrievals = g_list_append (current_retrievals, info); + gdk_selection_convert (widget->window, selection, target, time); + gtk_timeout_add (1000, (GtkFunction) gtk_selection_retrieval_timeout, info); + + return TRUE; +} + +/************************************************************* + * gtk_selection_data_set: + * Store new data into a GtkSelectionData object. Should + * _only_ by called from a selection handler callback. + * Null terminates the stored data. + * arguments: + * type: the type of selection data + * format: format (number of bits in a unit) + * data: pointer to the data (will be copied) + * length: length of the data + * results: + *************************************************************/ + +void +gtk_selection_data_set (GtkSelectionData *selection_data, + GdkAtom type, + gint format, + guchar *data, + gint length) +{ + if (selection_data->data) + g_free (selection_data->data); + + selection_data->type = type; + selection_data->format = format; + + if (data) + { + selection_data->data = g_new (guchar, length+1); + memcpy (selection_data->data, data, length); + selection_data->data[length] = 0; + } + else + selection_data->data = NULL; + + selection_data->length = length; +} + +/************************************************************* + * gtk_selection_init: + * Initialize local variables + * arguments: + * + * results: + *************************************************************/ + +static void +gtk_selection_init (void) +{ + gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE); + gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE); + gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE); + gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE); +} + +/************************************************************* + * gtk_selection_clear: + * Handler for "selection_clear_event" + * arguments: + * widget: + * event: + * results: + *************************************************************/ + +gint +gtk_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ + /* FIXME: there can be a problem if we change the selection + via gtk_selection_owner_set after another client claims + the selection, but before we get the notification event. + Tk filters based on serial #'s, which aren't retained by + GTK. Filtering based on time's will be inherently + somewhat unreliable. */ + + GList *tmp_list; + GtkSelectionInfo *selection_info; + + tmp_list = current_selections; + while (tmp_list) + { + selection_info = (GtkSelectionInfo *)tmp_list->data; + + if ((selection_info->selection == event->selection) && + (selection_info->widget == widget)) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL || selection_info->time > event->time) + return TRUE; + + current_selections = g_list_remove_link (current_selections, tmp_list); + g_list_free (tmp_list); + g_free (selection_info); + + return TRUE; +} + + +/************************************************************* + * gtk_selection_request: + * Handler for "selection_request_event" + * arguments: + * widget: + * event: + * results: + *************************************************************/ + +gint +gtk_selection_request (GtkWidget *widget, + GdkEventSelection *event) +{ + GtkIncrInfo *info; + GtkSelectionHandler *handler; + GList *tmp_list; + guchar *mult_atoms; + int i; + + /* Check if we own selection */ + + tmp_list = current_selections; + while (tmp_list) + { + GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data; + + if ((selection_info->selection == event->selection) && + (selection_info->widget == widget)) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL) + return FALSE; + + info = g_new(GtkIncrInfo, 1); + + info->widget = widget; + info->selection = event->selection; + info->num_incrs = 0; + + /* Create GdkWindow structure for the requestor */ + + info->requestor = gdk_window_lookup (event->requestor); + if (!info->requestor) + info->requestor = gdk_window_foreign_new (event->requestor); + + /* Determine conversions we need to perform */ + + if (event->target == gtk_selection_atoms[MULTIPLE]) + { + GdkAtom type; + gint format; + gint length; + + mult_atoms = NULL; + if (!gdk_property_get (info->requestor, event->property, GDK_SELECTION_TYPE_ATOM, + 0, GTK_SELECTION_MAX_SIZE, FALSE, + &type, &format, &length, &mult_atoms) || + type != GDK_SELECTION_TYPE_ATOM || format != 8*sizeof(GdkAtom)) + { + gdk_selection_send_notify (event->requestor, event->selection, + event->target, GDK_NONE, event->time); + g_free (mult_atoms); + g_free (info); + return TRUE; + } + + info->num_conversions = length / (2*sizeof (GdkAtom)); + info->conversions = g_new (GtkIncrConversion, info->num_conversions); + + for (i=0; i<info->num_conversions; i++) + { + info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i]; + info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1]; + } + } + else /* only a single conversion */ + { + info->conversions = g_new (GtkIncrConversion, 1); + info->num_conversions = 1; + info->conversions[0].target = event->target; + info->conversions[0].property = event->property; + mult_atoms = (guchar *)info->conversions; + } + + /* Loop through conversions and determine which of these are big + enough to require doing them via INCR */ + for (i=0; i<info->num_conversions; i++) + { + GtkSelectionData data; + gint items; + + data.selection = event->selection; + data.target = info->conversions[i].target; + data.data = NULL; + data.length = -1; + +#ifdef DEBUG_SELECTION + g_print("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)\n", + event->selection, info->conversions[i].target, + gdk_atom_name(info->conversions[i].target), + event->requestor, event->property); +#endif + + handler = gtk_selection_find_handler (widget, event->selection, + info->conversions[i].target); + if (handler) + (* handler->function)(widget, &data, handler->data); + else + gtk_selection_default_handler (widget, &data); + + if (data.length < 0) + { + ((GdkAtom *)mult_atoms)[2*i+1] = GDK_NONE; + info->conversions[i].property = GDK_NONE; + continue; + } + + g_return_val_if_fail ((data.format >= 8) + && (data.format % 8 == 0), FALSE) + + items = (data.length + data.format/8 - 1) / (data.format/8); + + if (data.length > GTK_SELECTION_MAX_SIZE) + { + /* Sending via INCR */ + + info->conversions[i].offset = 0; + info->conversions[i].data = data; + info->num_incrs++; + + gdk_property_change (info->requestor, + info->conversions[i].property, + gtk_selection_atoms[INCR], + 8*sizeof (GdkAtom), + GDK_PROP_MODE_REPLACE, + (guchar *)&items, 1); + } + else + { + info->conversions[i].offset = -1; + + gdk_property_change (info->requestor, + info->conversions[i].property, + data.type, + data.format, + GDK_PROP_MODE_REPLACE, + data.data, items); + + g_free (data.data); + } + } + + /* If we have some INCR's, we need to send the rest of the data in + a callback */ + + if (info->num_incrs > 0) + { + /* FIXME: this could be dangerous if window doesn't still + exist */ + +#ifdef DEBUG_SELECTION + g_print("Starting INCR...\n"); +#endif + + gdk_window_set_events (info->requestor, + gdk_window_get_events (info->requestor) | + GDK_PROPERTY_CHANGE_MASK); + current_incrs = g_list_append (current_incrs, info); + gtk_timeout_add (1000, (GtkFunction)gtk_selection_incr_timeout, info); + } + + /* If it was a MULTIPLE request, set the property to indicate which + conversions succeeded */ + if (event->target == gtk_selection_atoms[MULTIPLE]) + { + gdk_property_change (info->requestor, event->property, + GDK_SELECTION_TYPE_ATOM, 8*sizeof(GdkAtom), + GDK_PROP_MODE_REPLACE, + mult_atoms, info->num_conversions); + g_free (mult_atoms); + } + + gdk_selection_send_notify (event->requestor, event->selection, event->target, + event->property, event->time); + + if (info->num_incrs == 0) + { + g_free (info->conversions); + g_free (info); + } + + return TRUE; +} + +/************************************************************* + * gtk_selection_incr_event: + * Called whenever an PropertyNotify event occurs for an + * GdkWindow with user_data == NULL. These will be notifications + * that a window we are sending the selection to via the + * INCR protocol has deleted a property and is ready for + * more data. + * + * arguments: + * window: the requestor window + * event: the property event structure + * + * results: + *************************************************************/ + +gint +gtk_selection_incr_event (GdkWindow *window, + GdkEventProperty *event) +{ + GList *tmp_list; + GtkIncrInfo *info; + gint num_bytes; + guchar *buffer; + + int i; + + if (event->state != GDK_PROPERTY_DELETE) + return FALSE; + +#ifdef DEBUG_SELECTION + g_print("PropertyDelete, property %ld\n", event->atom); +#endif + + /* Now find the appropriate ongoing INCR */ + tmp_list = current_incrs; + while (tmp_list) + { + info = (GtkIncrInfo *)tmp_list->data; + if (info->requestor == event->window) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL) + return FALSE; + + /* Find out which target this is for */ + for (i=0; i<info->num_conversions; i++) + { + if (info->conversions[i].property == event->atom && + info->conversions[i].offset != -1) + { + info->idle_time = 0; + + if (info->conversions[i].offset == -2) /* only the last 0-length + piece*/ + { + num_bytes = 0; + buffer = NULL; + } + else + { + num_bytes = info->conversions[i].data.length - + info->conversions[i].offset; + buffer = info->conversions[i].data.data + + info->conversions[i].offset; + + if (num_bytes > GTK_SELECTION_MAX_SIZE) + { + num_bytes = GTK_SELECTION_MAX_SIZE; + info->conversions[i].offset += GTK_SELECTION_MAX_SIZE; + } + else + info->conversions[i].offset = -2; + } +#ifdef DEBUG_SELECTION + g_print("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld\n", + num_bytes, info->conversions[i].offset, + GDK_WINDOW_XWINDOW(info->requestor), event->atom); +#endif + gdk_property_change (info->requestor, event->atom, + info->conversions[i].data.type, + info->conversions[i].data.format, + GDK_PROP_MODE_REPLACE, + buffer, + (num_bytes + info->conversions[i].data.format/8 - 1) / + (info->conversions[i].data.format/8)); + + if (info->conversions[i].offset == -2) + { + g_free (info->conversions[i].data.data); + info->conversions[i].data.data = NULL; + } + + if (num_bytes == 0) + { + info->num_incrs--; + info->conversions[i].offset = -1; + } + } + break; + } + + /* Check if we're finished with all the targets */ + + if (info->num_incrs == 0) + { + current_incrs = g_list_remove_link (current_incrs, tmp_list); + g_list_free (tmp_list); + /* Let the timeout free it */ + } + + return TRUE; +} + +/************************************************************* + * gtk_selection_incr_timeout: + * Timeout callback for the sending portion of the INCR + * protocol + * arguments: + * info: Information about this incr + * results: + *************************************************************/ + +static gint +gtk_selection_incr_timeout (GtkIncrInfo *info) +{ + GList *tmp_list; + + /* Determine if retrieval has finished by checking if it still in + list of pending retrievals */ + + tmp_list = current_incrs; + while (tmp_list) + { + if (info == (GtkIncrInfo *)tmp_list->data) + break; + tmp_list = tmp_list->next; + } + + /* If retrieval is finished */ + if (!tmp_list || info->idle_time >= 5) + { + if (tmp_list && info->idle_time >= 5) + { + current_incrs = g_list_remove_link (current_incrs, tmp_list); + g_list_free (tmp_list); + } + + g_free (info->conversions); + /* FIXME: we should check if requestor window is still in use, + and if not, remove it? */ + + g_free (info); + + return FALSE; /* remove timeout */ + } + else + { + info->idle_time++; + + return TRUE; /* timeout will happen again */ + } +} + +/************************************************************* + * gtk_selection_notify: + * Handler for "selection_notify_event" signals on windows + * where a retrieval is currently in process. The selection + * owner has responded to our conversion request. + * arguments: + * widget: Widget getting signal + * event: Selection event structure + * info: Information about this retrieval + * results: + * was event handled? + *************************************************************/ + +gint +gtk_selection_notify (GtkWidget *widget, + GdkEventSelection *event) +{ + GList *tmp_list; + GtkRetrievalInfo *info; + guchar *buffer; + gint length; + GdkAtom type; + gint format; + +#ifdef DEBUG_SELECTION + g_print("Initial receipt of selection %ld, target %ld (property = %ld)\n", + event->selection, event->target, event->property); +#endif + + tmp_list = current_retrievals; + while (tmp_list) + { + info = (GtkRetrievalInfo *)tmp_list->data; + if (info->widget == widget && info->selection == event->selection) + break; + tmp_list = tmp_list->next; + } + + if (!tmp_list) /* no retrieval in progress */ + return FALSE; + + if (event->property == GDK_NONE) + { + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + /* structure will be freed in timeout */ + gtk_selection_retrieval_report (info, + GDK_NONE, 0, NULL, -1); + + return TRUE; + } + + length = gdk_selection_property_get (widget->window, &buffer, + &type, &format); + + if (type == gtk_selection_atoms[INCR]) + { + /* The remainder of the selection will come through PropertyNotify + events */ + + info->idle_time = 0; + info->offset = 0; /* Mark as OK to proceed */ + gdk_window_set_events (widget->window, + gdk_window_get_events (widget->window) + | GDK_PROPERTY_CHANGE_MASK); + } + else + { + /* We don't delete the info structure - that will happen in timeout */ + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + + info->offset = length; + gtk_selection_retrieval_report (info, + type, format, + buffer, length); + } + + gdk_property_delete (widget->window, event->property); + + g_free (buffer); + + return TRUE; +} + +/************************************************************* + * gtk_selection_property_notify: + * Handler for "property_notify_event" signals on windows + * where a retrieval is currently in process. The selection + * owner has added more data. + * arguments: + * widget: Widget getting signal + * event: Property event structure + * info: Information about this retrieval + * results: + * was event handled? + *************************************************************/ + +gint +gtk_selection_property_notify (GtkWidget *widget, + GdkEventProperty *event) +{ + GList *tmp_list; + GtkRetrievalInfo *info; + guchar *new_buffer; + int length; + GdkAtom type; + gint format; + + if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */ + (event->atom != gdk_selection_property)) /* not the right property */ + return FALSE; + +#ifdef DEBUG_SELECTION + g_print("PropertyNewValue, property %ld\n", + event->atom); +#endif + + tmp_list = current_retrievals; + while (tmp_list) + { + info = (GtkRetrievalInfo *)tmp_list->data; + if (info->widget == widget) + break; + tmp_list = tmp_list->next; + } + + if (!tmp_list) /* No retrieval in progress */ + return FALSE; + + if (info->offset < 0) /* We haven't got the SelectionNotify + for this retrieval yet */ + return FALSE; + + info->idle_time = 0; + + length = gdk_selection_property_get (widget->window, &new_buffer, + &type, &format); + gdk_property_delete (widget->window, event->atom); + + /* We could do a lot better efficiency-wise by paying attention to + what length was sent in the initial INCR transaction, instead of + doing memory allocation at every step. But its only guaranteed to + be a _lower bound_ (pretty useless!) */ + + if (length == 0 || type == GDK_NONE) /* final zero length portion */ + { + /* Info structure will be freed in timeout */ + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + gtk_selection_retrieval_report (info, + type, format, + (type == GDK_NONE) ? NULL : info->buffer, + (type == GDK_NONE) ? -1 : info->offset); + } + else /* append on newly arrived data */ + { + if (!info->buffer) + { +#ifdef DEBUG_SELECTION + g_print("Start - Adding %d bytes at offset 0\n", + length); +#endif + info->buffer = new_buffer; + info->offset = length; + } + else + { + +#ifdef DEBUG_SELECTION + g_print("Appending %d bytes at offset %d\n", + length,info->offset); +#endif + /* We copy length+1 bytes to preserve guaranteed null termination */ + info->buffer = g_realloc (info->buffer, info->offset+length+1); + memcpy (info->buffer + info->offset, new_buffer, length+1); + info->offset += length; + g_free (new_buffer); + } + } + + return TRUE; +} + +/************************************************************* + * gtk_selection_retrieval_timeout: + * Timeout callback while receiving a selection. + * arguments: + * info: Information about this retrieval + * results: + *************************************************************/ + +static gint +gtk_selection_retrieval_timeout (GtkRetrievalInfo *info) +{ + GList *tmp_list; + + /* Determine if retrieval has finished by checking if it still in + list of pending retrievals */ + + tmp_list = current_retrievals; + while (tmp_list) + { + if (info == (GtkRetrievalInfo *)tmp_list->data) + break; + tmp_list = tmp_list->next; + } + + /* If retrieval is finished */ + if (!tmp_list || info->idle_time >= 5) + { + if (tmp_list && info->idle_time >= 5) + { + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1); + } + + g_free (info->buffer); + g_free (info); + + return FALSE; /* remove timeout */ + } + else + { + info->idle_time++; + + return TRUE; /* timeout will happen again */ + } + +} + +/************************************************************* + * gtk_selection_retrieval_report: + * Emits a "selection_received" signal. + * arguments: + * info: information about the retrieval that completed + * buffer: buffer containing data (NULL => errror) + * results: + *************************************************************/ + +static void +gtk_selection_retrieval_report (GtkRetrievalInfo *info, + GdkAtom type, gint format, + guchar *buffer, gint length) +{ + GtkSelectionData data; + + data.selection = info->selection; + data.target = info->target; + data.type = type; + data.format = format; + + data.length = length; + data.data = buffer; + + gtk_signal_emit_by_name (GTK_OBJECT(info->widget), + "selection_received", &data); +} + +/************************************************************* + * gtk_selection_find_handler: + * Find handler for specified widget/selection/target + * arguments: + * widget: + * selection: + * target: + * results: + *************************************************************/ + +static GtkSelectionHandler * +gtk_selection_find_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target) +{ + GList *tmp_list; + GtkSelectionHandler *handler; + + g_return_val_if_fail (widget != NULL, FALSE); + + tmp_list = gtk_object_get_data (GTK_OBJECT (widget), + gtk_selection_handler_key); + + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + if ((handler->selection == selection) && (handler->target == target)) + return handler; + tmp_list = tmp_list->next; + } + + return NULL; +} + + +/************************************************************* + * gtk_selection_default_handler: + * Handles some default targets that exist for any widget + * If it can't fit results into buffer, returns -1. This + * won't happen in any conceivable case, since it would + * require 1000 selection targets! + * + * arguments: + * widget: selection owner + * selection: selection requested + * target: target requested + * buffer: buffer to write results into + * length: size of buffer + * type: type atom + * format: length of type's units in bits + * + * results: + * Number of bytes written to buffer, -1 if error + *************************************************************/ + +static void +gtk_selection_default_handler (GtkWidget *widget, + GtkSelectionData *data) +{ + if (data->target == gtk_selection_atoms[TIMESTAMP]) + { + /* Time which was used to obtain selection */ + GList *tmp_list; + GtkSelectionInfo *selection_info; + + tmp_list = current_selections; + while (tmp_list) + { + selection_info = (GtkSelectionInfo *)tmp_list->data; + if ((selection_info->widget == widget) && + (selection_info->selection == data->selection)) + { + gtk_selection_data_set (data, + GDK_SELECTION_TYPE_INTEGER, + sizeof (guint32)*8, + (guchar *)&selection_info->time, + sizeof (guint32)); + return; + } + + tmp_list = tmp_list->next; + } + + data->length = -1; + } + else if (data->target == gtk_selection_atoms[TARGETS]) + { + /* List of all targets supported for this widget/selection pair */ + GdkAtom *p; + gint count; + GList *tmp_list; + GtkSelectionHandler *handler; + + count = 3; + tmp_list = gtk_object_get_data (GTK_OBJECT(widget), + gtk_selection_handler_key); + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + + if (handler->selection == data->selection) + count++; + + tmp_list = tmp_list->next; + } + + data->type = GDK_SELECTION_TYPE_ATOM; + data->format = 8*sizeof (GdkAtom); + data->length = count*sizeof (GdkAtom); + + p = g_new (GdkAtom, count); + data->data = (guchar *)p; + + *p++ = gtk_selection_atoms[TIMESTAMP]; + *p++ = gtk_selection_atoms[TARGETS]; + *p++ = gtk_selection_atoms[MULTIPLE]; + + tmp_list = gtk_object_get_data (GTK_OBJECT(widget), + gtk_selection_handler_key); + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + + if (handler->selection == data->selection) + *p++ = handler->target; + + tmp_list = tmp_list->next; + } + } + else + { + data->length = -1; + } +} diff --git a/gtk/gtkselection.h b/gtk/gtkselection.h new file mode 100644 index 0000000000..18f3dc4b54 --- /dev/null +++ b/gtk/gtkselection.h @@ -0,0 +1,91 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_SELECTION_H__ +#define __GTK_SELECTION_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkenums.h> +#include <gtk/gtkwidget.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _GtkSelectionData GtkSelectioData; + +/* a callback function that provides the selection. Arguments are: + widget: selection owner + offset: offset into selection + buffer: buffer into which to store selection + length: length of buffer + bytes_after: (sizeof(selection) - offset - length ) (return) + data: callback data */ + +typedef void (*GtkSelectionFunction) (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data); + +/* Public interface */ + +gint gtk_selection_owner_set (GtkWidget *widget, + GdkAtom selection, + guint32 time); +void gtk_selection_add_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + GtkSelectionFunction function, + GtkRemoveFunction remove_func, + gpointer data); +gint gtk_selection_convert (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + guint32 time); + + +void gtk_selection_data_set (GtkSelectionData *selection_data, + GdkAtom type, + gint format, + guchar *data, + gint length); + +/* Called when a widget is destroyed */ + +void gtk_selection_remove_all (GtkWidget *widget); + +/* Event handlers */ + +gint gtk_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +gint gtk_selection_request (GtkWidget *widget, + GdkEventSelection *event); +gint gtk_selection_incr_event (GdkWindow *window, + GdkEventProperty *event); +gint gtk_selection_notify (GtkWidget *widget, + GdkEventSelection *event); +gint gtk_selection_property_notify (GtkWidget *widget, + GdkEventProperty *event); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SELECTION_H__ */ diff --git a/gtk/gtkseparator.c b/gtk/gtkseparator.c new file mode 100644 index 0000000000..6ad41ad5b0 --- /dev/null +++ b/gtk/gtkseparator.c @@ -0,0 +1,57 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkseparator.h" + + +static void gtk_separator_class_init (GtkSeparatorClass *klass); +static void gtk_separator_init (GtkSeparator *separator); + + +guint +gtk_separator_get_type () +{ + static guint separator_type = 0; + + if (!separator_type) + { + GtkTypeInfo separator_info = + { + "GtkSeparator", + sizeof (GtkSeparator), + sizeof (GtkSeparatorClass), + (GtkClassInitFunc) gtk_separator_class_init, + (GtkObjectInitFunc) gtk_separator_init, + (GtkArgFunc) NULL, + }; + + separator_type = gtk_type_unique (gtk_widget_get_type (), &separator_info); + } + + return separator_type; +} + +static void +gtk_separator_class_init (GtkSeparatorClass *class) +{ +} + +static void +gtk_separator_init (GtkSeparator *separator) +{ + GTK_WIDGET_SET_FLAGS (separator, GTK_NO_WINDOW | GTK_BASIC); +} diff --git a/gtk/gtkseparator.h b/gtk/gtkseparator.h new file mode 100644 index 0000000000..bfccd337a9 --- /dev/null +++ b/gtk/gtkseparator.h @@ -0,0 +1,58 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_SEPARATOR_H__ +#define __GTK_SEPARATOR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SEPARATOR(obj) GTK_CHECK_CAST (obj, gtk_separator_get_type (), GtkSeparator) +#define GTK_SEPARATOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_separator_get_type (), GtkSeparatorClass) +#define GTK_IS_SEPARATOR(obj) GTK_CHECK_TYPE (obj, gtk_separator_get_type ()) + + +typedef struct _GtkSeparator GtkSeparator; +typedef struct _GtkSeparatorClass GtkSeparatorClass; + +struct _GtkSeparator +{ + GtkWidget widget; +}; + +struct _GtkSeparatorClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_separator_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SEPARATOR_H__ */ diff --git a/gtk/gtksignal.c b/gtk/gtksignal.c new file mode 100644 index 0000000000..65efdb991f --- /dev/null +++ b/gtk/gtksignal.c @@ -0,0 +1,1322 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdarg.h> +#include "gtksignal.h" + + +#define MAX_PARAMS 20 +#define DONE 1 +#define RESTART 2 + +#define GTK_RUN_TYPE(x) ((x) & GTK_RUN_MASK) + + +typedef struct _GtkSignal GtkSignal; +typedef struct _GtkSignalInfo GtkSignalInfo; +typedef struct _GtkHandler GtkHandler; +typedef struct _GtkHandlerInfo GtkHandlerInfo; +typedef struct _GtkEmission GtkEmission; + +typedef void (*GtkSignalMarshaller0) (GtkObject *object, + gpointer data); + +struct _GtkSignalInfo +{ + gchar *name; + gint object_type; + gint signal_type; +}; + +struct _GtkSignal +{ + GtkSignalInfo info; + gint function_offset; + GtkSignalRunType run_type; + GtkSignalMarshaller marshaller; + GtkType return_val; + GtkType *params; + gint nparams; +}; + +struct _GtkHandler +{ + guint16 id; + guint signal_type : 13; + guint object_signal : 1; + guint blocked : 1; + guint after : 1; + guint no_marshal : 1; + GtkSignalFunc func; + gpointer func_data; + GtkSignalDestroy destroy_func; + GtkHandler *next; +}; + +struct _GtkHandlerInfo +{ + GtkObject *object; + GtkSignalMarshaller marshaller; + GtkArg *params; + GtkType *param_types; + GtkType return_val; + GtkSignalRunType run_type; + gint nparams; + gint signal_type; +}; + +struct _GtkEmission +{ + GtkObject *object; + gint signal_type; +}; + + +static void gtk_signal_init (void); +static guint gtk_signal_hash (gint *key); +static gint gtk_signal_compare (gint *a, + gint *b); +static guint gtk_signal_info_hash (GtkSignalInfo *a); +static gint gtk_signal_info_compare (GtkSignalInfo *a, + GtkSignalInfo *b); +static GtkHandler* gtk_signal_handler_new (void); +static void gtk_signal_handler_destroy (GtkHandler *handler); +static void gtk_signal_handler_insert (GtkObject *object, + GtkHandler *handler); +static gint gtk_signal_real_emit (GtkObject *object, + gint signal_type, + va_list args); +static GtkHandler* gtk_signal_get_handlers (GtkObject *object, + gint signal_type); +static gint gtk_signal_connect_by_type (GtkObject *object, + gint signal_type, + gint object_signal, + GtkSignalFunc func, + gpointer func_data, + GtkSignalDestroy destroy_func, + gint after, + gint no_marshal); +static GtkEmission* gtk_emission_new (void); +static void gtk_emission_destroy (GtkEmission *emission); +static void gtk_emission_add (GList **emissions, + GtkObject *object, + gint signal_type); +static void gtk_emission_remove (GList **emissions, + GtkObject *object, + gint signal_type); +static gint gtk_emission_check (GList *emissions, + GtkObject *object, + gint signal_type); +static gint gtk_handlers_run (GtkHandler *handlers, + GtkHandlerInfo *info, + gint after); +static void gtk_params_get (GtkArg *params, + gint nparams, + GtkType *param_types, + GtkType return_val, + va_list args); + + +static gint initialize = TRUE; +static GHashTable *signal_hash_table = NULL; +static GHashTable *signal_info_hash_table = NULL; +static gint next_signal = 1; +static gint next_handler_id = 1; + +static const char *handler_key = "signal_handlers"; + +static GMemChunk *handler_mem_chunk = NULL; +static GMemChunk *emission_mem_chunk = NULL; + +static GList *current_emissions = NULL; +static GList *stop_emissions = NULL; +static GList *restart_emissions = NULL; + +static GtkSignalMarshal marshal = NULL; +static GtkSignalDestroy destroy = NULL; + + +gint +gtk_signal_new (const gchar *name, + GtkSignalRunType run_type, + gint object_type, + gint function_offset, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + ...) +{ + GtkType *params; + GtkSignal *signal; + GtkSignalInfo info; + gint *type; + gint i; + va_list args; + + g_return_val_if_fail (name != NULL, 0); + g_return_val_if_fail (marshaller != NULL, 0); + g_return_val_if_fail (nparams < 10, 0); + + if (initialize) + gtk_signal_init (); + + info.name = (char*)name; + info.object_type = object_type; + + type = g_hash_table_lookup (signal_info_hash_table, &info); + if (type) + { + g_warning ("signal \"%s\" already exists in the \"%s\" class ancestry\n", + name, gtk_type_name (object_type)); + return 0; + } + + signal = g_new (GtkSignal, 1); + signal->info.name = g_strdup(name); + signal->info.object_type = object_type; + signal->info.signal_type = next_signal++; + signal->function_offset = function_offset; + signal->run_type = run_type; + signal->marshaller = marshaller; + signal->return_val = return_val; + signal->params = NULL; + signal->nparams = nparams; + + g_hash_table_insert (signal_hash_table, &signal->info.signal_type, signal); + g_hash_table_insert (signal_info_hash_table, &signal->info, &signal->info.signal_type); + + if (nparams > 0) + { + signal->params = g_new (GtkType, nparams); + params = signal->params; + + va_start (args, nparams); + + for (i = 0; i < nparams; i++) + params[i] = va_arg (args, GtkType); + + va_end (args); + } + + return signal->info.signal_type; +} + +gint +gtk_signal_lookup (const gchar *name, + gint object_type) +{ + GtkSignalInfo info; + gint *type; + + g_return_val_if_fail (name != NULL, 0); + + if (initialize) + gtk_signal_init (); + + info.name = (char*)name; + + while (object_type) + { + info.object_type = object_type; + + type = g_hash_table_lookup (signal_info_hash_table, &info); + if (type) + return *type; + + object_type = gtk_type_parent (object_type); + } + + return 0; +} + +gchar* +gtk_signal_name (gint signal_num) +{ + GtkSignal *signal; + + signal = g_hash_table_lookup (signal_hash_table, &signal_num); + if (signal) + return signal->info.name; + + return NULL; +} + +gint +gtk_signal_emit (GtkObject *object, + gint signal_type, + ...) +{ + gint return_val; + + va_list args; + + g_return_val_if_fail (object != NULL, FALSE); + + if (initialize) + gtk_signal_init (); + + va_start (args, signal_type); + + return_val = gtk_signal_real_emit (object, signal_type, args); + + va_end (args); + + return return_val; +} + +gint +gtk_signal_emit_by_name (GtkObject *object, + const gchar *name, + ...) +{ + gint return_val; + gint type; + va_list args; + + g_return_val_if_fail (object != NULL, FALSE); + + if (initialize) + gtk_signal_init (); + + return_val = TRUE; + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + + if (type) + { + va_start (args, name); + + return_val = gtk_signal_real_emit (object, type, args); + + va_end (args); + } + + return return_val; +} + +void +gtk_signal_emit_stop (GtkObject *object, + gint signal_type) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (signal_type >= 1); + + if (initialize) + gtk_signal_init (); + + if (gtk_emission_check (current_emissions, object, signal_type)) + gtk_emission_add (&stop_emissions, object, signal_type); +} + +void +gtk_signal_emit_stop_by_name (GtkObject *object, + const gchar *name) +{ + gint type; + + g_return_if_fail (object != NULL); + g_return_if_fail (name != NULL); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (type) + gtk_signal_emit_stop (object, type); +} + +gint +gtk_signal_connect (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, FALSE, + func, func_data, NULL, + FALSE, FALSE); +} + +gint +gtk_signal_connect_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, FALSE, + func, func_data, NULL, + TRUE, FALSE); +} + +gint +gtk_signal_connect_interp (GtkObject *object, + gchar *name, + GtkCallbackMarshal func, + gpointer func_data, + GtkDestroyNotify destroy_func, + gint after) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, FALSE, + (GtkSignalFunc) func, func_data, + destroy_func, after, TRUE); +} + +gint +gtk_signal_connect_object (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, TRUE, + func, slot_object, NULL, + FALSE, FALSE); +} + +gint +gtk_signal_connect_object_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, TRUE, + func, slot_object, NULL, + TRUE, FALSE); +} + +void +gtk_signal_disconnect (GtkObject *object, + gint anid) +{ + GtkHandler *tmp; + GtkHandler *prev; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + prev = NULL; + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->id == anid) + { + if (prev) + prev->next = tmp->next; + else + gtk_object_set_data (object, handler_key, tmp->next); + gtk_signal_handler_destroy (tmp); + return; + } + + prev = tmp; + tmp = tmp->next; + } + + g_warning ("could not find handler (%d)", anid); +} + +void +gtk_signal_disconnect_by_data (GtkObject *object, + gpointer data) +{ + GtkHandler *start; + GtkHandler *tmp; + GtkHandler *prev; + gint found_one; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + prev = NULL; + start = gtk_object_get_data (object, handler_key); + tmp = start; + found_one = FALSE; + + while (tmp) + { + if (tmp->func_data == data) + { + found_one = TRUE; + + if (prev) + prev->next = tmp->next; + else + start = tmp->next; + + gtk_signal_handler_destroy (tmp); + + if (prev) + { + tmp = prev->next; + } + else + { + prev = NULL; + tmp = start; + } + } + else + { + prev = tmp; + tmp = tmp->next; + } + } + + gtk_object_set_data (object, handler_key, start); + + if (!found_one) + g_warning ("could not find handler containing data (0x%0lX)", (long) data); +} + +void +gtk_signal_handler_block (GtkObject *object, + gint anid) +{ + GtkHandler *tmp; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->id == anid) + { + tmp->blocked = TRUE; + return; + } + + tmp = tmp->next; + } + + g_warning ("could not find handler (%d)", anid); +} + +void +gtk_signal_handler_block_by_data (GtkObject *object, + gpointer data) +{ + GtkHandler *tmp; + gint found_one; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + found_one = FALSE; + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->func_data == data) + { + tmp->blocked = TRUE; + found_one = TRUE; + } + + tmp = tmp->next; + } + + if (!found_one) + g_warning ("could not find handler containing data (0x%0lX)", (long) data); +} + +void +gtk_signal_handler_unblock (GtkObject *object, + gint anid) +{ + GtkHandler *tmp; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->id == anid) + { + tmp->blocked = FALSE; + return; + } + + tmp = tmp->next; + } + + g_warning ("could not find handler (%d)", anid); +} + +void +gtk_signal_handler_unblock_by_data (GtkObject *object, + gpointer data) +{ + GtkHandler *tmp; + gint found_one; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + found_one = FALSE; + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->func_data == data) + { + tmp->blocked = FALSE; + found_one = TRUE; + } + + tmp = tmp->next; + } + + if (!found_one) + g_warning ("could not find handler containing data (0x%0lX)", (long) data); +} + +void +gtk_signal_handlers_destroy (GtkObject *object) +{ + GtkHandler *list; + GtkHandler *handler; + + list = gtk_object_get_data (object, handler_key); + if (list) + { + while (list) + { + handler = list->next; + gtk_signal_handler_destroy (list); + list = handler; + } + + gtk_object_remove_data (object, handler_key); + } +} + +void +gtk_signal_default_marshaller (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *params) +{ + GtkSignalMarshaller0 rfunc; + + rfunc = (GtkSignalMarshaller0) func; + + (* rfunc) (object, func_data); +} + +void +gtk_signal_set_funcs (GtkSignalMarshal marshal_func, + GtkSignalDestroy destroy_func) +{ + marshal = marshal_func; + destroy = destroy_func; +} + + +static void +gtk_signal_init () +{ + if (initialize) + { + initialize = FALSE; + signal_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_hash, + (GCompareFunc) gtk_signal_compare); + signal_info_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_info_hash, + (GCompareFunc) gtk_signal_info_compare); + } +} + +static guint +gtk_signal_hash (gint *key) +{ + return (guint) *key; +} + +static gint +gtk_signal_compare (gint *a, + gint *b) +{ + return (*a == *b); +} + +static guint +gtk_signal_info_hash (GtkSignalInfo *a) +{ + return (g_string_hash (a->name) + a->object_type); +} + +static gint +gtk_signal_info_compare (GtkSignalInfo *a, + GtkSignalInfo *b) +{ + return ((a->object_type == b->object_type) && + g_string_equal (a->name, b->name)); +} + +static GtkHandler* +gtk_signal_handler_new () +{ + GtkHandler *handler; + + if (!handler_mem_chunk) + handler_mem_chunk = g_mem_chunk_new ("handler mem chunk", sizeof (GtkHandler), + 1024, G_ALLOC_AND_FREE); + + handler = g_chunk_new (GtkHandler, handler_mem_chunk); + + handler->id = 0; + handler->signal_type = 0; + handler->object_signal = FALSE; + handler->blocked = FALSE; + handler->after = FALSE; + handler->no_marshal = FALSE; + handler->func = NULL; + handler->func_data = NULL; + handler->destroy_func = NULL; + handler->next = NULL; + + return handler; +} + +static void +gtk_signal_handler_destroy (GtkHandler *handler) +{ + if (!handler->func && destroy) + (* destroy) (handler->func_data); + else if (handler->destroy_func) + (* handler->destroy_func) (handler->func_data); + g_mem_chunk_free (handler_mem_chunk, handler); +} + +static void +gtk_signal_handler_insert (GtkObject *object, + GtkHandler *handler) +{ + GtkHandler *start; + GtkHandler *tmp; + GtkHandler *prev; + + start = gtk_object_get_data (object, handler_key); + if (!start) + { + gtk_object_set_data (object, handler_key, handler); + } + else + { + prev = NULL; + tmp = start; + + while (tmp) + { + if (tmp->signal_type < handler->signal_type) + { + if (prev) + prev->next = handler; + else + gtk_object_set_data (object, handler_key, handler); + handler->next = tmp; + break; + } + + if (!tmp->next) + { + tmp->next = handler; + break; + } + + prev = tmp; + tmp = tmp->next; + } + } +} + +static gint +gtk_signal_real_emit (GtkObject *object, + gint signal_type, + va_list args) +{ + gint old_value; + GtkSignal *signal; + GtkHandler *handlers; + GtkHandlerInfo info; + guchar **signal_func_offset; + gint being_destroyed; + GtkArg params[MAX_PARAMS]; + + g_return_val_if_fail (object != NULL, FALSE); + g_return_val_if_fail (signal_type >= 1, TRUE); + + being_destroyed = GTK_OBJECT_BEING_DESTROYED (object); + if (!GTK_OBJECT_NEED_DESTROY (object)) + { + signal = g_hash_table_lookup (signal_hash_table, &signal_type); + g_return_val_if_fail (signal != NULL, TRUE); + g_return_val_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->info.object_type), TRUE); + + if ((signal->run_type & GTK_RUN_NO_RECURSE) && + gtk_emission_check (current_emissions, object, signal_type)) + { + gtk_emission_add (&restart_emissions, object, signal_type); + return TRUE; + } + + old_value = GTK_OBJECT_IN_CALL (object); + GTK_OBJECT_SET_FLAGS (object, GTK_IN_CALL); + + gtk_params_get (params, signal->nparams, signal->params, signal->return_val, args); + + gtk_emission_add (¤t_emissions, object, signal_type); + + restart: + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST) + { + signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); + if (*signal_func_offset) + (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params); + if (GTK_OBJECT_NEED_DESTROY (object)) + goto done; + } + + info.object = object; + info.marshaller = signal->marshaller; + info.params = params; + info.param_types = signal->params; + info.return_val = signal->return_val; + info.nparams = signal->nparams; + info.run_type = signal->run_type; + info.signal_type = signal_type; + + handlers = gtk_signal_get_handlers (object, signal_type); + switch (gtk_handlers_run (handlers, &info, FALSE)) + { + case DONE: + goto done; + case RESTART: + goto restart; + } + + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST) + { + signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); + if (*signal_func_offset) + (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params); + if (being_destroyed || GTK_OBJECT_NEED_DESTROY (object)) + goto done; + } + + switch (gtk_handlers_run (handlers, &info, TRUE)) + { + case DONE: + goto done; + case RESTART: + goto restart; + } + + done: + gtk_emission_remove (¤t_emissions, object, signal_type); + + if (signal->run_type & GTK_RUN_NO_RECURSE) + gtk_emission_remove (&restart_emissions, object, signal_type); + + if (!being_destroyed && !old_value) + GTK_OBJECT_UNSET_FLAGS (object, GTK_IN_CALL); + } + + if (!being_destroyed && GTK_OBJECT_NEED_DESTROY (object) && !GTK_OBJECT_IN_CALL (object)) + { + gtk_object_destroy (object); + return FALSE; + } + + return TRUE; +} + +static GtkHandler* +gtk_signal_get_handlers (GtkObject *object, + gint signal_type) +{ + GtkHandler *handlers; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (signal_type >= 1, NULL); + + handlers = gtk_object_get_data (object, handler_key); + + while (handlers) + { + if (handlers->signal_type == signal_type) + return handlers; + handlers = handlers->next; + } + + return NULL; +} + +static gint +gtk_signal_connect_by_type (GtkObject *object, + gint signal_type, + gint object_signal, + GtkSignalFunc func, + gpointer func_data, + GtkSignalDestroy destroy_func, + gint after, + gint no_marshal) +{ + GtkHandler *handler; + gint *object_signals; + gint nsignals; + gint found_it; + gint i; + + g_return_val_if_fail (object != NULL, 0); + g_return_val_if_fail (object->klass != NULL, 0); + g_return_val_if_fail (object->klass->signals != NULL, 0); + + /* Search through the signals for this object and make + * sure the one we are adding is valid. If it isn't then + * issue a warning and return. + */ + object_signals = object->klass->signals; + nsignals = object->klass->nsignals; + found_it = FALSE; + + for (i = 0; i < nsignals; i++) + if (object_signals[i] == signal_type) + { + found_it = TRUE; + break; + } + + if (!found_it) + { + g_warning ("could not find signal (%d) in object's list of signals", signal_type); + return 0; + } + + handler = gtk_signal_handler_new (); + handler->id = next_handler_id++; + handler->signal_type = signal_type; + handler->object_signal = object_signal; + handler->func = func; + handler->func_data = func_data; + handler->destroy_func = destroy_func; + + if (after) + handler->after = TRUE; + handler->no_marshal = no_marshal; + + gtk_signal_handler_insert (object, handler); + return handler->id; +} + +static GtkEmission* +gtk_emission_new () +{ + GtkEmission *emission; + + if (!emission_mem_chunk) + emission_mem_chunk = g_mem_chunk_new ("emission mem chunk", sizeof (GtkEmission), + 1024, G_ALLOC_AND_FREE); + + emission = g_chunk_new (GtkEmission, emission_mem_chunk); + + emission->object = NULL; + emission->signal_type = 0; + + return emission; +} + +static void +gtk_emission_destroy (GtkEmission *emission) +{ + g_mem_chunk_free (emission_mem_chunk, emission); +} + +static void +gtk_emission_add (GList **emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + + g_return_if_fail (emissions != NULL); + g_return_if_fail (object != NULL); + + emission = gtk_emission_new (); + emission->object = object; + emission->signal_type = signal_type; + + *emissions = g_list_prepend (*emissions, emission); +} + +static void +gtk_emission_remove (GList **emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + GList *tmp; + + g_return_if_fail (emissions != NULL); + g_return_if_fail (object != NULL); + + tmp = *emissions; + while (tmp) + { + emission = tmp->data; + + if ((emission->object == object) && + (emission->signal_type == signal_type)) + { + gtk_emission_destroy (emission); + *emissions = g_list_remove_link (*emissions, tmp); + g_list_free (tmp); + break; + } + + tmp = tmp->next; + } +} + +static gint +gtk_emission_check (GList *emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + GList *tmp; + + g_return_val_if_fail (object != NULL, FALSE); + + tmp = emissions; + while (tmp) + { + emission = tmp->data; + tmp = tmp->next; + + if ((emission->object == object) && + (emission->signal_type == signal_type)) + return TRUE; + } + return FALSE; +} + +static gint +gtk_handlers_run (GtkHandler *handlers, + GtkHandlerInfo *info, + gint after) +{ + while (handlers && (handlers->signal_type == info->signal_type)) + { + if (!handlers->blocked && (handlers->after == after)) + { + if (handlers->func) + { + if (handlers->no_marshal) + (* (GtkCallbackMarshal)handlers->func) (info->object, + handlers->func_data, + info->nparams, + info->params); + else if (handlers->object_signal) + (* info->marshaller) (GTK_OBJECT (handlers->func_data), + handlers->func, + handlers->func_data, + info->params); + else + (* info->marshaller) (info->object, + handlers->func, + handlers->func_data, + info->params); + } + else if (marshal) + (* marshal) (info->object, + handlers->func_data, + info->nparams, + info->params, + info->param_types, + info->return_val); + + if (GTK_OBJECT_NEED_DESTROY (info->object)) + return DONE; + else if (gtk_emission_check (stop_emissions, info->object, info->signal_type)) + { + gtk_emission_remove (&stop_emissions, info->object, info->signal_type); + + if (info->run_type & GTK_RUN_NO_RECURSE) + gtk_emission_remove (&restart_emissions, info->object, info->signal_type); + return DONE; + } + else if ((info->run_type & GTK_RUN_NO_RECURSE) && + gtk_emission_check (restart_emissions, info->object, info->signal_type)) + { + gtk_emission_remove (&restart_emissions, info->object, info->signal_type); + return RESTART; + } + } + + handlers = handlers->next; + } + + return 0; +} + +static void +gtk_params_get (GtkArg *params, + gint nparams, + GtkType *param_types, + GtkType return_val, + va_list args) +{ + int i; + + for (i = 0; i < nparams; i++) + { + if (param_types[i] != GTK_TYPE_NONE) + { + params[i].type = param_types[i]; + params[i].name = NULL; + } + + switch (GTK_FUNDAMENTAL_TYPE (param_types[i])) + { + case GTK_TYPE_INVALID: + break; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + GTK_VALUE_CHAR(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_BOOL: + GTK_VALUE_BOOL(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_INT: + GTK_VALUE_INT(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_UINT: + GTK_VALUE_UINT(params[i]) = va_arg (args, guint); + break; + case GTK_TYPE_ENUM: + GTK_VALUE_ENUM(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_FLAGS: + GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_LONG: + GTK_VALUE_LONG(params[i]) = va_arg (args, glong); + break; + case GTK_TYPE_ULONG: + GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong); + break; + case GTK_TYPE_FLOAT: + GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat); + break; + case GTK_TYPE_STRING: + GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*); + break; + case GTK_TYPE_POINTER: + GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer); + break; + case GTK_TYPE_BOXED: + GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer); + break; + case GTK_TYPE_SIGNAL: + GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction); + GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer); + break; + case GTK_TYPE_FOREIGN: + GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer); + GTK_VALUE_FOREIGN(params[i]).notify = + va_arg (args, GtkDestroyNotify); + break; + case GTK_TYPE_CALLBACK: + GTK_VALUE_CALLBACK(params[i]).marshal = + va_arg (args, GtkCallbackMarshal); + GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer); + GTK_VALUE_CALLBACK(params[i]).notify = + va_arg (args, GtkDestroyNotify); + break; + case GTK_TYPE_C_CALLBACK: + GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction); + GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer); + break; + case GTK_TYPE_ARGS: + GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, int); + GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*); + break; + case GTK_TYPE_OBJECT: + GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*); + g_assert (GTK_VALUE_OBJECT(params[i]) == NULL || + GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), + params[i].type)); + break; + default: + g_error ("unsupported type %s in signal arg", + gtk_type_name (params[i].type)); + break; + } + } + + if (return_val != GTK_TYPE_NONE) + { + params[i].type = return_val; + params[i].name = NULL; + } + + switch (GTK_FUNDAMENTAL_TYPE (return_val)) + { + case GTK_TYPE_INVALID: + break; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + params[i].d.pointer_data = va_arg (args, gchar*); + break; + case GTK_TYPE_BOOL: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_INT: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_UINT: + params[i].d.pointer_data = va_arg (args, guint*); + break; + case GTK_TYPE_ENUM: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_FLAGS: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_LONG: + params[i].d.pointer_data = va_arg (args, glong*); + break; + case GTK_TYPE_ULONG: + params[i].d.pointer_data = va_arg (args, gulong*); + break; + case GTK_TYPE_FLOAT: + params[i].d.pointer_data = va_arg (args, gfloat*); + break; + case GTK_TYPE_STRING: + params[i].d.pointer_data = va_arg (args, gchar**); + break; + case GTK_TYPE_POINTER: + params[i].d.pointer_data = va_arg (args, gpointer*); + break; + case GTK_TYPE_BOXED: + params[i].d.pointer_data = va_arg (args, gpointer*); + break; + case GTK_TYPE_OBJECT: + params[i].d.pointer_data = va_arg (args, GtkObject**); + break; + case GTK_TYPE_SIGNAL: + case GTK_TYPE_FOREIGN: + case GTK_TYPE_CALLBACK: + case GTK_TYPE_C_CALLBACK: + case GTK_TYPE_ARGS: + default: + g_error ("unsupported type %s in signal return", + gtk_type_name (return_val)); + break; + } +} diff --git a/gtk/gtksignal.h b/gtk/gtksignal.h new file mode 100644 index 0000000000..68ff999025 --- /dev/null +++ b/gtk/gtksignal.h @@ -0,0 +1,124 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_SIGNAL_H__ +#define __GTK_SIGNAL_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkenums.h> +#include <gtk/gtkobject.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#ifdef offsetof +#define GTK_SIGNAL_OFFSET(t, f) ((int) offsetof (t, f)) +#else /* offsetof */ +#define GTK_SIGNAL_OFFSET(t, f) ((int) ((char*) &((t*) 0)->f)) +#endif /* offsetof */ + +#define GTK_SIGNAL_FUNC(f) ((GtkSignalFunc) f) + + +typedef void (*GtkSignalFunc) (void); +typedef void (*GtkSignalMarshaller) (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +typedef void (*GtkSignalMarshal) (GtkObject *object, + gpointer data, + gint nparams, + GtkArg *args, + GtkType *arg_types, + GtkType return_type); +typedef void (*GtkSignalDestroy) (gpointer data); + + +gint gtk_signal_new (const gchar *name, + GtkSignalRunType run_type, + gint object_type, + gint function_offset, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + ...); +gint gtk_signal_lookup (const gchar *name, + gint object_type); +gchar* gtk_signal_name (gint signal_num); +gint gtk_signal_emit (GtkObject *object, + gint signal_type, + ...); +gint gtk_signal_emit_by_name (GtkObject *object, + const gchar *name, + ...); +void gtk_signal_emit_stop (GtkObject *object, + gint signal_type); +void gtk_signal_emit_stop_by_name (GtkObject *object, + const gchar *name); +gint gtk_signal_connect (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data); +gint gtk_signal_connect_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data); +gint gtk_signal_connect_object (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object); +gint gtk_signal_connect_object_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object); +gint gtk_signal_connect_interp (GtkObject *object, + gchar *name, + GtkCallbackMarshal func, + gpointer data, + GtkDestroyNotify destroy_func, + gint after); +void gtk_signal_disconnect (GtkObject *object, + gint anid); +void gtk_signal_disconnect_by_data (GtkObject *object, + gpointer data); +void gtk_signal_handler_block (GtkObject *object, + gint anid); +void gtk_signal_handler_block_by_data (GtkObject *object, + gpointer data); +void gtk_signal_handler_unblock (GtkObject *object, + gint anid); +void gtk_signal_handler_unblock_by_data (GtkObject *object, + gpointer data); +void gtk_signal_handlers_destroy (GtkObject *object); +void gtk_signal_default_marshaller (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void gtk_signal_set_funcs (GtkSignalMarshal marshal_func, + GtkSignalDestroy destroy_func); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SIGNAL_H__ */ diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c new file mode 100644 index 0000000000..ae8c1a5d9f --- /dev/null +++ b/gtk/gtkstyle.c @@ -0,0 +1,1795 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <math.h> +#include "gtkgc.h" +#include "gtkstyle.h" + + +#define LIGHTNESS_MULT 1.3 +#define DARKNESS_MULT 0.7 + + +typedef struct _GtkStyleKey GtkStyleKey; + +struct _GtkStyleKey +{ + GdkColor fg[5]; + GdkColor bg[5]; + GdkColor text[5]; + GdkColor base[5]; + + GdkPixmap *bg_pixmap[5]; + + GdkFont *font; + + gint depth; + GdkColormap *colormap; + GtkStyleClass *klass; +}; + + +static void gtk_style_init (GtkStyle *style); +static void gtk_styles_init (void); +static void gtk_style_remove (GtkStyle *style); +static GtkStyle* gtk_style_find (GtkStyle *style, + GdkColormap *cmap, + gint depth); +static GtkStyle* gtk_style_new_from_key (GtkStyleKey *key); +static GtkStyleKey* gtk_style_key_dup (GtkStyleKey *key); +static void gtk_style_destroy (GtkStyle *style); +static void gtk_style_key_destroy (GtkStyleKey *key); +static guint gtk_style_key_hash (GtkStyleKey *key); +static guint gtk_style_value_hash (GtkStyle *style); +static gint gtk_style_key_compare (GtkStyleKey *a, + GtkStyleKey *b); + +static void gtk_default_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y); +static void gtk_default_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x); +static void gtk_default_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill); +static void gtk_default_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string); + +static void gtk_style_shade (GdkColor *a, GdkColor *b, gdouble k); +static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b); +static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s); + + +static GtkStyleClass default_class = +{ + 2, + 2, + gtk_default_draw_hline, + gtk_default_draw_vline, + gtk_default_draw_shadow, + gtk_default_draw_polygon, + gtk_default_draw_arrow, + gtk_default_draw_diamond, + gtk_default_draw_oval, + gtk_default_draw_string, +}; + +static GdkColor gtk_default_normal_fg = { 0, 0, 0, 0 }; +static GdkColor gtk_default_active_fg = { 0, 0, 0, 0 }; +static GdkColor gtk_default_prelight_fg = { 0, 0, 0, 0 }; +static GdkColor gtk_default_selected_fg = { 0, 0xffff, 0xffff, 0xffff }; +static GdkColor gtk_default_insensitive_fg = { 0, 0x7530, 0x7530, 0x7530 }; + +static GdkColor gtk_default_normal_bg = { 0, 0xd6d6, 0xd6d6, 0xd6d6 }; +static GdkColor gtk_default_active_bg = { 0, 0xc350, 0xc350, 0xc350 }; +static GdkColor gtk_default_prelight_bg = { 0, 0xea60, 0xea60, 0xea60 }; +static GdkColor gtk_default_selected_bg = { 0, 0, 0, 0x9c40 }; +static GdkColor gtk_default_insensitive_bg = { 0, 0xd6d6, 0xd6d6, 0xd6d6 }; + +static GdkFont *default_font = NULL; + +static gint initialize = TRUE; +static GCache *style_cache = NULL; +static GSList *unattached_styles = NULL; + +static GMemChunk *key_mem_chunk = NULL; + + +GtkStyle* +gtk_style_new () +{ + GtkStyle *style; + gint i; + + style = g_new (GtkStyle, 1); + + if (!default_font) + default_font = gdk_font_load ("-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*"); + + style->font = default_font; + gdk_font_ref (style->font); + + style->ref_count = 0; + style->attach_count = 0; + style->colormap = NULL; + style->depth = -1; + style->klass = &default_class; + + style->black.red = 0; + style->black.green = 0; + style->black.blue = 0; + + style->white.red = 65535; + style->white.green = 65535; + style->white.blue = 65535; + + style->black_gc = NULL; + style->white_gc = NULL; + + style->fg[GTK_STATE_NORMAL] = gtk_default_normal_fg; + style->fg[GTK_STATE_ACTIVE] = gtk_default_active_fg; + style->fg[GTK_STATE_PRELIGHT] = gtk_default_prelight_fg; + style->fg[GTK_STATE_SELECTED] = gtk_default_selected_fg; + style->fg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_fg; + + style->bg[GTK_STATE_NORMAL] = gtk_default_normal_bg; + style->bg[GTK_STATE_ACTIVE] = gtk_default_active_bg; + style->bg[GTK_STATE_PRELIGHT] = gtk_default_prelight_bg; + style->bg[GTK_STATE_SELECTED] = gtk_default_selected_bg; + style->bg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_bg; + + for (i = 0; i < 5; i++) + { + style->text[i] = style->fg[i]; + style->base[i] = style->white; + } + + for (i = 0; i < 5; i++) + style->bg_pixmap[i] = NULL; + + for (i = 0; i < 5; i++) + { + style->fg_gc[i] = NULL; + style->bg_gc[i] = NULL; + style->light_gc[i] = NULL; + style->dark_gc[i] = NULL; + style->mid_gc[i] = NULL; + style->text_gc[i] = NULL; + style->base_gc[i] = NULL; + } + + unattached_styles = g_slist_prepend (unattached_styles, style); + + return style; +} + +GtkStyle* +gtk_style_attach (GtkStyle *style, + GdkWindow *window) +{ + GtkStyle *new_style; + GdkColormap *colormap; + gint depth; + + g_return_val_if_fail (style != NULL, NULL); + g_return_val_if_fail (window != NULL, NULL); + + colormap = gdk_window_get_colormap (window); + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + new_style = gtk_style_find (style, colormap, depth); + + if (new_style && (new_style != style)) + { + gtk_style_unref (style); + style = new_style; + gtk_style_ref (style); + } + + if (style->attach_count == 0) + unattached_styles = g_slist_remove (unattached_styles, style); + + style->attach_count += 1; + + return style; +} + +void +gtk_style_detach (GtkStyle *style) +{ + gint i; + + g_return_if_fail (style != NULL); + + style->attach_count -= 1; + if (style->attach_count == 0) + { + unattached_styles = g_slist_prepend (unattached_styles, style); + + gtk_gc_release (style->black_gc); + gtk_gc_release (style->white_gc); + + style->black_gc = NULL; + style->white_gc = NULL; + + for (i = 0; i < 5; i++) + { + gtk_gc_release (style->fg_gc[i]); + gtk_gc_release (style->bg_gc[i]); + gtk_gc_release (style->light_gc[i]); + gtk_gc_release (style->dark_gc[i]); + gtk_gc_release (style->mid_gc[i]); + gtk_gc_release (style->text_gc[i]); + gtk_gc_release (style->base_gc[i]); + + style->fg_gc[i] = NULL; + style->bg_gc[i] = NULL; + style->light_gc[i] = NULL; + style->dark_gc[i] = NULL; + style->mid_gc[i] = NULL; + style->text_gc[i] = NULL; + style->base_gc[i] = NULL; + } + + style->depth = -1; + style->colormap = NULL; + } + + gtk_style_remove (style); +} + +GtkStyle* +gtk_style_ref (GtkStyle *style) +{ + g_return_val_if_fail (style != NULL, NULL); + + style->ref_count += 1; + return style; +} + +void +gtk_style_unref (GtkStyle *style) +{ + g_return_if_fail (style != NULL); + + style->ref_count -= 1; + if (style->ref_count == 0) + gtk_style_destroy (style); +} + +void +gtk_style_set_background (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type) +{ + GdkPixmap *pixmap; + gint parent_relative; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if (style->bg_pixmap[state_type]) + { + if (style->bg_pixmap[state_type] == (GdkPixmap*) GDK_PARENT_RELATIVE) + { + pixmap = NULL; + parent_relative = TRUE; + } + else + { + pixmap = style->bg_pixmap[state_type]; + parent_relative = FALSE; + } + + gdk_window_set_back_pixmap (window, pixmap, parent_relative); + } + else + gdk_window_set_background (window, &style->bg[state_type]); +} + + +void +gtk_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_hline != NULL); + + (*style->klass->draw_hline) (style, window, state_type, x1, x2, y); +} + + +void +gtk_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_vline != NULL); + + (*style->klass->draw_vline) (style, window, state_type, y1, y2, x); +} + + +void +gtk_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_shadow != NULL); + + (*style->klass->draw_shadow) (style, window, state_type, shadow_type, x, y, width, height); +} + +void +gtk_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_shadow != NULL); + + (*style->klass->draw_polygon) (style, window, state_type, shadow_type, points, npoints, fill); +} + +void +gtk_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_arrow != NULL); + + (*style->klass->draw_arrow) (style, window, state_type, shadow_type, arrow_type, fill, x, y, width, height); +} + + +void +gtk_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_diamond != NULL); + + (*style->klass->draw_diamond) (style, window, state_type, shadow_type, x, y, width, height); +} + + +void +gtk_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_oval != NULL); + + (*style->klass->draw_oval) (style, window, state_type, shadow_type, x, y, width, height); +} + +void +gtk_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_oval != NULL); + + (*style->klass->draw_string) (style, window, state_type, x, y, string); +} + + +static void +gtk_style_init (GtkStyle *style) +{ + GdkGCValues gc_values; + GdkGCValuesMask gc_values_mask; + GdkColormap *colormap; + gint i; + + g_return_if_fail (style != NULL); + + if (style->attach_count == 0) + { + for (i = 0; i < 5; i++) + { + gtk_style_shade (&style->bg[i], &style->light[i], LIGHTNESS_MULT); + gtk_style_shade (&style->bg[i], &style->dark[i], DARKNESS_MULT); + + style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2; + style->mid[i].green = (style->light[i].green + style->dark[i].green) / 2; + style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2; + } + + colormap = style->colormap; + + gdk_color_black (colormap, &style->black); + gdk_color_white (colormap, &style->white); + + gc_values_mask = GDK_GC_FOREGROUND | GDK_GC_FONT; + if (style->font->type == GDK_FONT_FONT) + { + gc_values.font = style->font; + } + else if (style->font->type == GDK_FONT_FONTSET) + { + gc_values.font = default_font; + } + + gc_values.foreground = style->black; + style->black_gc = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->white; + style->white_gc = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + for (i = 0; i < 5; i++) + { + if (!gdk_color_alloc (colormap, &style->fg[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->fg[i].red, style->fg[i].green, style->fg[i].blue); + if (!gdk_color_alloc (colormap, &style->bg[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->bg[i].red, style->bg[i].green, style->bg[i].blue); + if (!gdk_color_alloc (colormap, &style->light[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->light[i].red, style->light[i].green, style->light[i].blue); + if (!gdk_color_alloc (colormap, &style->dark[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->dark[i].red, style->dark[i].green, style->dark[i].blue); + if (!gdk_color_alloc (colormap, &style->mid[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->mid[i].red, style->mid[i].green, style->mid[i].blue); + if (!gdk_color_alloc (colormap, &style->text[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->text[i].red, style->text[i].green, style->text[i].blue); + if (!gdk_color_alloc (colormap, &style->base[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->base[i].red, style->base[i].green, style->base[i].blue); + + gc_values.foreground = style->fg[i]; + style->fg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->bg[i]; + style->bg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->light[i]; + style->light_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->dark[i]; + style->dark_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->mid[i]; + style->mid_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->text[i]; + style->text_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->base[i]; + style->base_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + } + } +} + +static void +gtk_styles_init () +{ + if (initialize) + { + initialize = FALSE; + + style_cache = g_cache_new ((GCacheNewFunc) gtk_style_new_from_key, + (GCacheDestroyFunc) gtk_style_destroy, + (GCacheDupFunc) gtk_style_key_dup, + (GCacheDestroyFunc) gtk_style_key_destroy, + (GHashFunc) gtk_style_key_hash, + (GHashFunc) gtk_style_value_hash, + (GCompareFunc) gtk_style_key_compare); + } +} + +static void +gtk_style_remove (GtkStyle *style) +{ + if (initialize) + gtk_styles_init (); + + g_cache_remove (style_cache, style); +} + +static GtkStyle* +gtk_style_find (GtkStyle *style, + GdkColormap *cmap, + gint depth) +{ + GtkStyleKey key; + gint i; + + if (initialize) + gtk_styles_init (); + + for (i = 0; i < 5; i++) + { + key.fg[i] = style->fg[i]; + key.bg[i] = style->bg[i]; + key.text[i] = style->text[i]; + key.base[i] = style->base[i]; + key.bg_pixmap[i] = style->bg_pixmap[i]; + } + + key.font = style->font; + key.klass = style->klass; + key.depth = depth; + key.colormap = cmap; + + style = g_cache_insert (style_cache, &key); + + return style; +} + +static GtkStyle* +gtk_style_new_from_key (GtkStyleKey *key) +{ + GtkStyle *style; + GSList *list; + gint i; + + style = NULL; + list = unattached_styles; + + while (list) + { + style = list->data; + list = list->next; + + if ((style->depth != -1) && (style->depth != key->depth)) + { + style = NULL; + continue; + } + if (style->colormap && (style->colormap != key->colormap)) + { + style = NULL; + continue; + } + if (style->klass != key->klass) + { + style = NULL; + continue; + } + if (!gdk_font_equal (style->font, key->font)) + { + style = NULL; + continue; + } + + for (i = 0; style && (i < 5); i++) + { + if (style->bg_pixmap[i] != key->bg_pixmap[i]) + { + style = NULL; + continue; + } + + if ((style->fg[i].red != key->fg[i].red) || + (style->fg[i].green != key->fg[i].green) || + (style->fg[i].blue != key->fg[i].blue)) + { + style = NULL; + continue; + } + + if ((style->bg[i].red != key->bg[i].red) || + (style->bg[i].green != key->bg[i].green) || + (style->bg[i].blue != key->bg[i].blue)) + { + style = NULL; + continue; + } + + if ((style->text[i].red != key->text[i].red) || + (style->text[i].green != key->text[i].green) || + (style->text[i].blue != key->text[i].blue)) + { + style = NULL; + continue; + } + + if ((style->base[i].red != key->base[i].red) || + (style->base[i].green != key->base[i].green) || + (style->base[i].blue != key->base[i].blue)) + { + style = NULL; + continue; + } + } + + if (style) + break; + } + + if (!style) + { + style = g_new (GtkStyle, 1); + + style->ref_count = 0; + style->attach_count = 0; + + style->font = key->font; + gdk_font_ref (style->font); + + style->depth = key->depth; + style->colormap = key->colormap; + style->klass = key->klass; + + style->black.red = 0; + style->black.green = 0; + style->black.blue = 0; + + style->white.red = 65535; + style->white.green = 65535; + style->white.blue = 65535; + + style->black_gc = NULL; + style->white_gc = NULL; + + for (i = 0; i < 5; i++) + { + style->fg[i] = key->fg[i]; + style->bg[i] = key->bg[i]; + style->text[i] = key->text[i]; + style->base[i] = key->base[i]; + } + + for (i = 0; i < 5; i++) + style->bg_pixmap[i] = key->bg_pixmap[i]; + + for (i = 0; i < 5; i++) + { + style->fg_gc[i] = NULL; + style->bg_gc[i] = NULL; + style->light_gc[i] = NULL; + style->dark_gc[i] = NULL; + style->mid_gc[i] = NULL; + style->text_gc[i] = NULL; + style->base_gc[i] = NULL; + } + } + + if (style->depth == -1) + style->depth = key->depth; + if (!style->colormap) + style->colormap = key->colormap; + + gtk_style_init (style); + + return style; +} + +static GtkStyleKey* +gtk_style_key_dup (GtkStyleKey *key) +{ + GtkStyleKey *new_key; + + if (!key_mem_chunk) + key_mem_chunk = g_mem_chunk_new ("key mem chunk", sizeof (GtkStyleKey), + 1024, G_ALLOC_AND_FREE); + + new_key = g_chunk_new (GtkStyleKey, key_mem_chunk); + + *new_key = *key; + + return new_key; +} + +static void +gtk_style_destroy (GtkStyle *style) +{ + gint i; + + if (style->ref_count != 0) + return; + + if (style->attach_count > 0) + { + gtk_gc_release (style->black_gc); + gtk_gc_release (style->white_gc); + + for (i = 0; i < 5; i++) + { + gtk_gc_release (style->fg_gc[i]); + gtk_gc_release (style->bg_gc[i]); + gtk_gc_release (style->light_gc[i]); + gtk_gc_release (style->dark_gc[i]); + gtk_gc_release (style->mid_gc[i]); + gtk_gc_release (style->text_gc[i]); + gtk_gc_release (style->base_gc[i]); + } + } + + unattached_styles = g_slist_remove (unattached_styles, style); + + if (style->font->type == GDK_FONT_FONT) + gdk_font_free (style->font); + else if (style->font->type == GDK_FONT_FONTSET) + gdk_fontset_free (style->font); + else + g_error("undefined font type\n"); + + g_free (style); +} + +static void +gtk_style_key_destroy (GtkStyleKey *key) +{ + g_mem_chunk_free (key_mem_chunk, key); +} + +static guint +gtk_style_key_hash (GtkStyleKey *key) +{ + guint hash_val; + gint i; + + hash_val = 0; + + for (i = 0; i < 5; i++) + { + hash_val += key->fg[i].red + key->fg[i].green + key->fg[i].blue; + hash_val += key->bg[i].red + key->bg[i].green + key->bg[i].blue; + hash_val += key->text[i].red + key->text[i].green + key->text[i].blue; + hash_val += key->base[i].red + key->base[i].green + key->base[i].blue; + } + + hash_val += (guint) gdk_font_id (key->font); + hash_val += (guint) key->depth; + hash_val += (gulong) key->colormap; + hash_val += (gulong) key->klass; + + return hash_val; +} + +static guint +gtk_style_value_hash (GtkStyle *style) +{ + guint hash_val; + gint i; + + hash_val = 0; + + for (i = 0; i < 5; i++) + { + hash_val += style->fg[i].red + style->fg[i].green + style->fg[i].blue; + hash_val += style->bg[i].red + style->bg[i].green + style->bg[i].blue; + hash_val += style->text[i].red + style->text[i].green + style->text[i].blue; + hash_val += style->base[i].red + style->base[i].green + style->base[i].blue; + } + + hash_val += (guint) gdk_font_id (style->font); + hash_val += (gulong) style->klass; + + return hash_val; +} + +static gint +gtk_style_key_compare (GtkStyleKey *a, + GtkStyleKey *b) +{ + gint i; + + if (a->depth != b->depth) + return FALSE; + if (a->colormap != b->colormap) + return FALSE; + if (a->klass != b->klass) + return FALSE; + if (!gdk_font_equal (a->font, b->font)) + return FALSE; + + for (i = 0; i < 5; i++) + { + if (a->bg_pixmap[i] != b->bg_pixmap[i]) + return FALSE; + + if ((a->fg[i].red != b->fg[i].red) || + (a->fg[i].green != b->fg[i].green) || + (a->fg[i].blue != b->fg[i].blue)) + return FALSE; + if ((a->bg[i].red != b->bg[i].red) || + (a->bg[i].green != b->bg[i].green) || + (a->bg[i].blue != b->bg[i].blue)) + return FALSE; + if ((a->text[i].red != b->text[i].red) || + (a->text[i].green != b->text[i].green) || + (a->text[i].blue != b->text[i].blue)) + return FALSE; + if ((a->base[i].red != b->base[i].red) || + (a->base[i].green != b->base[i].green) || + (a->base[i].blue != b->base[i].blue)) + return FALSE; + } + + return TRUE; +} + + +static void +gtk_default_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + thickness_light = style->klass->ythickness / 2; + thickness_dark = style->klass->ythickness - thickness_light; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x2 - i - 1, y + i, x2, y + i); + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, x2 - i - 1, y + i); + } + + y += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, x1 + thickness_light - i - 1, y + i); + gdk_draw_line (window, style->light_gc[state_type], x1 + thickness_light - i - 1, y + i, x2, y + i); + } +} + + +static void +gtk_default_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + thickness_light = style->klass->xthickness / 2; + thickness_dark = style->klass->xthickness - thickness_light; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x + i, y2 - i - 1, x + i, y2); + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, y2 - i - 1); + } + + x += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, y1 + thickness_light - i); + gdk_draw_line (window, style->light_gc[state_type], x + i, y1 + thickness_light - i, x + i, y2); + } +} + + +static void +gtk_default_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + GdkGC *gc1; + GdkGC *gc2; + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + switch (shadow_type) + { + case GTK_SHADOW_NONE: + gc1 = NULL; + gc2 = NULL; + break; + case GTK_SHADOW_IN: + case GTK_SHADOW_ETCHED_IN: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + break; + case GTK_SHADOW_OUT: + case GTK_SHADOW_ETCHED_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + break; + } + + switch (shadow_type) + { + case GTK_SHADOW_NONE: + break; + + case GTK_SHADOW_IN: + gdk_draw_line (window, gc1, + x, y + height - 1, x + width - 1, y + height - 1); + gdk_draw_line (window, gc1, + x + width - 1, y, x + width - 1, y + height - 1); + + gdk_draw_line (window, style->bg_gc[state_type], + x + 1, y + height - 2, x + width - 2, y + height - 2); + gdk_draw_line (window, style->bg_gc[state_type], + x + width - 2, y + 1, x + width - 2, y + height - 2); + + gdk_draw_line (window, style->black_gc, + x + 1, y + 1, x + width - 2, y + 1); + gdk_draw_line (window, style->black_gc, + x + 1, y + 1, x + 1, y + height - 2); + + gdk_draw_line (window, gc2, + x, y, x + width - 1, y); + gdk_draw_line (window, gc2, + x, y, x, y + height - 1); + break; + + case GTK_SHADOW_OUT: + gdk_draw_line (window, gc1, + x + 1, y + height - 2, x + width - 2, y + height - 2); + gdk_draw_line (window, gc1, + x + width - 2, y + 1, x + width - 2, y + height - 2); + + gdk_draw_line (window, gc2, + x, y, x + width - 1, y); + gdk_draw_line (window, gc2, + x, y, x, y + height - 1); + + gdk_draw_line (window, style->bg_gc[state_type], + x + 1, y + 1, x + width - 2, y + 1); + gdk_draw_line (window, style->bg_gc[state_type], + x + 1, y + 1, x + 1, y + height - 2); + + gdk_draw_line (window, style->black_gc, + x, y + height - 1, x + width - 1, y + height - 1); + gdk_draw_line (window, style->black_gc, + x + width - 1, y, x + width - 1, y + height - 1); + break; + + case GTK_SHADOW_ETCHED_IN: + case GTK_SHADOW_ETCHED_OUT: + thickness_light = 1; + thickness_dark = 1; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, gc1, + x + i, + y + height - i - 1, + x + width - i - 1, + y + height - i - 1); + gdk_draw_line (window, gc1, + x + width - i - 1, + y + i, + x + width - i - 1, + y + height - i - 1); + + gdk_draw_line (window, gc2, + x + i, + y + i, + x + width - i - 2, + y + i); + gdk_draw_line (window, gc2, + x + i, + y + i, + x + i, + y + height - i - 2); + } + + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + width - thickness_dark - i - 1, + y + thickness_dark + i); + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + thickness_dark + i, + y + height - thickness_dark - i - 1); + + gdk_draw_line (window, gc2, + x + thickness_dark + i, + y + height - thickness_light - i - 1, + x + width - thickness_light - 1, + y + height - thickness_light - i - 1); + gdk_draw_line (window, gc2, + x + width - thickness_light - i - 1, + y + thickness_dark + i, + x + width - thickness_light - i - 1, + y + height - thickness_light - 1); + } + break; + } +} + + +static void +gtk_default_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill) +{ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* M_PI */ +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 +#endif /* M_PI_4 */ + + static const gdouble pi_over_4 = M_PI_4; + static const gdouble pi_3_over_4 = M_PI_4 * 3; + + GdkGC *gc1; + GdkGC *gc2; + GdkGC *gc3; + GdkGC *gc4; + gdouble angle; + gint xadjust; + gint yadjust; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + g_return_if_fail (points != NULL); + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gc1 = style->bg_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->black_gc; + break; + case GTK_SHADOW_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->black_gc; + gc4 = style->bg_gc[state_type]; + break; + default: + return; + } + + if (fill) + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, npoints); + + npoints -= 1; + for (i = 0; i < npoints; i++) + { + if ((points[i].x == points[i+1].x) && + (points[i].y == points[i+1].y)) + { + angle = 0; + } + else + { + angle = atan2 (points[i+1].y - points[i].y, + points[i+1].x - points[i].x); + } + + if ((angle > -pi_3_over_4) && (angle < pi_over_4)) + { + while (angle < 0) + angle += M_PI; + while (angle > M_PI) + angle -= M_PI; + + if ((angle > pi_3_over_4) || (angle < pi_over_4)) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc1, + points[i].x-xadjust, points[i].y-yadjust, + points[i+1].x-xadjust, points[i+1].y-yadjust); + gdk_draw_line (window, gc3, + points[i].x, points[i].y, + points[i+1].x, points[i+1].y); + } + } + + for (i = 0; i < npoints; i++) + { + if ((points[i].x == points[i+1].x) && + (points[i].y == points[i+1].y)) + { + angle = 0; + } + else + { + angle = atan2 (points[i+1].y - points[i].y, + points[i+1].x - points[i].x); + } + + if ((angle <= -pi_3_over_4) || (angle >= pi_over_4)) + { + while (angle < 0) + angle += M_PI; + while (angle > M_PI) + angle -= M_PI; + + if ((angle > pi_3_over_4) || (angle < pi_over_4)) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc4, + points[i].x+xadjust, points[i].y+yadjust, + points[i+1].x+xadjust, points[i+1].y+yadjust); + gdk_draw_line (window, gc2, + points[i].x, points[i].y, + points[i+1].x, points[i+1].y); + } + } +} + + +static void +gtk_default_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height) +{ + GdkGC *gc1; + GdkGC *gc2; + GdkGC *gc3; + GdkGC *gc4; + gint half_width; + gint half_height; + GdkPoint points[3]; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gc1 = style->bg_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->black_gc; + break; + case GTK_SHADOW_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->black_gc; + gc4 = style->bg_gc[state_type]; + break; + default: + return; + } + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + half_width = width / 2; + half_height = height / 2; + + switch (arrow_type) + { + case GTK_ARROW_UP: + if (fill) + { + points[0].x = x + half_width; + points[0].y = y; + points[1].x = x; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y + height - 1; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc1, + x + 1, y + height - 2, + x + width - 2, y + height - 2); + gdk_draw_line (window, gc3, + x + 0, y + height - 1, + x + width - 1, y + height - 1); + + gdk_draw_line (window, gc1, + x + width - 2, y + height - 1, + x + half_width, y + 1); + gdk_draw_line (window, gc3, + x + width - 1, y + height - 1, + x + half_width, y); + + gdk_draw_line (window, gc4, + x + half_width, y + 1, + x + 1, y + height - 1); + gdk_draw_line (window, gc2, + x + half_width, y, + x, y + height - 1); + break; + case GTK_ARROW_DOWN: + if (fill) + { + points[0].x = x + width - 1; + points[0].y = y; + points[1].x = x; + points[1].y = y; + points[2].x = x + half_width; + points[2].y = y + height - 1; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc4, + x + width - 2, + y + 1, x + 1, y + 1); + gdk_draw_line (window, gc2, + x + width - 1, y, + x, y); + + gdk_draw_line (window, gc4, + x + 1, y, + x + half_width, y + height - 2); + gdk_draw_line (window, gc2, + x, y, + x + half_width, y + height - 1); + + gdk_draw_line (window, gc1, + x + half_width, y + height - 2, + x + width - 2, y); + gdk_draw_line (window, gc3, + x + half_width, y + height - 1, + x + width - 1, y); + break; + case GTK_ARROW_LEFT: + if (fill) + { + points[0].x = x; + points[0].y = y + half_height; + points[1].x = x + width - 1; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc1, + x + 1, y + half_height, + x + width - 1, y + height - 1); + gdk_draw_line (window, gc3, + x, y + half_height, + x + width - 1, y + height - 1); + + gdk_draw_line (window, gc1, + x + width - 2, y + height - 1, + x + width - 2, y + 1); + gdk_draw_line (window, gc3, + x + width - 1, y + height - 1, + x + width - 1, y); + + gdk_draw_line (window, gc4, + x + width - 1, y + 1, + x + 1, y + half_width); + gdk_draw_line (window, gc2, + x + width - 1, y, + x, y + half_width); + break; + case GTK_ARROW_RIGHT: + if (fill) + { + points[0].x = x + width - 1; + points[0].y = y + half_height; + points[1].x = x; + points[1].y = y; + points[2].x = x; + points[2].y = y + height - 1; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc4, + x + width - 1, y + half_height, + x + 1, y + 1); + gdk_draw_line (window, gc2, + x + width - 1, y + half_height, + x, y); + + gdk_draw_line (window, gc4, + x + 1, y + 1, + x + 1, y + height - 2); + gdk_draw_line (window, gc2, + x, y, + x, y + height - 1); + + gdk_draw_line (window, gc1, + x + 1, y + height - 2, + x + width - 1, y + half_height); + gdk_draw_line (window, gc3, + x, y + height - 1, + x + width - 1, y + half_height); + break; + } +} + + +static void +gtk_default_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + gint half_width; + gint half_height; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + half_width = width / 2; + half_height = height / 2; + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gdk_draw_line (window, style->bg_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->bg_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x, y + half_height, + x + half_width, y + height); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->black_gc, + x + 2, y + half_height, + x + half_width, y + 2); + gdk_draw_line (window, style->black_gc, + x + half_width, y + 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x + 1, y + half_height, + x + half_width, y + 1); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x, y + half_height, + x + half_width, y); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y, + x + width, y + half_height); + break; + case GTK_SHADOW_OUT: + gdk_draw_line (window, style->dark_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->black_gc, + x, y + half_height, + x + half_width, y + height); + gdk_draw_line (window, style->black_gc, + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->bg_gc[state_type], + x + 2, y + half_height, + x + half_width, y + 2); + gdk_draw_line (window, style->bg_gc[state_type], + x + half_width, y + 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y + half_height, + x + half_width, y + 1); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x, y + half_height, + x + half_width, y); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y, + x + width, y + half_height); + break; + default: + break; + } +} + + +static void +gtk_default_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +gtk_default_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if (state_type == GTK_STATE_INSENSITIVE) + gdk_draw_string (window, style->font, style->white_gc, x + 1, y + 1, string); + gdk_draw_string (window, style->font, style->fg_gc[state_type], x, y, string); +} + + +static void +gtk_style_shade (GdkColor *a, + GdkColor *b, + gdouble k) +{ + gdouble red; + gdouble green; + gdouble blue; + + red = (gdouble) a->red / 65535.0; + green = (gdouble) a->green / 65535.0; + blue = (gdouble) a->blue / 65535.0; + + rgb_to_hls (&red, &green, &blue); + + green *= k; + if (green > 1.0) + green = 1.0; + else if (green < 0.0) + green = 0.0; + + blue *= k; + if (blue > 1.0) + blue = 1.0; + else if (blue < 0.0) + blue = 0.0; + + hls_to_rgb (&red, &green, &blue); + + b->red = red * 65535.0; + b->green = green * 65535.0; + b->blue = blue * 65535.0; +} + +static void +rgb_to_hls (gdouble *r, + gdouble *g, + gdouble *b) +{ + gdouble min; + gdouble max; + gdouble red; + gdouble green; + gdouble blue; + gdouble h, l, s; + gdouble delta; + + red = *r; + green = *g; + blue = *b; + + if (red > green) + { + if (red > blue) + max = red; + else + max = blue; + + if (green < blue) + min = green; + else + min = blue; + } + else + { + if (green > blue) + max = green; + else + max = blue; + + if (red < blue) + min = red; + else + min = blue; + } + + l = (max + min) / 2; + s = 0; + h = 0; + + if (max != min) + { + if (l <= 0.5) + s = (max - min) / (max + min); + else + s = (max - min) / (2 - max - min); + + delta = max -min; + if (red == max) + h = (green - blue) / delta; + else if (green == max) + h = 2 + (blue - red) / delta; + else if (blue == max) + h = 4 + (red - green) / delta; + + h *= 60; + if (h < 0.0) + h += 360; + } + + *r = h; + *g = l; + *b = s; +} + +static void +hls_to_rgb (gdouble *h, + gdouble *l, + gdouble *s) +{ + gdouble hue; + gdouble lightness; + gdouble saturation; + gdouble m1, m2; + gdouble r, g, b; + + lightness = *l; + saturation = *s; + + if (lightness <= 0.5) + m2 = lightness * (1 + saturation); + else + m2 = lightness + saturation - lightness * saturation; + m1 = 2 * lightness - m2; + + if (saturation == 0) + { + *h = lightness; + *l = lightness; + *s = lightness; + } + else + { + hue = *h + 120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + r = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + r = m2; + else if (hue < 240) + r = m1 + (m2 - m1) * (240 - hue) / 60; + else + r = m1; + + hue = *h; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + g = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + g = m2; + else if (hue < 240) + g = m1 + (m2 - m1) * (240 - hue) / 60; + else + g = m1; + + hue = *h - 120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + b = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + b = m2; + else if (hue < 240) + b = m1 + (m2 - m1) * (240 - hue) / 60; + else + b = m1; + + *h = r; + *l = g; + *s = b; + } +} diff --git a/gtk/gtkstyle.h b/gtk/gtkstyle.h new file mode 100644 index 0000000000..c0ec33736c --- /dev/null +++ b/gtk/gtkstyle.h @@ -0,0 +1,217 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_STYLE_H__ +#define __GTK_STYLE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkenums.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GtkStyle GtkStyle; +typedef struct _GtkStyleClass GtkStyleClass; + +/* This is used for having dynamic style changing stuff */ +/* fg, bg, light, dark, mid, text, base */ +#define GTK_STYLE_NUM_STYLECOLORS() 7*5 + +struct _GtkStyle +{ + GdkColor fg[5]; + GdkColor bg[5]; + GdkColor light[5]; + GdkColor dark[5]; + GdkColor mid[5]; + GdkColor text[5]; + GdkColor base[5]; + + GdkColor black; + GdkColor white; + GdkFont *font; + + GdkGC *fg_gc[5]; + GdkGC *bg_gc[5]; + GdkGC *light_gc[5]; + GdkGC *dark_gc[5]; + GdkGC *mid_gc[5]; + GdkGC *text_gc[5]; + GdkGC *base_gc[5]; + GdkGC *black_gc; + GdkGC *white_gc; + + GdkPixmap *bg_pixmap[5]; + + gint ref_count; + gint attach_count; + + gint depth; + GdkColormap *colormap; + + GtkStyleClass *klass; +}; + +struct _GtkStyleClass +{ + gint xthickness; + gint ythickness; + + void (*draw_hline) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y); + void (*draw_vline) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x); + void (*draw_shadow) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); + void (*draw_polygon) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *point, + gint npoints, + gint fill); + void (*draw_arrow) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height); + void (*draw_diamond) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); + void (*draw_oval) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); + void (*draw_string) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string); +}; + + +GtkStyle* gtk_style_new (void); +GtkStyle* gtk_style_attach (GtkStyle *style, + GdkWindow *window); +void gtk_style_detach (GtkStyle *style); +GtkStyle *gtk_style_ref (GtkStyle *style); +void gtk_style_unref (GtkStyle *style); +void gtk_style_set_background (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type); + + +void gtk_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y); +void gtk_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x); +void gtk_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill); +void gtk_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_STYLE_H__ */ diff --git a/gtk/gtktable.c b/gtk/gtktable.c new file mode 100644 index 0000000000..7711524dea --- /dev/null +++ b/gtk/gtktable.c @@ -0,0 +1,1178 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtktable.h" + + +static void gtk_table_class_init (GtkTableClass *klass); +static void gtk_table_init (GtkTable *table); +static void gtk_table_destroy (GtkObject *object); +static void gtk_table_map (GtkWidget *widget); +static void gtk_table_unmap (GtkWidget *widget); +static void gtk_table_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_table_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_table_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_table_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_table_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_table_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + +static void gtk_table_size_request_init (GtkTable *table); +static void gtk_table_size_request_pass1 (GtkTable *table); +static void gtk_table_size_request_pass2 (GtkTable *table); +static void gtk_table_size_request_pass3 (GtkTable *table); + +static void gtk_table_size_allocate_init (GtkTable *table); +static void gtk_table_size_allocate_pass1 (GtkTable *table); +static void gtk_table_size_allocate_pass2 (GtkTable *table); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_table_get_type () +{ + static guint table_type = 0; + + if (!table_type) + { + GtkTypeInfo table_info = + { + "GtkTable", + sizeof (GtkTable), + sizeof (GtkTableClass), + (GtkClassInitFunc) gtk_table_class_init, + (GtkObjectInitFunc) gtk_table_init, + (GtkArgFunc) NULL, + }; + + table_type = gtk_type_unique (gtk_container_get_type (), &table_info); + } + + return table_type; +} + +static void +gtk_table_class_init (GtkTableClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_table_destroy; + + widget_class->map = gtk_table_map; + widget_class->unmap = gtk_table_unmap; + widget_class->draw = gtk_table_draw; + widget_class->expose_event = gtk_table_expose; + widget_class->size_request = gtk_table_size_request; + widget_class->size_allocate = gtk_table_size_allocate; + + container_class->add = gtk_table_add; + container_class->remove = gtk_table_remove; + container_class->foreach = gtk_table_foreach; +} + +static void +gtk_table_init (GtkTable *table) +{ + GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW | GTK_BASIC); + + table->children = NULL; + table->rows = NULL; + table->cols = NULL; + table->nrows = 0; + table->ncols = 0; + table->homogeneous = FALSE; +} + +GtkWidget* +gtk_table_new (gint rows, + gint columns, + gint homogeneous) +{ + GtkTable *table; + gint row, col; + + table = gtk_type_new (gtk_table_get_type ()); + + table->nrows = rows; + table->ncols = columns; + table->homogeneous = (homogeneous ? TRUE : FALSE); + + table->rows = g_new (GtkTableRowCol, table->nrows); + table->cols = g_new (GtkTableRowCol, table->ncols); + + for (row = 0; row < table->nrows; row++) + { + table->rows[row].requisition = 0; + table->rows[row].allocation = 0; + table->rows[row].spacing = 0; + table->rows[row].need_expand = 0; + table->rows[row].need_shrink = 0; + table->rows[row].expand = 0; + table->rows[row].shrink = 0; + } + + for (col = 0; col < table->ncols; col++) + { + table->cols[col].requisition = 0; + table->cols[col].allocation = 0; + table->cols[col].spacing = 0; + table->cols[col].need_expand = 0; + table->cols[col].need_shrink = 0; + table->cols[col].expand = 0; + table->cols[col].shrink = 0; + } + + return GTK_WIDGET (table); +} + +void +gtk_table_attach (GtkTable *table, + GtkWidget *child, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach, + gint xoptions, + gint yoptions, + gint xpadding, + gint ypadding) +{ + GtkTableChild *table_child; + + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + g_return_if_fail (child != NULL); + + g_return_if_fail ((left_attach >= 0) && (left_attach < table->ncols)); + g_return_if_fail ((left_attach < right_attach) && (right_attach <= table->ncols)); + g_return_if_fail ((top_attach >= 0) && (top_attach < table->nrows)); + g_return_if_fail ((top_attach < bottom_attach) && (bottom_attach <= table->nrows)); + + table_child = g_new (GtkTableChild, 1); + table_child->widget = child; + table_child->left_attach = left_attach; + table_child->right_attach = right_attach; + table_child->top_attach = top_attach; + table_child->bottom_attach = bottom_attach; + table_child->xexpand = (xoptions & GTK_EXPAND) != 0; + table_child->xshrink = (xoptions & GTK_SHRINK) != 0; + table_child->xfill = (xoptions & GTK_FILL) != 0; + table_child->xpadding = xpadding; + table_child->yexpand = (yoptions & GTK_EXPAND) != 0; + table_child->yshrink = (yoptions & GTK_SHRINK) != 0; + table_child->yfill = (yoptions & GTK_FILL) != 0; + table_child->ypadding = ypadding; + + table->children = g_list_prepend (table->children, table_child); + + gtk_widget_set_parent (child, GTK_WIDGET (table)); + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (table))) + { + if (GTK_WIDGET_REALIZED (GTK_WIDGET (table)) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (child); +} + +void +gtk_table_attach_defaults (GtkTable *table, + GtkWidget *widget, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach) +{ + gtk_table_attach (table, widget, + left_attach, right_attach, + top_attach, bottom_attach, + GTK_EXPAND | GTK_FILL, + GTK_EXPAND | GTK_FILL, + 0, 0); +} + +void +gtk_table_set_row_spacing (GtkTable *table, + gint row, + gint spacing) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + g_return_if_fail ((row >= 0) && (row < (table->nrows - 1))); + + if (table->rows[row].spacing != spacing) + { + table->rows[row].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); + } +} + +void +gtk_table_set_col_spacing (GtkTable *table, + gint column, + gint spacing) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + g_return_if_fail ((column >= 0) && (column < (table->ncols - 1))); + + if (table->cols[column].spacing != spacing) + { + table->cols[column].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); + } +} + +void +gtk_table_set_row_spacings (GtkTable *table, + gint spacing) +{ + gint row; + + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + + for (row = 0; row < table->nrows - 1; row++) + table->rows[row].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); +} + +void +gtk_table_set_col_spacings (GtkTable *table, + gint spacing) +{ + gint col; + + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + + for (col = 0; col < table->ncols - 1; col++) + table->cols[col].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); +} + + +static void +gtk_table_destroy (GtkObject *object) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_TABLE (object)); + + table = GTK_TABLE (object); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + child->widget->parent = NULL; + gtk_object_unref (GTK_OBJECT (child->widget)); + gtk_widget_destroy (child->widget); + g_free (child); + } + + g_list_free (table->children); + g_free (table->rows); + g_free (table->cols); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_table_map (GtkWidget *widget) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + + table = GTK_TABLE (widget); + GTK_WIDGET_SET_FLAGS (table, GTK_MAPPED); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); + } +} + +static void +gtk_table_unmap (GtkWidget *widget) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + + table = GTK_TABLE (widget); + GTK_WIDGET_UNSET_FLAGS (table, GTK_MAPPED); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); + } +} + +static void +gtk_table_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + table = GTK_TABLE (widget); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); + } + } +} + +static gint +gtk_table_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TABLE (widget), FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + table = GTK_TABLE (widget); + + child_event = *event; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static void +gtk_table_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkTable *table; + gint row, col; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + g_return_if_fail (requisition != NULL); + + table = GTK_TABLE (widget); + + requisition->width = 0; + requisition->height = 0; + + gtk_table_size_request_init (table); + gtk_table_size_request_pass1 (table); + gtk_table_size_request_pass2 (table); + gtk_table_size_request_pass3 (table); + gtk_table_size_request_pass2 (table); + + for (col = 0; col < table->ncols; col++) + requisition->width += table->cols[col].requisition; + for (col = 0; col < table->ncols - 1; col++) + requisition->width += table->cols[col].spacing; + + for (row = 0; row < table->nrows; row++) + requisition->height += table->rows[row].requisition; + for (row = 0; row < table->nrows - 1; row++) + requisition->height += table->rows[row].spacing; + + requisition->width += GTK_CONTAINER (table)->border_width * 2; + requisition->height += GTK_CONTAINER (table)->border_width * 2; +} + +static void +gtk_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkTable *table; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + table = GTK_TABLE (widget); + + gtk_table_size_allocate_init (table); + gtk_table_size_allocate_pass1 (table); + gtk_table_size_allocate_pass2 (table); +} + +static void +gtk_table_add (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_TABLE (container)); + g_return_if_fail (widget != NULL); + + gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1); +} + +static void +gtk_table_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_TABLE (container)); + g_return_if_fail (widget != NULL); + + table = GTK_TABLE (container); + children = table->children; + + while (children) + { + child = children->data; + children = children->next; + + if (child->widget == widget) + { + gtk_widget_unparent (widget); + + table->children = g_list_remove (table->children, child); + g_free (child); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + break; + } + } +} + +static void +gtk_table_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_TABLE (container)); + g_return_if_fail (callback != NULL); + + table = GTK_TABLE (container); + children = table->children; + + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child->widget, callback_data); + } +} + +static void +gtk_table_size_request_init (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint row, col; + + for (row = 0; row < table->nrows; row++) + table->rows[row].requisition = 0; + for (col = 0; col < table->ncols; col++) + table->cols[col].requisition = 0; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + gtk_widget_size_request (child->widget, &child->widget->requisition); + } +} + +static void +gtk_table_size_request_pass1 (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint width; + gint height; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + /* Child spans a single column. + */ + if (child->left_attach == (child->right_attach - 1)) + { + width = child->widget->requisition.width + child->xpadding * 2; + table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width); + } + + /* Child spans a single row. + */ + if (child->top_attach == (child->bottom_attach - 1)) + { + height = child->widget->requisition.height + child->ypadding * 2; + table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height); + } + } + } +} + +static void +gtk_table_size_request_pass2 (GtkTable *table) +{ + gint max_width; + gint max_height; + gint row, col; + + if (table->homogeneous) + { + max_width = 0; + max_height = 0; + + for (col = 0; col < table->ncols; col++) + max_width = MAX (max_width, table->cols[col].requisition); + for (row = 0; row < table->nrows; row++) + max_height = MAX (max_height, table->rows[row].requisition); + + for (col = 0; col < table->ncols; col++) + table->cols[col].requisition = max_width; + for (row = 0; row < table->nrows; row++) + table->rows[row].requisition = max_height; + } +} + +static void +gtk_table_size_request_pass3 (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint width, height; + gint row, col; + gint extra; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + /* Child spans multiple columns. + */ + if (child->left_attach != (child->right_attach - 1)) + { + /* Check and see if there is already enough space + * for the child. + */ + width = 0; + for (col = child->left_attach; col < child->right_attach; col++) + { + width += table->cols[col].requisition; + if ((col + 1) < child->right_attach) + width += table->cols[col].spacing; + } + + /* If we need to request more space for this child to fill + * its requisition, then divide up the needed space evenly + * amongst the columns it spans. + */ + if (width < child->widget->requisition.width) + { + width = child->widget->requisition.width - width; + extra = width / (child->right_attach - child->left_attach); + + for (col = child->left_attach; col < child->right_attach; col++) + { + if ((col + 1) < child->right_attach) + table->cols[col].requisition += extra; + else + table->cols[col].requisition += width; + width -= extra; + } + } + } + + /* Child spans multiple rows. + */ + if (child->top_attach != (child->bottom_attach - 1)) + { + /* Check and see if there is already enough space + * for the child. + */ + height = 0; + for (row = child->top_attach; row < child->bottom_attach; row++) + { + height += table->rows[row].requisition; + if ((row + 1) < child->bottom_attach) + height += table->rows[row].spacing; + } + + /* If we need to request more space for this child to fill + * its requisition, then divide up the needed space evenly + * amongst the columns it spans. + */ + if (height < child->widget->requisition.height) + { + height = child->widget->requisition.height - height; + extra = height / (child->bottom_attach - child->top_attach); + + for (row = child->top_attach; row < child->bottom_attach; row++) + { + if ((row + 1) < child->bottom_attach) + table->rows[row].requisition += extra; + else + table->rows[row].requisition += height; + height -= extra; + } + } + } + } + } +} + +static void +gtk_table_size_allocate_init (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint row, col; + gint has_expand; + gint has_shrink; + + /* Initialize the rows and cols. + * By default, rows and cols do not expand and do shrink. + * Those values are modified by the children that occupy + * the rows and cols. + */ + for (col = 0; col < table->ncols; col++) + { + table->cols[col].allocation = table->cols[col].requisition; + table->cols[col].need_expand = FALSE; + table->cols[col].need_shrink = TRUE; + table->cols[col].expand = FALSE; + table->cols[col].shrink = TRUE; + } + for (row = 0; row < table->nrows; row++) + { + table->rows[row].allocation = table->rows[row].requisition; + table->rows[row].need_expand = FALSE; + table->rows[row].need_shrink = TRUE; + table->rows[row].expand = FALSE; + table->rows[row].shrink = TRUE; + } + + /* Loop over all the children and adjust the row and col values + * based on whether the children want to be allowed to expand + * or shrink. This loop handles children that occupy a single + * row or column. + */ + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + if (child->left_attach == (child->right_attach - 1)) + { + if (child->xexpand) + table->cols[child->left_attach].expand = TRUE; + + if (!child->xshrink) + table->cols[child->left_attach].shrink = FALSE; + } + + if (child->top_attach == (child->bottom_attach - 1)) + { + if (child->yexpand) + table->rows[child->top_attach].expand = TRUE; + + if (!child->yshrink) + table->rows[child->top_attach].shrink = FALSE; + } + } + } + + /* Loop over all the children again and this time handle children + * which span multiple rows or columns. + */ + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + if (child->left_attach != (child->right_attach - 1)) + { + if (child->xexpand) + { + has_expand = FALSE; + for (col = child->left_attach; col < child->right_attach; col++) + if (table->cols[col].expand) + { + has_expand = TRUE; + break; + } + + if (!has_expand) + for (col = child->left_attach; col < child->right_attach; col++) + table->cols[col].need_expand = TRUE; + } + + if (!child->xshrink) + { + has_shrink = TRUE; + for (col = child->left_attach; col < child->right_attach; col++) + if (!table->cols[col].shrink) + { + has_shrink = FALSE; + break; + } + + if (has_shrink) + for (col = child->left_attach; col < child->right_attach; col++) + table->cols[col].need_shrink = FALSE; + } + } + + if (child->top_attach != (child->bottom_attach - 1)) + { + if (child->yexpand) + { + has_expand = FALSE; + for (row = child->top_attach; row < child->bottom_attach; row++) + if (table->rows[row].expand) + { + has_expand = TRUE; + break; + } + + if (!has_expand) + for (row = child->top_attach; row < child->bottom_attach; row++) + table->rows[row].need_expand = TRUE; + } + + if (!child->yshrink) + { + has_shrink = TRUE; + for (row = child->top_attach; row < child->bottom_attach; row++) + if (!table->rows[row].shrink) + { + has_shrink = FALSE; + break; + } + + if (has_shrink) + for (row = child->top_attach; row < child->bottom_attach; row++) + table->rows[row].need_shrink = FALSE; + } + } + } + } + + /* Loop over the columns and set the expand and shrink values + * if the column can be expanded or shrunk. + */ + for (col = 0; col < table->ncols; col++) + { + if (table->cols[col].need_expand) + table->cols[col].expand = TRUE; + if (!table->cols[col].need_shrink) + table->cols[col].shrink = FALSE; + } + + /* Loop over the rows and set the expand and shrink values + * if the row can be expanded or shrunk. + */ + for (row = 0; row < table->nrows; row++) + { + if (table->rows[row].need_expand) + table->rows[row].expand = TRUE; + if (!table->rows[row].need_shrink) + table->rows[row].shrink = FALSE; + } +} + +static void +gtk_table_size_allocate_pass1 (GtkTable *table) +{ + gint real_width; + gint real_height; + gint width, height; + gint row, col; + gint nexpand; + gint nshrink; + gint extra; + + /* If we were allocated more space than we requested + * then we have to expand any expandable rows and columns + * to fill in the extra space. + */ + + real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2; + real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2; + + if (table->homogeneous) + { + nexpand = 0; + for (col = 0; col < table->ncols; col++) + if (table->cols[col].expand) + { + nexpand += 1; + break; + } + + if (nexpand > 0) + { + width = real_width; + + for (col = 0; col < table->ncols - 1; col++) + width -= table->cols[col].spacing; + + extra = width / table->ncols; + + for (col = 0; col < table->ncols; col++) + { + if ((col + 1) == table->ncols) + table->cols[col].allocation = width; + else + table->cols[col].allocation = extra; + + width -= extra; + } + } + } + else + { + width = 0; + nexpand = 0; + nshrink = 0; + + for (col = 0; col < table->ncols; col++) + { + width += table->cols[col].requisition; + if (table->cols[col].expand) + nexpand += 1; + if (table->cols[col].shrink) + nshrink += 1; + } + for (col = 0; col < table->ncols - 1; col++) + width += table->cols[col].spacing; + + /* Check to see if we were allocated more width than we requested. + */ + if ((width < real_width) && (nexpand >= 1)) + { + width = real_width - width; + extra = width / nexpand; + + for (col = 0; col < table->ncols; col++) + if (table->cols[col].expand) + { + if (nexpand == 1) + table->cols[col].allocation += width; + else + table->cols[col].allocation += extra; + + width -= extra; + nexpand -= 1; + } + } + + /* Check to see if we were allocated less width than we requested. + */ + if ((width > real_width) && (nshrink >= 1)) + { + width = width - real_width; + extra = width / nshrink; + + for (col = 0; col < table->ncols; col++) + if (table->cols[col].shrink) + { + if (nshrink == 1) + table->cols[col].allocation -= width; + else + table->cols[col].allocation -= extra; + + width -= extra; + nshrink -= 1; + } + } + } + + if (table->homogeneous) + { + nexpand = 0; + for (row = 0; row < table->nrows; row++) + if (table->rows[row].expand) + { + nexpand += 1; + break; + } + + if (nexpand > 0) + { + height = real_height; + + for (row = 0; row < table->nrows - 1; row++) + height -= table->rows[row].spacing; + + extra = height / table->nrows; + + for (row = 0; row < table->nrows; row++) + { + if ((row + 1) == table->nrows) + table->rows[row].allocation = height; + else + table->rows[row].allocation = extra; + + height -= extra; + } + } + } + else + { + height = 0; + nexpand = 0; + nshrink = 0; + + for (row = 0; row < table->nrows; row++) + { + height += table->rows[row].requisition; + if (table->rows[row].expand) + nexpand += 1; + if (table->rows[row].shrink) + nshrink += 1; + } + for (row = 0; row < table->nrows - 1; row++) + height += table->rows[row].spacing; + + /* Check to see if we were allocated more height than we requested. + */ + if ((height < real_height) && (nexpand >= 1)) + { + height = real_height - height; + extra = height / nexpand; + + for (row = 0; row < table->nrows; row++) + if (table->rows[row].expand) + { + if (nexpand == 1) + table->rows[row].allocation += height; + else + table->rows[row].allocation += extra; + + height -= extra; + nexpand -= 1; + } + } + + /* Check to see if we were allocated less height than we requested. + */ + if ((height > real_height) && (nshrink >= 1)) + { + height = height - real_height; + extra = height / nshrink; + + for (row = 0; row < table->nrows; row++) + if (table->rows[row].shrink) + { + if (nshrink == 1) + table->rows[row].allocation -= height; + else + table->rows[row].allocation -= extra; + + height -= extra; + nshrink -= 1; + } + } + } +} + +static void +gtk_table_size_allocate_pass2 (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint max_width; + gint max_height; + gint x, y; + gint row, col; + GtkAllocation allocation; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width; + y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width; + max_width = 0; + max_height = 0; + + for (col = 0; col < child->left_attach; col++) + { + x += table->cols[col].allocation; + x += table->cols[col].spacing; + } + + for (col = child->left_attach; col < child->right_attach; col++) + { + max_width += table->cols[col].allocation; + if ((col + 1) < child->right_attach) + max_width += table->cols[col].spacing; + } + + for (row = 0; row < child->top_attach; row++) + { + y += table->rows[row].allocation; + y += table->rows[row].spacing; + } + + for (row = child->top_attach; row < child->bottom_attach; row++) + { + max_height += table->rows[row].allocation; + if ((row + 1) < child->bottom_attach) + max_height += table->rows[row].spacing; + } + + if (child->xfill) + { + allocation.width = max_width - child->xpadding * 2; + allocation.x = x + (max_width - allocation.width) / 2; + } + else + { + allocation.width = child->widget->requisition.width; + allocation.x = x + (max_width - allocation.width) / 2; + } + + if (child->yfill) + { + allocation.height = max_height - child->ypadding * 2; + allocation.y = y + (max_height - allocation.height) / 2; + } + else + { + allocation.height = child->widget->requisition.height; + allocation.y = y + (max_height - allocation.height) / 2; + } + + gtk_widget_size_allocate (child->widget, &allocation); + } + } +} diff --git a/gtk/gtktable.h b/gtk/gtktable.h new file mode 100644 index 0000000000..f144e78d26 --- /dev/null +++ b/gtk/gtktable.h @@ -0,0 +1,126 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_TABLE_H__ +#define __GTK_TABLE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TABLE(obj) GTK_CHECK_CAST (obj, gtk_table_get_type (), GtkTable) +#define GTK_TABLE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_table_get_type (), GtkTableClass) +#define GTK_IS_TABLE(obj) GTK_CHECK_TYPE (obj, gtk_table_get_type ()) + + +typedef struct _GtkTable GtkTable; +typedef struct _GtkTableClass GtkTableClass; +typedef struct _GtkTableChild GtkTableChild; +typedef struct _GtkTableRowCol GtkTableRowCol; + +struct _GtkTable +{ + GtkContainer container; + + GList *children; + GtkTableRowCol *rows; + GtkTableRowCol *cols; + guint16 nrows; + guint16 ncols; + + guint homogeneous : 1; +}; + +struct _GtkTableClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkTableChild +{ + GtkWidget *widget; + guint16 left_attach; + guint16 right_attach; + guint16 top_attach; + guint16 bottom_attach; + guint16 xpadding; + guint16 ypadding; + guint xexpand : 1; + guint yexpand : 1; + guint xshrink : 1; + guint yshrink : 1; + guint xfill : 1; + guint yfill : 1; +}; + +struct _GtkTableRowCol +{ + guint16 requisition; + guint16 allocation; + guint16 spacing; + guint need_expand : 1; + guint need_shrink : 1; + guint expand : 1; + guint shrink : 1; +}; + + +guint gtk_table_get_type (void); +GtkWidget* gtk_table_new (gint rows, + gint columns, + gint homogeneous); + +void gtk_table_attach (GtkTable *table, + GtkWidget *child, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach, + gint xoptions, + gint yoptions, + gint xpadding, + gint ypadding); +void gtk_table_attach_defaults (GtkTable *table, + GtkWidget *widget, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach); +void gtk_table_set_row_spacing (GtkTable *table, + gint row, + gint spacing); +void gtk_table_set_col_spacing (GtkTable *table, + gint column, + gint spacing); +void gtk_table_set_row_spacings (GtkTable *table, + gint spacing); +void gtk_table_set_col_spacings (GtkTable *table, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TABLE_H__ */ diff --git a/gtk/gtktext.c b/gtk/gtktext.c new file mode 100644 index 0000000000..ae3dd4b5cf --- /dev/null +++ b/gtk/gtktext.c @@ -0,0 +1,3522 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <ctype.h> +#include <string.h> +#include "gdk/gdkkeysyms.h" +#include "gtkmain.h" +#include "gtksignal.h" +#include "gtktext.h" +#include "line-wrap.xbm" +#include "line-arrow.xbm" + + +#define INITIAL_BUFFER_SIZE 1024 +#define INITIAL_LINE_CACHE_SIZE 256 +#define MIN_GAP_SIZE 256 +#define LINE_DELIM '\n' +#define MIN_TEXT_WIDTH_LINES 20 +#define MIN_TEXT_HEIGHT_LINES 10 +#define TEXT_BORDER_ROOM 3 +#define LINE_WRAP_ROOM 8 /* The bitmaps are 6 wide. */ +#define DEFAULT_TAB_STOP_WIDTH 4 +#define SCROLL_PIXELS 5 +#define KEY_SCROLL_PIXELS 10 + +#define SET_PROPERTY_MARK(m, p, o) do { \ + (m)->property = (p); \ + (m)->offset = (o); \ + } while (0) +#define MARK_CURRENT_PROPERTY(mark) ((TextProperty*)(mark)->property->data) +#define MARK_NEXT_PROPERTY(mark) ((TextProperty*)(mark)->property->next->data) +#define MARK_PREV_PROPERTY(mark) ((TextProperty*)((mark)->property->prev ? \ + (mark)->property->prev->data \ + : NULL)) +#define MARK_PREV_LIST_PTR(mark) ((mark)->property->prev) +#define MARK_LIST_PTR(mark) ((mark)->property) +#define MARK_NEXT_LIST_PTR(mark) ((mark)->property->next) +#define MARK_OFFSET(mark) ((mark)->offset) +#define MARK_PROPERTY_LENGTH(mark) (MARK_CURRENT_PROPERTY(mark)->length) +#define MARK_CURRENT_FONT(mark) (((TextProperty*)(mark)->property->data)->font->gdk_font) +#define MARK_CURRENT_FORE(mark) (((TextProperty*)(mark)->property->data)->fore_color) +#define MARK_CURRENT_BACK(mark) (((TextProperty*)(mark)->property->data)->back_color) +#define MARK_CURRENT_TEXT_FONT(m) (((TextProperty*)(m)->property->data)->font) +#define TEXT_INDEX(t, index) ((index) < (t)->gap_position ? (t)->text[index] : \ + (t)->text[(index) + (t)->gap_size]) +#define TEXT_LENGTH(t) ((t)->text_end - (t)->gap_size) +#define FONT_HEIGHT(f) ((f)->ascent + (f)->descent) +#define LINE_HEIGHT(l) ((l).font_ascent + (l).font_descent) +#define LINE_CONTAINS(l, i) ((l).start.index <= (i) && (l).end.index >= (i)) +#define LINE_STARTS_AT(l, i) ((l).start.index == (i)) +#define LINE_START_PIXEL(l) ((l).tab_cont.pixel_offset) +#define LAST_INDEX(t, m) ((m).index == TEXT_LENGTH(t)) +#define CACHE_DATA(c) (*(LineParams*)(c)->data) + + +typedef struct _TextFont TextFont; +typedef struct _TextProperty TextProperty; +typedef struct _TabStopMark TabStopMark; +typedef struct _PrevTabCont PrevTabCont; +typedef struct _FetchLinesData FetchLinesData; +typedef struct _LineParams LineParams; +typedef struct _SetVerticalScrollData SetVerticalScrollData; + +typedef gint (*LineIteratorFunction) (GtkText* text, LineParams* lp, void* data); + +typedef enum +{ + FetchLinesPixels, + FetchLinesCount +} FLType; + +struct _SetVerticalScrollData { + gint pixel_height; + gint last_didnt_wrap; + gint last_line_start; + GtkPropertyMark mark; +}; + +struct _TextFont +{ + /* The actual font. */ + GdkFont *gdk_font; + + gint16 char_widths[256]; +}; + +struct _TextProperty +{ + /* Font. */ + TextFont* font; + + /* Background Color. */ + GdkColor* back_color; + + /* Foreground Color. */ + GdkColor* fore_color; + + /* Length of this property. */ + guint length; +}; + +struct _TabStopMark +{ + GList* tab_stops; /* Index into list containing the next tab position. If + * NULL, using default widths. */ + gint to_next_tab; +}; + +struct _PrevTabCont +{ + guint pixel_offset; + TabStopMark tab_start; +}; + +struct _FetchLinesData +{ + GList* new_lines; + FLType fl_type; + gint data; + gint data_max; +}; + +struct _LineParams +{ + guint font_ascent; + guint font_descent; + guint pixel_width; + guint displayable_chars; + guint wraps : 1; + + PrevTabCont tab_cont; + PrevTabCont tab_cont_next; + + GtkPropertyMark start; + GtkPropertyMark end; +}; + + +static void gtk_text_class_init (GtkTextClass *klass); +static void gtk_text_init (GtkText *text); +static void gtk_text_destroy (GtkObject *object); +static void gtk_text_realize (GtkWidget *widget); +static void gtk_text_unrealize (GtkWidget *widget); +static void gtk_text_draw_focus (GtkWidget *widget); +static void gtk_text_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_text_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_text_adjustment (GtkAdjustment *adjustment, + GtkText *text); +static void gtk_text_disconnect (GtkAdjustment *adjustment, + GtkText *text); + +/* Event handlers */ +static void gtk_text_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_text_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_text_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_text_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_text_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_text_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_text_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_text_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_text_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +static gint gtk_text_selection_request (GtkWidget *widget, + GdkEventSelection *event); +static gint gtk_text_selection_notify (GtkWidget *widget, + GdkEventSelection *event); + +static void move_gap_to_point (GtkText* text); +static void make_forward_space (GtkText* text, guint len); +static void insert_text_property (GtkText* text, GdkFont* font, + GdkColor *fore, GdkColor* back, guint len); +static void delete_text_property (GtkText* text, guint len); +static void init_properties (GtkText *text); +static guint pixel_height_of (GtkText* text, GList* cache_line); + +/* Property Movement and Size Computations */ +static void advance_mark (GtkPropertyMark* mark); +static void decrement_mark (GtkPropertyMark* mark); +static void advance_mark_n (GtkPropertyMark* mark, gint n); +static void decrement_mark_n (GtkPropertyMark* mark, gint n); +static void move_mark_n (GtkPropertyMark* mark, gint n); +static GtkPropertyMark find_mark (GtkText* text, guint mark_position); +static GtkPropertyMark find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near); +static void find_line_containing_point (GtkText* text, guint point); +static TextProperty* new_text_property (GdkFont* font, GdkColor* fore, GdkColor* back, guint length); + +/* Display */ +static gint total_line_height (GtkText* text, + GList* line, + gint line_count); +static LineParams find_line_params (GtkText* text, + const GtkPropertyMark *mark, + const PrevTabCont *tab_cont, + PrevTabCont *next_cont); +static void recompute_geometry (GtkText* text); +static void insert_char_line_expose (GtkText* text, gchar key, guint old_pixels); +static void delete_char_line_expose (GtkText* text, gchar key, guint old_pixels); +static void clear_area (GtkText *text, GdkRectangle *area); +static void draw_line (GtkText* text, + gint pixel_height, + LineParams* lp); +static void draw_line_wrap (GtkText* text, + guint height); +static void draw_cursor (GtkText* text, gint absolute); +static void undraw_cursor (GtkText* text, gint absolute); +static gint drawn_cursor_min (GtkText* text); +static gint drawn_cursor_max (GtkText* text); +static void expose_text (GtkText* text, GdkRectangle *area, gboolean cursor); + +/* Search and Placement. */ +static void find_cursor (GtkText* text); +static void find_cursor_at_line (GtkText* text, + const LineParams* start_line, + gint pixel_height); +static void mouse_click_1 (GtkText* text, GdkEventButton *event); + +/* Scrolling. */ +static void adjust_adj (GtkText* text, GtkAdjustment* adj); +static void scroll_up (GtkText* text, gint diff); +static void scroll_down (GtkText* text, gint diff); +static void scroll_int (GtkText* text, gint diff); + +/* Cache Management. */ +static GList* remove_cache_line (GtkText* text, GList* list); + +/* Key Motion. */ +static void move_cursor_buffer_ver (GtkText *text, int dir); +static void move_cursor_page_ver (GtkText *text, int dir); +static void move_cursor_ver (GtkText *text, int count); +static void move_cursor_hor (GtkText *text, int count); + +/*#define DEBUG_GTK_TEXT*/ + +#if defined(DEBUG_GTK_TEXT) && defined(__GNUC__) +/* Debugging utilities. */ +static void gtk_text_assert_mark (GtkText *text, + GtkPropertyMark *mark, + GtkPropertyMark *before, + GtkPropertyMark *after, + const gchar *msg, + const gchar *where, + gint line); + +static void gtk_text_assert (GtkText *text, + const gchar *msg, + gint line); +static void gtk_text_show_cache_line (GtkText *text, GList *cache, + const char* what, const char* func, gint line); +static void gtk_text_show_cache (GtkText *text, const char* func, gint line); +static void gtk_text_show_adj (GtkText *text, + GtkAdjustment *adj, + const char* what, + const char* func, + gint line); +static void gtk_text_show_props (GtkText* test, + const char* func, + int line); + +#define TDEBUG(args) g_print args +#define TEXT_ASSERT(text) gtk_text_assert (text,__PRETTY_FUNCTION__,__LINE__) +#define TEXT_ASSERT_MARK(text,mark,msg) gtk_text_assert_mark (text,mark, \ + __PRETTY_FUNCTION__,msg,__LINE__) +#define TEXT_SHOW(text) gtk_text_show_cache (text, __PRETTY_FUNCTION__,__LINE__) +#define TEXT_SHOW_LINE(text,line,msg) gtk_text_show_cache_line (text,line,msg,\ + __PRETTY_FUNCTION__,__LINE__) +#define TEXT_SHOW_ADJ(text,adj,msg) gtk_text_show_adj (text,adj,msg, \ + __PRETTY_FUNCTION__,__LINE__) +#else +#define TDEBUG(args) +#define TEXT_ASSERT(text) +#define TEXT_ASSERT_MARK(text,mark,msg) +#define TEXT_SHOW(text) +#define TEXT_SHOW_LINE(text,line,msg) +#define TEXT_SHOW_ADJ(text,adj,msg) +#endif + +/* Memory Management. */ +static GMemChunk *params_mem_chunk = NULL; +static GMemChunk *text_property_chunk = NULL; + +static GtkWidgetClass *parent_class = NULL; + + +/**********************************************************************/ +/* Widget Crap */ +/**********************************************************************/ + +guint +gtk_text_get_type () +{ + static guint text_type = 0; + + if (!text_type) + { + GtkTypeInfo text_info = + { + "GtkText", + sizeof (GtkText), + sizeof (GtkTextClass), + (GtkClassInitFunc) gtk_text_class_init, + (GtkObjectInitFunc) gtk_text_init, + (GtkArgFunc) NULL, + }; + + text_type = gtk_type_unique (gtk_widget_get_type (), &text_info); + } + + return text_type; +} + +static void +gtk_text_class_init (GtkTextClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = gtk_text_destroy; + + widget_class->realize = gtk_text_realize; + widget_class->unrealize = gtk_text_unrealize; + widget_class->draw_focus = gtk_text_draw_focus; + widget_class->size_request = gtk_text_size_request; + widget_class->size_allocate = gtk_text_size_allocate; + widget_class->draw = gtk_text_draw; + widget_class->expose_event = gtk_text_expose; + widget_class->button_press_event = gtk_text_button_press; + widget_class->button_release_event = gtk_text_button_release; + widget_class->motion_notify_event = gtk_text_motion_notify; + widget_class->key_press_event = gtk_text_key_press; + widget_class->focus_in_event = gtk_text_focus_in; + widget_class->focus_out_event = gtk_text_focus_out; + widget_class->selection_clear_event = gtk_text_selection_clear; + widget_class->selection_request_event = gtk_text_selection_request; + widget_class->selection_notify_event = gtk_text_selection_notify; +} + +static void +gtk_text_init (GtkText *text) +{ + GTK_WIDGET_SET_FLAGS (text, GTK_CAN_FOCUS); + + text->text = g_new (guchar, INITIAL_BUFFER_SIZE); + text->text_len = INITIAL_BUFFER_SIZE; + + if (!params_mem_chunk) + params_mem_chunk = g_mem_chunk_new ("LineParams", + sizeof (LineParams), + 256 * sizeof (LineParams), + G_ALLOC_AND_FREE); + + text->default_tab_width = 4; + text->tab_stops = NULL; + + text->tab_stops = g_list_prepend (text->tab_stops, (void*)8); + text->tab_stops = g_list_prepend (text->tab_stops, (void*)8); + + text->line_wrap = TRUE; + text->is_editable = TRUE; +} + +GtkWidget* +gtk_text_new (GtkAdjustment *hadj, + GtkAdjustment *vadj) +{ + GtkText *text; + + text = gtk_type_new (gtk_text_get_type ()); + + gtk_text_set_adjustments (text, hadj, vadj); + + return GTK_WIDGET (text); +} + +void +gtk_text_set_editable (GtkText *text, + gint editable) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + text->is_editable = (editable != FALSE); + text->is_editable = FALSE; /* UNTIL JOSH FIXES IT */ +} + +void +gtk_text_set_adjustments (GtkText *text, + GtkAdjustment *hadj, + GtkAdjustment *vadj) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + if (text->hadj && (text->hadj != hadj)) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (text->hadj), text); + gtk_object_unref (GTK_OBJECT (text->hadj)); + } + + if (text->vadj && (text->vadj != vadj)) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (text->vadj), text); + gtk_object_unref (GTK_OBJECT (text->vadj)); + } + + if (!hadj) + hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + + if (!vadj) + vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + + if (text->hadj != hadj) + { + text->hadj = hadj; + gtk_object_ref (GTK_OBJECT (text->hadj)); + + gtk_signal_connect (GTK_OBJECT (text->hadj), "changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->hadj), "value_changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->hadj), "disconnect", + (GtkSignalFunc) gtk_text_disconnect, + text); + } + + if (text->vadj != vadj) + { + text->vadj = vadj; + gtk_object_ref (GTK_OBJECT (text->vadj)); + + gtk_signal_connect (GTK_OBJECT (text->vadj), "changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->vadj), "value_changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->vadj), "disconnect", + (GtkSignalFunc) gtk_text_disconnect, + text); + } +} + +void +gtk_text_set_point (GtkText *text, + guint index) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + g_return_if_fail (index >= 0 && index <= TEXT_LENGTH (text)) + + text->point = find_mark (text, index); +} + +guint +gtk_text_get_point (GtkText *text) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + return text->point.index; +} + +guint +gtk_text_get_length (GtkText *text) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + return TEXT_LENGTH (text); +} + +void +gtk_text_freeze (GtkText *text) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + text->freeze = TRUE; +} + +void +gtk_text_thaw (GtkText *text) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + text->freeze = FALSE; + + if (GTK_WIDGET_DRAWABLE (text)) + { + recompute_geometry (text); + gtk_widget_queue_draw (GTK_WIDGET (text)); + } +} + +void +gtk_text_insert (GtkText *text, + GdkFont *font, + GdkColor *fore, + GdkColor *back, + const char *chars, + gint length) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + g_assert (GTK_WIDGET_REALIZED (text)); + + /* back may be NULL, fore may not. */ + if (fore == NULL) + fore = &text->widget.style->fg[GTK_STATE_NORMAL]; + + /* This must be because we need to have the style set up. */ + g_assert (GTK_WIDGET_REALIZED(text)); + + if (length < 0) + length = strlen (chars); + + if (length == 0) + return; + + move_gap_to_point (text); + + if (font == NULL) + font = GTK_WIDGET (text)->style->font; + + make_forward_space (text, length); + + memcpy (text->text + text->gap_position, chars, length); + + insert_text_property (text, font, fore, back, length); + + text->gap_size -= length; + text->gap_position += length; + + advance_mark_n (&text->point, length); +} + +gint +gtk_text_backward_delete (GtkText *text, + guint nchars) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + if (nchars > text->point.index || nchars <= 0) + return FALSE; + + gtk_text_set_point (text, text->point.index - nchars); + + return gtk_text_foreward_delete (text, nchars); +} + +gint +gtk_text_foreward_delete (GtkText *text, + guint nchars) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + if (text->point.index + nchars > TEXT_LENGTH (text) || nchars <= 0) + return FALSE; + + move_gap_to_point (text); + + text->gap_size += nchars; + + delete_text_property (text, nchars); + + return TRUE; +} + +static void +gtk_text_destroy (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_TEXT (object)); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_text_realize (GtkWidget *widget) +{ + GtkText *text; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + + text = (GtkText*) widget; + GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, text); + + attributes.x = (widget->style->klass->xthickness + TEXT_BORDER_ROOM); + attributes.y = (widget->style->klass->ythickness + TEXT_BORDER_ROOM); + attributes.width = widget->allocation.width - attributes.x * 2; + attributes.height = widget->allocation.height - attributes.y * 2; + + text->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (text->text_area, text); + + widget->style = gtk_style_attach (widget->style, widget->window); + + /* Can't call gtk_style_set_background here because its handled specially */ + if (!text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + gdk_window_set_background (text->widget.window, &text->widget.style->bg[GTK_STATE_NORMAL]); + + if (!text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + gdk_window_set_background (text->text_area, &text->widget.style->bg[GTK_STATE_NORMAL]); + + text->line_wrap_bitmap = gdk_bitmap_create_from_data (text->text_area, + (gchar*) line_wrap_bits, + line_wrap_width, + line_wrap_height); + + text->line_arrow_bitmap = gdk_bitmap_create_from_data (text->text_area, + (gchar*) line_arrow_bits, + line_arrow_width, + line_arrow_height); + + text->gc = gdk_gc_new (text->text_area); + gdk_gc_set_exposures (text->gc, TRUE); + gdk_gc_set_foreground (text->gc, &widget->style->fg[GTK_STATE_NORMAL]); + + init_properties (text); + + gdk_window_show (text->text_area); +} + +static void +gtk_text_unrealize (GtkWidget *widget) +{ + GtkText *text; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + + text = GTK_TEXT (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + gdk_window_destroy (text->text_area); + gdk_gc_destroy (text->gc); + + widget->window = NULL; + text->text_area = NULL; + text->gc = NULL; +} + +static void +clear_focus_area (GtkText *text, gint area_x, gint area_y, gint area_width, gint area_height) +{ + gint ythick = TEXT_BORDER_ROOM + text->widget.style->klass->ythickness; + gint xthick = TEXT_BORDER_ROOM + text->widget.style->klass->xthickness; + + gint width, height; + gint xorig, yorig; + gint x, y; + + gdk_window_get_size (text->widget.style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); + + yorig = - text->first_onscreen_ver_pixel + ythick; + xorig = - text->first_onscreen_hor_pixel + xthick; + + while (yorig > 0) + yorig -= height; + + while (xorig > 0) + xorig -= width; + + for (y = area_y; y < area_y + area_height; ) + { + gint yoff = (y - yorig) % height; + gint yw = MIN(height - yoff, (area_y + area_height) - y); + + for (x = area_x; x < area_x + area_width; ) + { + gint xoff = (x - xorig) % width; + gint xw = MIN(width - xoff, (area_x + area_width) - x); + + gdk_draw_pixmap (text->widget.window, + text->gc, + text->widget.style->bg_pixmap[GTK_STATE_NORMAL], + xoff, + yoff, + x, + y, + xw, + yw); + + x += width - xoff; + } + y += height - yoff; + } +} + +static void +gtk_text_draw_focus (GtkWidget *widget) +{ + GtkText *text; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + + text = GTK_TEXT (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + TDEBUG (("in gtk_text_draw_focus\n")); + + x = 0; + y = 0; + width = widget->allocation.width; + height = widget->allocation.height; + + if (widget->style->bg_pixmap[GTK_STATE_NORMAL]) + { + gint ythick = TEXT_BORDER_ROOM + widget->style->klass->ythickness; + gint xthick = TEXT_BORDER_ROOM + widget->style->klass->xthickness; + + /* top rect */ + clear_focus_area (text, 0, 0, width, ythick); + /* right rect */ + clear_focus_area (text, 0, ythick, xthick, height - 2 * ythick); + /* left rect */ + clear_focus_area (text, width - xthick, ythick, xthick, height - 2 * ythick); + /* bottom rect */ + clear_focus_area (text, 0, height - ythick, width, ythick); + } + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + + gdk_draw_rectangle (widget->window, + widget->style->fg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + } + else + { + gdk_draw_rectangle (widget->window, + widget->style->white_gc, FALSE, + x + 2, + y + 2, + width - 1 - 2, + height - 1 - 2); + } + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + } + else + { + TDEBUG (("in gtk_text_draw_focus (undrawable !!!)\n")); + } +} + +static void +gtk_text_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + gint xthickness; + gint ythickness; + gint char_height; + gint char_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + g_return_if_fail (requisition != NULL); + + xthickness = widget->style->klass->xthickness + TEXT_BORDER_ROOM; + ythickness = widget->style->klass->ythickness + TEXT_BORDER_ROOM; + + char_height = MIN_TEXT_HEIGHT_LINES * (widget->style->font->ascent + + widget->style->font->descent); + + char_width = MIN_TEXT_WIDTH_LINES * (gdk_text_width (widget->style->font, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + 26) + / 26); + + requisition->width = char_width + xthickness * 2; + requisition->height = char_height + ythickness * 2; +} + +static void +gtk_text_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkText *text; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + g_return_if_fail (allocation != NULL); + + text = GTK_TEXT (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gdk_window_move_resize (text->text_area, + widget->style->klass->xthickness + TEXT_BORDER_ROOM, + widget->style->klass->ythickness + TEXT_BORDER_ROOM, + widget->allocation.width - (widget->style->klass->xthickness + + TEXT_BORDER_ROOM) * 2, + widget->allocation.height - (widget->style->klass->ythickness + + TEXT_BORDER_ROOM) * 2); + + recompute_geometry (text); + } +} + +static void +gtk_text_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + expose_text (GTK_TEXT (widget), area, TRUE); + gtk_widget_draw_focus (widget); + } +} + +static gint +gtk_text_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->window == GTK_TEXT (widget)->text_area) + { + TDEBUG (("in gtk_text_expose (expose)\n")); + expose_text (GTK_TEXT (widget), &event->area, TRUE); + } + else if (event->count == 0) + { + TDEBUG (("in gtk_text_expose (focus)\n")); + gtk_widget_draw_focus (widget); + } + + return FALSE; +} + +static gint +gtk_text_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkText *text; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + text = GTK_TEXT(widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if (event->type == GDK_BUTTON_PRESS && event->button != 2) + gtk_grab_add (widget); + + if (event->button == 1) + { + switch (event->type) + { + case GDK_BUTTON_PRESS: + undraw_cursor (GTK_TEXT (widget), FALSE); + mouse_click_1 (GTK_TEXT (widget), event); + draw_cursor (GTK_TEXT (widget), FALSE); + /* start selection */ + break; + + case GDK_2BUTTON_PRESS: + /* select word */ + break; + + case GDK_3BUTTON_PRESS: + /* select line */ + break; + + default: + break; + } + } + else if (event->type == GDK_BUTTON_PRESS) + { + if (event->button == 2) + { + /* insert selection. */ + } + else + { + /* start selection */ + } + } + + return FALSE; +} + +static gint +gtk_text_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkText *text; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->button != 2) + { + gtk_grab_remove (widget); + + text = GTK_TEXT (widget); + + /* stop selecting. */ + } + + return FALSE; +} + +static gint +gtk_text_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkText *text; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + text = GTK_TEXT (widget); + + x = event->x; + if (event->is_hint || (text->text_area != event->window)) + gdk_window_get_pointer (text->text_area, &x, NULL, NULL); + + /* update selection */ + + return FALSE; +} + +static void +gtk_text_insert_1_at_point (GtkText* text, char key) +{ + gtk_text_insert (text, + MARK_CURRENT_FONT (&text->point), + MARK_CURRENT_FORE (&text->point), + MARK_CURRENT_BACK (&text->point), + &key, 1); +} + +static gint +gtk_text_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkText *text; + gchar key; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return_val = FALSE; + + text = GTK_TEXT (widget); + + if (!return_val) + { + key = event->keyval; + return_val = TRUE; + + if (text->is_editable == FALSE) + { + switch (event->keyval) + { + case GDK_Home: scroll_int (text, -text->vadj->value); break; + case GDK_End: scroll_int (text, +text->vadj->upper); break; + case GDK_Page_Up: scroll_int (text, -text->vadj->page_increment); break; + case GDK_Page_Down: scroll_int (text, +text->vadj->page_increment); break; + case GDK_Up: scroll_int (text, -KEY_SCROLL_PIXELS); break; + case GDK_Down: scroll_int (text, +KEY_SCROLL_PIXELS); break; + default: break; + } + } + else + { + text->point = find_mark (text, text->cursor_mark.index); + + switch (event->keyval) + { + case GDK_Home: move_cursor_buffer_ver (text, -1); break; + case GDK_End: move_cursor_buffer_ver (text, +1); break; + case GDK_Page_Up: move_cursor_page_ver (text, -1); break; + case GDK_Page_Down: move_cursor_page_ver (text, +1); break; + case GDK_Up: move_cursor_ver (text, -1); break; + case GDK_Down: move_cursor_ver (text, +1); break; + case GDK_Left: move_cursor_hor (text, -1); break; + case GDK_Right: move_cursor_hor (text, +1); break; + + case GDK_BackSpace: + if (!text->has_cursor || text->cursor_mark.index == 0) + break; + + gtk_text_backward_delete (text, 1); + break; + case GDK_Delete: + if (!text->has_cursor || LAST_INDEX (text, text->cursor_mark)) + break; + + gtk_text_foreward_delete (text, 1); + break; + case GDK_Tab: + if (!text->has_cursor) + break; + + gtk_text_insert_1_at_point (text, '\t'); + break; + case GDK_Return: + if (!text->has_cursor) + break; + + gtk_text_insert_1_at_point (text, '\n'); + break; + default: + if (!text->has_cursor) + break; + + if ((event->keyval >= 0x20) && (event->keyval <= 0x7e)) + { + return_val = TRUE; + + if (event->state & GDK_CONTROL_MASK) + { + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && text->control_keys[(int) (key - 'a')]) + (* text->control_keys[(int) (key - 'a')]) (text); + } + else if (event->state & GDK_MOD1_MASK) + { + g_message ("alt key"); + + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && text->alt_keys[(int) (key - 'a')]) + (* text->alt_keys[(int) (key - 'a')]) (text); + } + else + { + gtk_text_insert_1_at_point (text, key); + } + } + else + { + return_val = FALSE; + } + break; + } + } + } + + return return_val; +} + +static gint +gtk_text_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + TDEBUG (("in gtk_text_focus_in\n")); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + draw_cursor (GTK_TEXT(widget), TRUE); + + return FALSE; +} + +static gint +gtk_text_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + TDEBUG (("in gtk_text_focus_out\n")); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + undraw_cursor (GTK_TEXT(widget), TRUE); + + return FALSE; +} + +static void +gtk_text_adjustment (GtkAdjustment *adjustment, + GtkText *text) +{ + g_return_if_fail (adjustment != NULL); + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + if (adjustment == text->hadj) + { + g_warning ("horizontal scrolling not implemented"); + } + else + { + gint diff = ((gint)adjustment->value) - text->last_ver_value; + + if (diff != 0) + { + undraw_cursor (text, FALSE); + + if (diff > 0) + scroll_down (text, diff); + else /* if (diff < 0) */ + scroll_up (text, diff); + + draw_cursor (text, FALSE); + + text->last_ver_value = adjustment->value; + } + } +} + +static void +gtk_text_disconnect (GtkAdjustment *adjustment, + GtkText *text) +{ + g_return_if_fail (adjustment != NULL); + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + if (adjustment == text->hadj) + text->hadj = NULL; + if (adjustment == text->vadj) + text->vadj = NULL; +} + + +static GtkPropertyMark +find_this_line_start_mark (GtkText* text, guint point_position, const GtkPropertyMark* near) +{ + GtkPropertyMark mark; + + mark = find_mark_near (text, point_position, near); + + while (mark.index > 0 && + TEXT_INDEX (text, mark.index - 1) != LINE_DELIM) + decrement_mark (&mark); + + return mark; +} + +static void +init_tab_cont (GtkText* text, PrevTabCont* tab_cont) +{ + tab_cont->pixel_offset = 0; + tab_cont->tab_start.tab_stops = text->tab_stops; + tab_cont->tab_start.to_next_tab = (gulong) text->tab_stops->data; + + if (!tab_cont->tab_start.to_next_tab) + tab_cont->tab_start.to_next_tab = text->default_tab_width; +} + +static void +line_params_iterate (GtkText* text, + const GtkPropertyMark* mark0, + const PrevTabCont* tab_mark0, + gint8 alloc, + void* data, + LineIteratorFunction iter) + /* mark0 MUST be a real line start. if ALLOC, allocate line params + * from a mem chunk. DATA is passed to ITER_CALL, which is called + * for each line following MARK, iteration continues unless ITER_CALL + * returns TRUE. */ +{ + GtkPropertyMark mark = *mark0; + PrevTabCont tab_conts[2]; + LineParams *lp, lpbuf; + gint tab_cont_index = 0; + + if (tab_mark0) + tab_conts[0] = *tab_mark0; + else + init_tab_cont (text, tab_conts); + + for (;;) + { + if (alloc) + lp = g_chunk_new (LineParams, params_mem_chunk); + else + lp = &lpbuf; + + *lp = find_line_params (text, &mark, tab_conts + tab_cont_index, + tab_conts + (tab_cont_index + 1) % 2); + + if ((*iter) (text, lp, data)) + return; + + if (LAST_INDEX (text, lp->end)) + break; + + mark = lp->end; + advance_mark (&mark); + tab_cont_index = (tab_cont_index + 1) % 2; + } +} + +static gint +fetch_lines_iterator (GtkText* text, LineParams* lp, void* data) +{ + FetchLinesData *fldata = (FetchLinesData*) data; + + fldata->new_lines = g_list_prepend (fldata->new_lines, lp); + + switch (fldata->fl_type) + { + case FetchLinesCount: + if (!text->line_wrap || !lp->wraps) + fldata->data += 1; + + if (fldata->data >= fldata->data_max) + return TRUE; + + break; + case FetchLinesPixels: + + fldata->data += LINE_HEIGHT(*lp); + + if (fldata->data >= fldata->data_max) + return TRUE; + + break; + } + + return FALSE; +} + +static GList* +fetch_lines (GtkText* text, + const GtkPropertyMark* mark0, + const PrevTabCont* tab_cont0, + FLType fl_type, + gint data) +{ + FetchLinesData fl_data; + + fl_data.new_lines = NULL; + fl_data.data = 0; + fl_data.data_max = data; + fl_data.fl_type = fl_type; + + line_params_iterate (text, mark0, tab_cont0, TRUE, &fl_data, fetch_lines_iterator); + + return g_list_reverse (fl_data.new_lines); +} + +static void +fetch_lines_backward (GtkText* text) +{ + GList* new_lines = NULL, *new_line_start; + + GtkPropertyMark mark = find_this_line_start_mark (text, + CACHE_DATA(text->line_start_cache).start.index - 1, + &CACHE_DATA(text->line_start_cache).start); + + new_line_start = new_lines = fetch_lines (text, &mark, NULL, FetchLinesCount, 1); + + while (new_line_start->next) + new_line_start = new_line_start->next; + + new_line_start->next = text->line_start_cache; + text->line_start_cache->prev = new_line_start; +} + +static void +fetch_lines_forward (GtkText* text, gint line_count) +{ + GtkPropertyMark mark; + GList* line = text->line_start_cache; + + while(line->next) + line = line->next; + + mark = CACHE_DATA(line).end; + + if (LAST_INDEX (text, mark)) + return; + + advance_mark(&mark); + + line->next = fetch_lines (text, &mark, &CACHE_DATA(line).tab_cont_next, FetchLinesCount, line_count); + + if (line->next) + line->next->prev = line; +} + +static gint +total_line_height (GtkText* text, GList* line, gint line_count) +{ + gint height = 0; + + for (; line && line_count > 0; line = line->next) + { + height += LINE_HEIGHT(CACHE_DATA(line)); + + if (!text->line_wrap || !CACHE_DATA(line).wraps) + line_count -= 1; + + if (!line->next) + fetch_lines_forward (text, line_count); + } + + return height; +} + +static void +swap_lines (GtkText* text, GList* old, GList* new, gint old_line_count) +{ + if (old == text->line_start_cache) + { + GList* last; + + for (; old_line_count > 0; old_line_count -= 1) + { + while (text->line_start_cache && + text->line_wrap && + CACHE_DATA(text->line_start_cache).wraps) + remove_cache_line(text, text->line_start_cache); + + remove_cache_line(text, text->line_start_cache); + } + + last = g_list_last (new); + + last->next = text->line_start_cache; + + if (text->line_start_cache) + text->line_start_cache->prev = last; + + text->line_start_cache = new; + } + else + { + GList *last; + + g_assert (old->prev); + + last = old->prev; + + for (; old_line_count > 0; old_line_count -= 1) + { + while (old && text->line_wrap && CACHE_DATA(old).wraps) + old = remove_cache_line (text, old); + + old = remove_cache_line (text, old); + } + + last->next = new; + new->prev = last; + + last = g_list_last (new); + + last->next = old; + + if (old) + old->prev = last; + } +} + +static void +correct_cache_delete (GtkText* text, gint lines) +{ + GList* cache = text->current_line; + gint i; + + for (i = 0; cache && i < lines; i += 1, cache = cache->next) + /* nothing */; + + for (; cache; cache = cache->next) + { + GtkPropertyMark *start = &CACHE_DATA(cache).start; + GtkPropertyMark *end = &CACHE_DATA(cache).end; + + start->index -= 1; + end->index -= 1; + + if (start->property == text->point.property) + start->offset = start->index - (text->point.index - text->point.offset); + + if (end->property == text->point.property) + end->offset = end->index - (text->point.index - text->point.offset); + + /*TEXT_ASSERT_MARK(text, start, "start");*/ + /*TEXT_ASSERT_MARK(text, end, "end");*/ + } +} + +static void +delete_char_line_expose (GtkText* text, gchar key, guint old_pixels) +{ + gint pixel_height; + guint new_pixels = 0; + gint old_line_count = 1 + (key == LINE_DELIM); + GdkRectangle rect; + GList* new_line = NULL; + gint width, height; + + text->cursor_virtual_x = 0; + + undraw_cursor (text, FALSE); + + correct_cache_delete (text, old_line_count); + + pixel_height = pixel_height_of(text, text->current_line) - + LINE_HEIGHT(CACHE_DATA(text->current_line)); + + if (CACHE_DATA(text->current_line).start.index == text->point.index) + CACHE_DATA(text->current_line).start = text->point; + + new_line = fetch_lines (text, + &CACHE_DATA(text->current_line).start, + &CACHE_DATA(text->current_line).tab_cont, + FetchLinesCount, + 1); + + swap_lines (text, text->current_line, new_line, old_line_count); + + text->current_line = new_line; + + new_pixels = total_line_height (text, new_line, 1); + + gdk_window_get_size (text->text_area, &width, &height); + + if (old_pixels != new_pixels) + { + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + pixel_height + old_pixels, + 0, + pixel_height + new_pixels, + width, + height); + + text->vadj->upper += new_pixels; + text->vadj->upper -= old_pixels; + adjust_adj (text, text->vadj); + } + + rect.x = 0; + rect.y = pixel_height; + rect.width = width; + rect.height = new_pixels; + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + text->cursor_mark = text->point; + + find_cursor (text); + + draw_cursor (text, FALSE); + + TEXT_ASSERT (text); + TEXT_SHOW(text); +} + +static void +correct_cache_insert (GtkText* text) +{ + GList* cache = text->current_line; + + for (; cache; cache = cache->next) + { + GtkPropertyMark *start = &CACHE_DATA(cache).start; + GtkPropertyMark *end = &CACHE_DATA(cache).end; + + if (start->index >= text->point.index) + { + if (start->property == text->point.property) + move_mark_n(start, 1); + else + start->index += 1; + } + + if (end->index >= text->point.index) + { + if (end->property == text->point.property) + move_mark_n(end, 1); + else + end->index += 1; + } + + /*TEXT_ASSERT_MARK(text, start, "start");*/ + /*TEXT_ASSERT_MARK(text, end, "end");*/ + } +} + + +static void +insert_char_line_expose (GtkText* text, gchar key, guint old_pixels) +{ + gint pixel_height; + guint new_pixels = 0; + guint new_line_count = 1 + (key == LINE_DELIM); + GdkRectangle rect; + GList* new_line = NULL; + gint width, height; + + text->cursor_virtual_x = 0; + + undraw_cursor (text, FALSE); + + correct_cache_insert (text); + + TEXT_SHOW_ADJ (text, text->vadj, "vadj"); + + pixel_height = pixel_height_of(text, text->current_line) - + LINE_HEIGHT(CACHE_DATA(text->current_line)); + + new_line = fetch_lines (text, + &CACHE_DATA(text->current_line).start, + &CACHE_DATA(text->current_line).tab_cont, + FetchLinesCount, + new_line_count); + + swap_lines (text, text->current_line, new_line, 1); + + text->current_line = new_line; + + new_pixels = total_line_height (text, new_line, new_line_count); + + gdk_window_get_size (text->text_area, &width, &height); + + if (old_pixels != new_pixels) + { + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + pixel_height + old_pixels, + 0, + pixel_height + new_pixels, + width, + height + (old_pixels - new_pixels) - pixel_height); + + text->vadj->upper += new_pixels; + text->vadj->upper -= old_pixels; + adjust_adj (text, text->vadj); + } + + rect.x = 0; + rect.y = pixel_height; + rect.width = width; + rect.height = new_pixels; + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + text->cursor_mark = text->point; + + find_cursor (text); + + draw_cursor (text, FALSE); + + TEXT_SHOW_ADJ (text, text->vadj, "vadj"); + TEXT_ASSERT (text); + TEXT_SHOW(text); +} + +static guint +font_hash (gpointer font) +{ + return gdk_font_id ((GdkFont*) font); +} + +static TextFont* +get_text_font (GdkFont* gfont) +{ + static GHashTable *font_cache_table = NULL; + TextFont* tf; + gpointer lu; + gint i; + + if (!font_cache_table) + font_cache_table = g_hash_table_new (font_hash, (GCompareFunc) gdk_font_equal); + + lu = g_hash_table_lookup (font_cache_table, gfont); + + if (lu) + return (TextFont*)lu; + + tf = g_new (TextFont, 1); + + tf->gdk_font = gfont; + + for(i = 0; i < 256; i += 1) + tf->char_widths[i] = gdk_char_width (gfont, (char)i); + + g_hash_table_insert (font_cache_table, gfont, tf); + + return tf; +} + +static gint +text_properties_equal (TextProperty* prop, GdkFont* font, GdkColor *fore, GdkColor *back) +{ + return prop->font == get_text_font(font) && + (fore == prop->fore_color || gdk_color_equal(prop->fore_color, fore)) && + (back == prop->back_color || (back && prop->back_color && gdk_color_equal(prop->back_color, back))); +} + +static TextProperty* +new_text_property (GdkFont* font, GdkColor* fore, GdkColor* back, guint length) +{ + TextProperty *prop; + + if (text_property_chunk == NULL) + { + text_property_chunk = g_mem_chunk_new ("text property mem chunk", + sizeof(TextProperty), + 1024*sizeof(TextProperty), + G_ALLOC_ONLY); + } + + prop = g_chunk_new(TextProperty, text_property_chunk); + + prop->font = get_text_font (font); + prop->fore_color = fore; + prop->back_color = back; + prop->length = length; + + return prop; +} + +/* Flop the memory between the point and the gap around like a + * dead fish. */ +static void +move_gap_to_point (GtkText* text) +{ + if (text->gap_position < text->point.index) + { + gint diff = text->point.index - text->gap_position; + + memmove (text->text + text->gap_position, + text->text + text->gap_position + text->gap_size, + diff); + + text->gap_position = text->point.index; + } + else if (text->gap_position > text->point.index) + { + gint diff = text->gap_position - text->point.index; + + memmove (text->text + text->point.index + text->gap_size, + text->text + text->point.index, + diff); + + text->gap_position = text->point.index; + } +} + +/* Increase the gap size. */ +static void +make_forward_space (GtkText* text, guint len) +{ + if (text->gap_size < len) + { + guint sum = MAX(2*len, MIN_GAP_SIZE) + text->text_end; + + if (sum >= text->text_len) + { + guint i = 1; + + while (i <= sum) i <<= 1; + + text->text = (guchar*)g_realloc(text->text, i); + } + + memmove (text->text + text->gap_position + text->gap_size + 2*len, + text->text + text->gap_position + text->gap_size, + text->text_end - (text->gap_position + text->gap_size)); + + text->text_end += len*2; + text->gap_size += len*2; + } +} + +/* Inserts into the text property list a list element that guarantees + * that for len characters following the point, text has the correct + * property. does not move point. adjusts text_properties_point and + * text_properties_point_offset relative to the current value of + * point. */ +static void +insert_text_property (GtkText* text, GdkFont* font, + GdkColor *fore, GdkColor* back, guint len) +{ + GtkPropertyMark *mark = &text->point; + TextProperty* forward_prop = MARK_CURRENT_PROPERTY(mark); + TextProperty* backward_prop = MARK_PREV_PROPERTY(mark); + + if (MARK_OFFSET(mark) == 0) + { + /* Point is on the boundary of two properties. + * If it is the same as either, grow, else insert + * a new one. */ + + if (text_properties_equal(forward_prop, font, fore, back)) + { + /* Grow the property in front of us. */ + + MARK_PROPERTY_LENGTH(mark) += len; + } + else if (backward_prop && + text_properties_equal(backward_prop, font, fore, back)) + { + /* Grow property behind us, point property and offset + * change. */ + + SET_PROPERTY_MARK (&text->point, + MARK_PREV_LIST_PTR (mark), + backward_prop->length); + + backward_prop->length += len; + } + else + { + /* Splice a new property into the list. */ + + GList* new_prop = g_list_alloc(); + + new_prop->next = MARK_LIST_PTR(mark); + new_prop->prev = MARK_PREV_LIST_PTR(mark); + new_prop->next->prev = new_prop; + + if (new_prop->prev) + new_prop->prev->next = new_prop; + + new_prop->data = new_text_property (font, fore, back, len); + + SET_PROPERTY_MARK (mark, new_prop, 0); + } + } + else + { + /* In the middle of forward_prop, if properties are equal, + * just add to its length, else split it into two and splice + * in a new one. */ + if (text_properties_equal (forward_prop, font, fore, back)) + { + forward_prop->length += len; + } + else + { + GList* new_prop = g_list_alloc(); + GList* new_prop_forward = g_list_alloc(); + gint old_length = forward_prop->length; + GList* next = MARK_NEXT_LIST_PTR(mark); + + /* Set the new lengths according to where they are split. Construct + * two new properties. */ + forward_prop->length = MARK_OFFSET(mark); + + new_prop_forward->data = new_text_property(forward_prop->font->gdk_font, + fore, + back, + old_length - forward_prop->length); + + new_prop->data = new_text_property(font, fore, back, len); + + /* Now splice things in. */ + MARK_NEXT_LIST_PTR(mark) = new_prop; + new_prop->prev = MARK_LIST_PTR(mark); + + new_prop->next = new_prop_forward; + new_prop_forward->prev = new_prop; + + new_prop_forward->next = next; + + if (next) + next->prev = new_prop_forward; + + SET_PROPERTY_MARK (mark, new_prop, 0); + } + } + + while (text->text_properties_end->next) + text->text_properties_end = text->text_properties_end->next; + + while (text->text_properties->prev) + text->text_properties = text->text_properties->prev; +} + +static void +delete_text_property (GtkText* text, guint nchars) +{ + /* Delete nchars forward from point. */ + TextProperty *prop; + GList *tmp; + gint is_first; + + for(; nchars; nchars -= 1) + { + prop = MARK_CURRENT_PROPERTY(&text->point); + + prop->length -= 1; + + if (prop->length == 0) + { + tmp = MARK_LIST_PTR (&text->point); + + is_first = tmp == text->text_properties; + + MARK_LIST_PTR (&text->point) = g_list_remove_link (tmp, tmp); + text->point.offset = 0; + + g_mem_chunk_free (text_property_chunk, prop); + + prop = MARK_CURRENT_PROPERTY (&text->point); + + if (is_first) + text->text_properties = MARK_LIST_PTR (&text->point); + + g_assert (prop->length != 0); + } + else if (prop->length == text->point.offset) + { + MARK_LIST_PTR (&text->point) = MARK_NEXT_LIST_PTR (&text->point); + text->point.offset = 0; + } + } +} + +static void +init_properties (GtkText *text) +{ + if (!text->text_properties) + { + text->text_properties = g_list_alloc(); + text->text_properties->next = NULL; + text->text_properties->prev = NULL; + text->text_properties->data = new_text_property (text->widget.style->font, + &text->widget.style->fg[GTK_STATE_NORMAL], + &text->widget.style->bg[GTK_STATE_NORMAL], + 1); + text->text_properties_end = text->text_properties; + + SET_PROPERTY_MARK (&text->point, text->text_properties, 0); + + text->point.index = 0; + } +} + + +/**********************************************************************/ +/* Property Movement */ +/**********************************************************************/ + +static void +move_mark_n (GtkPropertyMark* mark, gint n) +{ + if (n > 0) + advance_mark_n(mark, n); + else if (n < 0) + decrement_mark_n(mark, -n); +} + +static void +advance_mark_n (GtkPropertyMark* mark, gint n) +{ + gint i; + + g_assert (n > 0); + + for (i = 0; i < n; i += 1) + advance_mark (mark); +} + +static void +advance_mark (GtkPropertyMark* mark) +{ + TextProperty* prop = MARK_CURRENT_PROPERTY (mark); + + mark->index += 1; + + if (prop->length > mark->offset + 1) + mark->offset += 1; + else + { + mark->property = MARK_NEXT_LIST_PTR (mark); + mark->offset = 0; + } +} + +static void +decrement_mark (GtkPropertyMark* mark) +{ + mark->index -= 1; + + if (mark->offset > 0) + mark->offset -= 1; + else + { + mark->property = MARK_PREV_LIST_PTR (mark); + mark->offset = MARK_CURRENT_PROPERTY (mark)->length - 1; + } +} + +static void +decrement_mark_n (GtkPropertyMark* mark, gint n) +{ + gint i; + + g_assert (n > 0); + + for (i = 0; i < n; i += 1) + decrement_mark (mark); +} + +static GtkPropertyMark +find_mark (GtkText* text, guint mark_position) +{ + return find_mark_near (text, mark_position, &text->point); +} + +/* This can be optimized in two ways. + * First, advances can be made in units of the current TextProperty + * length, when possible. This will reduce computation and function + * call overhead. + * + * You can also start from the end, what a drag. + */ +static GtkPropertyMark +find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near) +{ + gint diffa; + gint diffb; + + GtkPropertyMark mark; + + if (!near) + diffa = mark_position + 1; + else + diffa = mark_position - near->index; + + diffb = mark_position; + + if (diffa < 0) + diffa = -diffa; + + if (diffa <= diffb) + { + mark = *near; + } + else + { + mark.index = 0; + mark.property = text->text_properties; + mark.offset = 0; + } + + if (mark.index > mark_position) + { + while (mark.index > mark_position) + decrement_mark (&mark); + } + else + { + while (mark_position > mark.index) + advance_mark (&mark); + } + + return mark; +} + +static void +find_line_containing_point (GtkText* text, guint point) +{ + GList* cache; + gint height; + + text->current_line = NULL; + + if (!text->line_start_cache->next) + { + /* @@@ Its visible, right? */ + text->current_line = text->line_start_cache; + return; + } + + while ( ( (text->first_cut_pixels != 0) && + (CACHE_DATA(text->line_start_cache->next).start.index > point) ) || + ( (text->first_cut_pixels == 0) && + (CACHE_DATA(text->line_start_cache).start.index > point) ) ) + { + scroll_int (text, - SCROLL_PIXELS); + g_assert (text->line_start_cache->next); + } + + TEXT_SHOW (text); + gdk_window_get_size (text->text_area, NULL, &height); + + for (cache = text->line_start_cache; cache; cache = cache->next) + { + guint lph; + + if (CACHE_DATA(cache).end.index >= point || + LAST_INDEX(text, CACHE_DATA(cache).end)) + { + text->current_line = cache; /* LOOK HERE, this proc has an + * important side effect. */ + return; + } + + TEXT_SHOW_LINE (text, cache, "cache"); + + lph = pixel_height_of (text, cache->next); + + while (lph > height || lph == 0) + { + TEXT_SHOW_LINE (text, cache, "cache"); + TEXT_SHOW_LINE (text, cache->next, "cache->next"); + scroll_int (text, LINE_HEIGHT(CACHE_DATA(cache->next))); + lph = pixel_height_of (text, cache->next); + } + } + + g_assert (FALSE); /* Must set text->current_line here */ +} + +static guint +pixel_height_of (GtkText* text, GList* cache_line) +{ + gint pixels = - text->first_cut_pixels; + GList *cache = text->line_start_cache; + + while (TRUE) { + pixels += LINE_HEIGHT (CACHE_DATA(cache)); + + if (cache->data == cache_line->data) + break; + + cache = cache->next; + } + + return pixels; +} + +/**********************************************************************/ +/* Search and Placement */ +/**********************************************************************/ + +static gint +find_char_width (GtkText* text, const GtkPropertyMark *mark, const TabStopMark *tab_mark) +{ + gchar ch = TEXT_INDEX (text, mark->index); + gint16* char_widths = MARK_CURRENT_TEXT_FONT (mark)->char_widths; + + if (ch == '\t') + { + return tab_mark->to_next_tab * char_widths[' ']; + } + else + { + return char_widths[ch & 0xff]; + } +} + +static void +advance_tab_mark (GtkText* text, TabStopMark* tab_mark, gchar ch) +{ + if (tab_mark->to_next_tab == 1 || ch == '\t') + { + if (tab_mark->tab_stops->next) + { + tab_mark->tab_stops = tab_mark->tab_stops->next; + tab_mark->to_next_tab = (gulong) tab_mark->tab_stops->data; + } + else + { + tab_mark->to_next_tab = text->default_tab_width; + } + } + else + { + tab_mark->to_next_tab -= 1; + } +} + +static void +advance_tab_mark_n (GtkText* text, TabStopMark* tab_mark, gint n) + /* No tabs! */ +{ + while (n--) + advance_tab_mark (text, tab_mark, 0); +} + +static void +find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height) +{ + gchar ch; + + GtkPropertyMark mark = start_line->start; + TabStopMark tab_mark = start_line->tab_cont.tab_start; + gint pixel_width = LINE_START_PIXEL (*start_line); + + while (mark.index < text->cursor_mark.index) + { + pixel_width += find_char_width (text, &mark, &tab_mark); + + advance_tab_mark (text, &tab_mark, TEXT_INDEX(text, mark.index)); + advance_mark (&mark); + } + + text->cursor_pos_x = pixel_width; + text->cursor_pos_y = pixel_height; + text->cursor_char_offset = start_line->font_descent; + text->cursor_mark = mark; + + ch = TEXT_INDEX (text, mark.index); + + if (!isspace(ch)) + text->cursor_char = ch; + else + text->cursor_char = 0; +} + +static void +find_cursor (GtkText* text) +{ + if (!text->has_cursor) + return; + + find_line_containing_point (text, text->cursor_mark.index); + + g_assert (text->cursor_mark.index >= text->first_line_start_index); + + if (text->current_line) + find_cursor_at_line (text, + &CACHE_DATA(text->current_line), + pixel_height_of(text, text->current_line)); +} + +static void +mouse_click_1_at_line (GtkText *text, const LineParams* lp, + guint line_pixel_height, + gint button_x) +{ + GtkPropertyMark mark = lp->start; + TabStopMark tab_mark = lp->tab_cont.tab_start; + + guint char_width = find_char_width(text, &mark, &tab_mark); + guint pixel_width = LINE_START_PIXEL (*lp) + (char_width+1)/2; + + text->cursor_pos_y = line_pixel_height; + + for (;;) + { + gchar ch = TEXT_INDEX (text, mark.index); + + if (button_x < pixel_width || mark.index == lp->end.index) + { + text->cursor_pos_x = pixel_width - (char_width+1)/2; + text->cursor_mark = mark; + text->cursor_char_offset = lp->font_descent; + + if (!isspace(ch)) + text->cursor_char = ch; + else + text->cursor_char = 0; + + break; + } + + advance_tab_mark (text, &tab_mark, ch); + advance_mark (&mark); + + pixel_width += char_width/2; + + char_width = find_char_width (text, &mark, &tab_mark); + + pixel_width += (char_width+1)/2; + } +} + +static void +mouse_click_1 (GtkText* text, GdkEventButton *event) +{ + if (text->is_editable) + { + gint pixel_height; + GList* cache = text->line_start_cache; + + g_assert (cache); + + pixel_height = - text->first_cut_pixels; + + text->has_cursor = 1; + + for (; cache; cache = cache->next) + { + pixel_height += LINE_HEIGHT(CACHE_DATA(cache)); + + if (event->y < pixel_height || !cache->next) + { + mouse_click_1_at_line (text, &CACHE_DATA(cache), pixel_height, event->x); + + find_cursor (text); + + return; + } + } + } +} + +/**********************************************************************/ +/* Cache Manager */ +/**********************************************************************/ + +static void +free_cache (GtkText* text) +{ + GList* cache = text->line_start_cache; + + for (; cache; cache = cache->next) + g_mem_chunk_free (params_mem_chunk, cache->data); + + g_list_free (text->line_start_cache); + + text->line_start_cache = NULL; +} + +static GList* +remove_cache_line (GtkText* text, GList* member) +{ + if (member == text->line_start_cache) + { + if (text->line_start_cache) + text->line_start_cache = text->line_start_cache->next; + return text->line_start_cache; + } + else + { + GList *list = member->prev; + + list->next = list->next->next; + if (list->next) + list->next->prev = list; + + member->next = NULL; + g_mem_chunk_free (params_mem_chunk, member->data); + g_list_free (member); + + return list->next; + } +} + +/**********************************************************************/ +/* Key Motion */ +/**********************************************************************/ + +static void +move_cursor_buffer_ver (GtkText *text, int dir) +{ + if (dir > 0) + scroll_int (text, text->vadj->upper); + else + scroll_int (text, - text->vadj->value); +} + +static void +move_cursor_page_ver (GtkText *text, int dir) +{ + scroll_int (text, dir * text->vadj->page_increment); +} + +static void +move_cursor_ver (GtkText *text, int count) +{ + gint i; + GtkPropertyMark mark; + gint offset; + + if (!text->has_cursor) + { + scroll_int (text, count * KEY_SCROLL_PIXELS); + return; + } + + mark = find_this_line_start_mark (text, text->cursor_mark.index, &text->cursor_mark); + offset = text->cursor_mark.index - mark.index; + + if (offset > text->cursor_virtual_x) + text->cursor_virtual_x = offset; + + if (count < 0) + { + if (mark.index == 0) + return; + + decrement_mark (&mark); + mark = find_this_line_start_mark (text, mark.index, &mark); + } + else + { + mark = text->cursor_mark; + + while (!LAST_INDEX(text, mark) && TEXT_INDEX(text, mark.index) != LINE_DELIM) + advance_mark (&mark); + + if (LAST_INDEX(text, mark)) + return; + + advance_mark (&mark); + } + + for (i=0; i < text->cursor_virtual_x; i += 1, advance_mark(&mark)) + if (LAST_INDEX(text, mark) || TEXT_INDEX(text, mark.index) == LINE_DELIM) + break; + + undraw_cursor (text, FALSE); + + text->cursor_mark = mark; + + find_cursor (text); + + draw_cursor (text, FALSE); +} + +static void +move_cursor_hor (GtkText *text, int count) +{ + /* count should be +-1. */ + if (!text->has_cursor) + return; + + if ( (count > 0 && text->cursor_mark.index + count > TEXT_LENGTH(text)) || + (count < 0 && text->cursor_mark.index < (- count)) || + (count == 0) ) + return; + + text->cursor_virtual_x = 0; + + undraw_cursor (text, FALSE); + + move_mark_n (&text->cursor_mark, count); + + find_cursor (text); + + draw_cursor (text, FALSE); +} + +/**********************************************************************/ +/* Scrolling */ +/**********************************************************************/ + +static void +adjust_adj (GtkText* text, GtkAdjustment* adj) +{ + gint height; + + gdk_window_get_size (text->text_area, NULL, &height); + + adj->step_increment = MIN (adj->upper, (float) SCROLL_PIXELS); + adj->page_increment = MIN (adj->upper, height - (float) KEY_SCROLL_PIXELS); + adj->page_size = MIN (adj->upper, height); + adj->value = MIN (adj->value, adj->upper - adj->page_size); + adj->value = MAX (adj->value, 0.0); + + gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed"); +} + +static gint +set_vertical_scroll_iterator (GtkText* text, LineParams* lp, void* data) +{ + gint *pixel_count = (gint*) data; + + if (text->first_line_start_index == lp->start.index) + text->vadj->value = (float) *pixel_count; + + *pixel_count += LINE_HEIGHT (*lp); + + return FALSE; +} + +static gint +set_vertical_scroll_find_iterator (GtkText* text, LineParams* lp, void* data) +{ + SetVerticalScrollData *svdata = (SetVerticalScrollData *) data; + gint return_val; + + if (svdata->last_didnt_wrap) + svdata->last_line_start = lp->start.index; + + if (svdata->pixel_height <= (gint) text->vadj->value && + svdata->pixel_height + LINE_HEIGHT(*lp) > (gint) text->vadj->value) + { + svdata->mark = lp->start; + + text->first_cut_pixels = (gint)text->vadj->value - svdata->pixel_height; + text->first_onscreen_ver_pixel = svdata->pixel_height; + text->first_line_start_index = svdata->last_line_start; + + return_val = TRUE; + } + else + { + svdata->pixel_height += LINE_HEIGHT (*lp); + + return_val = FALSE; + } + + if (!lp->wraps) + svdata->last_didnt_wrap = TRUE; + else + svdata->last_didnt_wrap = FALSE; + + return return_val; +} + +static GtkPropertyMark +set_vertical_scroll (GtkText* text) +{ + GtkPropertyMark mark = find_mark (text, 0); + SetVerticalScrollData data; + gint height; + gint pixel_count = 0; + gint orig_value; + + line_params_iterate (text, &mark, NULL, FALSE, &pixel_count, set_vertical_scroll_iterator); + + text->vadj->upper = (float) pixel_count; + orig_value = (gint) text->vadj->value; + + gdk_window_get_size (text->text_area, NULL, &height); + + text->vadj->step_increment = MIN (text->vadj->upper, (float) SCROLL_PIXELS); + text->vadj->page_increment = MIN (text->vadj->upper, height - (float) KEY_SCROLL_PIXELS); + text->vadj->page_size = MIN (text->vadj->upper, height); + text->vadj->value = MIN (text->vadj->value, text->vadj->upper - text->vadj->page_size); + text->vadj->value = MAX (text->vadj->value, 0.0); + + text->last_ver_value = (gint)text->vadj->value; + text->first_cut_pixels = 0; + + gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "changed"); + + if (text->vadj->value != orig_value) + { + /* We got clipped, and don't really know which line to put first. */ + data.pixel_height = 0; + data.last_didnt_wrap = TRUE; + + line_params_iterate (text, &mark, NULL, + FALSE, &data, + set_vertical_scroll_find_iterator); + + return data.mark; + } + else + { + return find_mark (text, text->first_line_start_index); + } +} + +static void +scroll_int (GtkText* text, gint diff) +{ + gfloat upper; + + text->vadj->value += diff; + + upper = text->vadj->upper - text->vadj->page_size; + text->vadj->value = MIN (text->vadj->value, upper); + text->vadj->value = MAX (text->vadj->value, 0.0); + + gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "value_changed"); +} + +static gint last_visible_line_height (GtkText* text) +{ + GList *cache = text->line_start_cache; + gint height; + + gdk_window_get_size (text->text_area, NULL, &height); + + for (; cache->next; cache = cache->next) + if (pixel_height_of(text, cache->next) > height) + break; + + if (cache) + return pixel_height_of(text, cache) - 1; + else + return 0; +} + +static gint first_visible_line_height (GtkText* text) +{ + if (text->first_cut_pixels) + return pixel_height_of(text, text->line_start_cache) + 1; + else + return 1; +} + +static void +scroll_down (GtkText* text, gint diff0) +{ + GdkRectangle rect; + gint real_diff = 0; + gint width, height; + + text->first_onscreen_ver_pixel += diff0; + + while (diff0-- > 0) + { + g_assert (text->line_start_cache && + text->line_start_cache->next); + + if (text->first_cut_pixels < LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1) + { + text->first_cut_pixels += 1; + } + else + { + text->first_cut_pixels = 0; + + text->line_start_cache = text->line_start_cache->next; + + text->first_line_start_index = + CACHE_DATA(text->line_start_cache).start.index; + + if (!text->line_start_cache->next) + fetch_lines_forward (text, 1); + } + + real_diff += 1; + } + + gdk_window_get_size (text->text_area, &width, &height); + if (height > real_diff) + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + real_diff, + 0, + 0, + width, + height - real_diff); + + rect.x = 0; + rect.y = MAX (0, height - real_diff); + rect.width = width; + rect.height = MIN (height, real_diff); + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + if (text->current_line) + { + gint cursor_min; + + text->cursor_pos_y -= real_diff; + cursor_min = drawn_cursor_min(text); + + if (cursor_min < 0) + { + GdkEventButton button; + + button.x = text->cursor_pos_x; + button.y = first_visible_line_height (text); + + mouse_click_1 (text, &button); + } + } +} + +static void +scroll_up (GtkText* text, gint diff0) +{ + gint real_diff = 0; + GdkRectangle rect; + gint width, height; + + text->first_onscreen_ver_pixel += diff0; + + while (diff0++ < 0) + { + g_assert (text->line_start_cache); + + if (text->first_cut_pixels > 0) + { + text->first_cut_pixels -= 1; + } + else + { + if (!text->line_start_cache->prev) + fetch_lines_backward (text); + + text->line_start_cache = text->line_start_cache->prev; + + text->first_line_start_index = + CACHE_DATA(text->line_start_cache).start.index; + + text->first_cut_pixels = LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1; + } + + real_diff += 1; + } + + gdk_window_get_size (text->text_area, &width, &height); + if (height > real_diff) + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + 0, + 0, + real_diff, + width, + height - real_diff); + + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = MIN (height, real_diff); + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + if (text->current_line) + { + gint cursor_max; + gint height; + + text->cursor_pos_y += real_diff; + cursor_max = drawn_cursor_max(text); + gdk_window_get_size (text->text_area, NULL, &height); + + if (cursor_max >= height) + { + GdkEventButton button; + + button.x = text->cursor_pos_x; + button.y = last_visible_line_height(text); + + mouse_click_1 (text, &button); + } + } +} + +/**********************************************************************/ +/* Display Code */ +/**********************************************************************/ + +/* Assumes mark starts a line. Calculates the height, width, and + * displayable character count of a single DISPLAYABLE line. That + * means that in line-wrap mode, this does may not compute the + * properties of an entire line. */ +static LineParams +find_line_params (GtkText* text, + const GtkPropertyMark* mark, + const PrevTabCont *tab_cont, + PrevTabCont *next_cont) +{ + LineParams lp; + TabStopMark tab_mark = tab_cont->tab_start; + guint max_display_pixels; + gchar ch; + gint ch_width; + GdkFont *font; + + gdk_window_get_size (text->text_area, (gint*) &max_display_pixels, NULL); + max_display_pixels -= LINE_WRAP_ROOM; + + lp.wraps = 0; + lp.tab_cont = *tab_cont; + lp.start = *mark; + lp.end = *mark; + lp.pixel_width = tab_cont->pixel_offset; + lp.displayable_chars = 0; + lp.font_ascent = 0; + lp.font_descent = 0; + + init_tab_cont (text, next_cont); + + while (!LAST_INDEX(text, lp.end)) + { + g_assert (lp.end.property); + + ch = TEXT_INDEX (text, lp.end.index); + font = MARK_CURRENT_FONT (&lp.end); + + if (ch == LINE_DELIM) + { + /* Newline doesn't count in computation of line height, even + * if its in a bigger font than the rest of the line. Unless, + * of course, there are no other characters. */ + + if (!lp.font_ascent && !lp.font_descent) + { + lp.font_ascent = font->ascent; + lp.font_descent = font->descent; + } + + lp.tab_cont_next = *next_cont; + + return lp; + } + + ch_width = find_char_width (text, &lp.end, &tab_mark); + + if (ch_width + lp.pixel_width > max_display_pixels) + { + lp.wraps = 1; + + if (text->line_wrap) + { + next_cont->tab_start = tab_mark; + next_cont->pixel_offset = 0; + + if (ch == '\t') + { + /* Here's the tough case, a tab is wrapping. */ + gint pixels_avail = max_display_pixels - lp.pixel_width; + gint space_width = MARK_CURRENT_TEXT_FONT(&lp.end)->char_widths[' ']; + gint spaces_avail = pixels_avail / space_width; + + if (spaces_avail == 0) + { + decrement_mark (&lp.end); + } + else + { + advance_tab_mark (text, &next_cont->tab_start, '\t'); + next_cont->pixel_offset = space_width * (tab_mark.to_next_tab - + spaces_avail); + lp.displayable_chars += 1; + } + } + else + { + /* Don't include this character, it will wrap. */ + decrement_mark (&lp.end); + } + + lp.tab_cont_next = *next_cont; + + return lp; + } + } + else + { + lp.displayable_chars += 1; + } + + lp.font_ascent = MAX (font->ascent, lp.font_ascent); + lp.font_descent = MAX (font->descent, lp.font_descent); + lp.pixel_width += ch_width; + + advance_mark(&lp.end); + advance_tab_mark (text, &tab_mark, ch); + } + + if (LAST_INDEX(text, lp.start)) + { + /* Special case, empty last line. */ + font = MARK_CURRENT_FONT (&lp.end); + + lp.font_ascent = font->ascent; + lp.font_descent = font->descent; + } + + lp.tab_cont_next = *next_cont; + + return lp; +} + +static void +expand_scratch_buffer (GtkText* text, guint len) +{ + if (len >= text->scratch_buffer_len) + { + guint i = 1; + + while (i <= len && i < MIN_GAP_SIZE) i <<= 1; + + if (text->scratch_buffer) + text->scratch_buffer = g_new (guchar, i); + else + text->scratch_buffer = g_realloc (text->scratch_buffer, i); + + text->scratch_buffer_len = i; + } +} + +static void +draw_line (GtkText* text, + gint pixel_start_height, + LineParams* lp) +{ + GdkGCValues gc_values; + gint i; + gint len = 0; + guint running_offset = lp->tab_cont.pixel_offset; + guchar* buffer; + + GtkPropertyMark mark = lp->start; + TabStopMark tab_mark = lp->tab_cont.tab_start; + gint pixel_height = pixel_start_height + lp->font_ascent; + guint chars = lp->displayable_chars; + + /* First provide a contiguous segment of memory. This makes reading + * the code below *much* easier, and only incurs the cost of copying + * when the line being displayed spans the gap. */ + if (mark.index <= text->gap_position && + mark.index + chars > text->gap_position) + { + expand_scratch_buffer (text, chars); + + for (i = 0; i < chars; i += 1) + text->scratch_buffer[i] = TEXT_INDEX(text, mark.index + i); + + buffer = text->scratch_buffer; + } + else + { + if (mark.index >= text->gap_position) + buffer = text->text + mark.index + text->gap_size; + else + buffer = text->text + mark.index; + } + + if (running_offset > 0 && MARK_CURRENT_BACK (&mark)) + { + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + 0, + pixel_start_height, + running_offset, + LINE_HEIGHT (*lp)); + } + + for (; chars > 0; chars -= len, buffer += len, len = 0) + { + if (buffer[0] != '\t') + { + guchar* next_tab = memchr (buffer, '\t', chars); + gint pixel_width; + GdkFont *font; + + len = MIN (MARK_CURRENT_PROPERTY (&mark)->length - mark.offset, chars); + + if (next_tab) + len = MIN (len, next_tab - buffer); + + font = MARK_CURRENT_PROPERTY (&mark)->font->gdk_font; + if (font->type == GDK_FONT_FONT) + { + gdk_gc_set_font (text->gc, font); + gdk_gc_get_values (text->gc, &gc_values); + pixel_width = gdk_text_width (gc_values.font, + (gchar*) buffer, len); + } + else + pixel_width = gdk_text_width (font, (gchar*) buffer, len); + + if (MARK_CURRENT_BACK (&mark)) + { + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + running_offset, + pixel_start_height, + pixel_width, + LINE_HEIGHT(*lp)); + } + + gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (&mark)); + + gdk_draw_text (text->text_area, MARK_CURRENT_FONT (&mark), + text->gc, + running_offset, + pixel_height, + (gchar*) buffer, + len); + + running_offset += pixel_width; + + advance_tab_mark_n (text, &tab_mark, len); + } + else + { + len = 1; + + if (MARK_CURRENT_BACK (&mark)) + { + gint pixels_remaining; + gint space_width; + gint spaces_avail; + + gdk_window_get_size (text->text_area, &pixels_remaining, NULL); + pixels_remaining -= (LINE_WRAP_ROOM + running_offset); + + space_width = MARK_CURRENT_TEXT_FONT(&mark)->char_widths[' ']; + + spaces_avail = pixels_remaining / space_width; + spaces_avail = MIN (spaces_avail, tab_mark.to_next_tab); + + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + running_offset, + pixel_start_height, + spaces_avail * space_width, + LINE_HEIGHT (*lp)); + } + + running_offset += tab_mark.to_next_tab * + MARK_CURRENT_TEXT_FONT(&mark)->char_widths[' ']; + + advance_tab_mark (text, &tab_mark, '\t'); + } + + advance_mark_n (&mark, len); + } +} + +static void +draw_line_wrap (GtkText* text, guint height /* baseline height */) +{ + gint width; + GdkPixmap *bitmap; + gint bitmap_width; + gint bitmap_height; + + if (text->line_wrap) + { + bitmap = text->line_wrap_bitmap; + bitmap_width = line_wrap_width; + bitmap_height = line_wrap_height; + } + else + { + bitmap = text->line_arrow_bitmap; + bitmap_width = line_arrow_width; + bitmap_height = line_arrow_height; + } + + gdk_window_get_size (text->text_area, &width, NULL); + width -= LINE_WRAP_ROOM; + + gdk_gc_set_stipple (text->gc, + bitmap); + + gdk_gc_set_fill (text->gc, GDK_STIPPLED); + + gdk_gc_set_foreground (text->gc, &text->widget.style->fg[GTK_STATE_NORMAL]); + + gdk_gc_set_ts_origin (text->gc, + width + 1, + height - bitmap_height - 1); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + width + 1, + height - bitmap_height - 1 /* one pixel above the baseline. */, + bitmap_width, + bitmap_height); + + gdk_gc_set_ts_origin (text->gc, 0, 0); + + gdk_gc_set_fill (text->gc, GDK_SOLID); +} + +static void +undraw_cursor (GtkText* text, gint absolute) +{ + TDEBUG (("in undraw_cursor\n")); + + if (absolute) + text->cursor_drawn_level = 0; + + if (text->has_cursor && (text->cursor_drawn_level ++ == 0)) + { + GdkFont* font; + + g_assert(text->cursor_mark.property); + + font = MARK_CURRENT_FONT(&text->cursor_mark); + + if (text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + { + GdkRectangle rect; + + rect.x = text->cursor_pos_x; + rect.y = text->cursor_pos_y - text->cursor_char_offset - font->ascent; + rect.width = 1; + rect.height = font->ascent + 1; /* @@@ I add one here because draw_line is inclusive, right? */ + + clear_area (text, &rect); + } + else + { + if (MARK_CURRENT_BACK (&text->cursor_mark)) + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&text->cursor_mark)); + else + gdk_gc_set_foreground (text->gc, &text->widget.style->bg[GTK_STATE_NORMAL]); + + gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset, text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset - font->ascent); + } + + if (text->cursor_char) + { + if (font->type == GDK_FONT_FONT) + gdk_gc_set_font (text->gc, font); + + gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (&text->cursor_mark)); + + gdk_draw_text (text->text_area, font, + text->gc, + text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset, + &text->cursor_char, + 1); + } + } +} + +static gint +drawn_cursor_min (GtkText* text) +{ + if (text->has_cursor) + { + GdkFont* font; + + g_assert(text->cursor_mark.property); + + font = MARK_CURRENT_FONT(&text->cursor_mark); + + return text->cursor_pos_y - text->cursor_char_offset - font->ascent; + } + else + return 0; +} + +static gint +drawn_cursor_max (GtkText* text) +{ + if (text->has_cursor) + { + GdkFont* font; + + g_assert(text->cursor_mark.property); + + font = MARK_CURRENT_FONT(&text->cursor_mark); + + return text->cursor_pos_y - text->cursor_char_offset; + } + else + return 0; +} + +static void +draw_cursor (GtkText* text, gint absolute) +{ + TDEBUG (("in draw_cursor\n")); + + if (absolute) + text->cursor_drawn_level = 1; + + if (text->has_cursor && (--text->cursor_drawn_level == 0)) + { + GdkFont* font; + + g_assert (text->cursor_mark.property); + + font = MARK_CURRENT_FONT (&text->cursor_mark); + + gdk_gc_set_foreground (text->gc, &text->widget.style->fg[GTK_STATE_NORMAL]); + + gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset, + text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset - font->ascent); + } +} + +static void +clear_area (GtkText *text, GdkRectangle *area) +{ + if (text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + { + gint width, height; + gint x = area->x, y = area->y; + gint xorig, yorig; + + gdk_window_get_size (text->widget.style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); + + yorig = - text->first_onscreen_ver_pixel; + xorig = - text->first_onscreen_hor_pixel; + + for (y = area->y; y < area->y + area->height; ) + { + gint yoff = (y - yorig) % height; + gint yw = MIN(height - yoff, (area->y + area->height) - y); + + for (x = area->x; x < area->x + area->width; ) + { + gint xoff = (x - xorig) % width; + gint xw = MIN(width - xoff, (area->x + area->width) - x); + + gdk_draw_pixmap (text->text_area, + text->gc, + text->widget.style->bg_pixmap[GTK_STATE_NORMAL], + xoff, + yoff, + x, + y, + xw, + yw); + + x += width - xoff; + } + y += height - yoff; + } + } + else + gdk_window_clear_area (text->text_area, area->x, area->y, area->width, area->height); +} + +static void +expose_text (GtkText* text, GdkRectangle *area, gboolean cursor) +{ + GList *cache = text->line_start_cache; + gint pixels = - text->first_cut_pixels; + gint min_y = area->y; + gint max_y = area->y + area->height; + gint height; + + gdk_window_get_size (text->text_area, NULL, &height); + max_y = MIN (max_y, height); + + TDEBUG (("in expose x=%d y=%d w=%d h=%d\n", area->x, area->y, area->width, area->height)); + + clear_area (text, area); + + for (; pixels < height; cache = cache->next) + { + if (pixels < max_y && (pixels + LINE_HEIGHT(CACHE_DATA(cache))) >= min_y) + { + draw_line (text, pixels, &CACHE_DATA(cache)); + + if (CACHE_DATA(cache).wraps) + draw_line_wrap (text, pixels + CACHE_DATA(cache).font_ascent); + } + + if (cursor && text->has_cursor && GTK_WIDGET_HAS_FOCUS (&text->widget)) + { + if (CACHE_DATA(cache).start.index <= text->cursor_mark.index && + CACHE_DATA(cache).end.index >= text->cursor_mark.index) + draw_cursor (text, TRUE); + } + + pixels += LINE_HEIGHT(CACHE_DATA(cache)); + + if (!cache->next) + { + fetch_lines_forward (text, 1); + + if (!cache->next) + break; + } + } +} + +static void +recompute_geometry (GtkText* text) +{ + GtkPropertyMark start_mark; + gint height; + gint width; + + free_cache (text); + + start_mark = set_vertical_scroll (text); + + gdk_window_get_size (text->text_area, &width, &height); + + text->line_start_cache = fetch_lines (text, + &start_mark, + NULL, + FetchLinesPixels, + height + text->first_cut_pixels); + + find_cursor (text); +} + +/**********************************************************************/ +/* Selection */ +/**********************************************************************/ + +static gint +gtk_text_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ +#if 0 + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + if (entry->have_selection) + { + entry->have_selection = FALSE; + gtk_entry_queue_draw (entry); + } +#endif + return FALSE; +} + +static gint +gtk_text_selection_request (GtkWidget *widget, + GdkEventSelection *event) +{ +#if 0 + + GtkEntry *entry; + gint selection_start_pos; + gint selection_end_pos; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + if (entry->selection_start_pos != entry->selection_end_pos) + { + selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); + selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); + + gdk_selection_set (event->requestor, event->selection, + event->property, event->time, + (guchar*) &entry->text[selection_start_pos], + selection_end_pos - selection_start_pos); + } +#endif + return FALSE; +} + +static gint +gtk_text_selection_notify (GtkWidget *widget, + GdkEventSelection *event) +{ +#if 0 + GtkEntry *entry; + gchar *data; + gint tmp_pos; + gint reselect; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + gdk_selection_get (widget->window, (guchar**) &data); + + reselect = FALSE; + if (entry->selection_start_pos != entry->selection_end_pos) + { + reselect = TRUE; + gtk_delete_selection (entry); + } + + tmp_pos = entry->current_pos; + gtk_entry_insert_text (entry, data, strlen (data), &tmp_pos); + + if (reselect) + { + reselect = entry->have_selection; + gtk_select_region (entry, entry->current_pos, tmp_pos); + entry->have_selection = reselect; + } + + entry->current_pos = tmp_pos; + + gtk_entry_queue_draw (entry); +#endif + return FALSE; +} + +/**********************************************************************/ +/* Debug */ +/**********************************************************************/ + +#ifdef DEBUG_GTK_TEXT +static void +gtk_text_show_cache_line (GtkText *text, GList *cache, + const char* what, const char* func, gint line) +{ + LineParams *lp = &CACHE_DATA(cache); + gint i; + + g_print ("%s:%d: cache line %s s=%d,e=%d,lh=%d (", + func, + line, + what, + lp->start.index, + lp->end.index, + LINE_HEIGHT(*lp)); + + for (i = lp->start.index; i < (lp->end.index + lp->wraps); i += 1) + g_print ("%c", TEXT_INDEX (text, i)); + + g_print (")\n"); +} + +static void +gtk_text_show_cache (GtkText *text, const char* func, gint line) +{ + GList *l = text->line_start_cache; + + g_print ("*** line cache ***\n"); + for (; l; l = l->next) + gtk_text_show_cache_line (text, l, "all", func, line); +} + +static void +gtk_text_assert_mark (GtkText *text, + GtkPropertyMark *mark, + GtkPropertyMark *before, + GtkPropertyMark *after, + const gchar *msg, + const gchar *where, + gint line) +{ + GtkPropertyMark correct_mark = find_mark (text, mark->index); + + if (mark->offset != correct_mark.offset || + mark->property != correct_mark.property) + g_warning ("incorrect %s text property marker in %s:%d, index %d -- bad!", where, msg, line, mark->index); +} + +static void +gtk_text_assert (GtkText *text, + const gchar *msg, + gint line) +{ + GList* cache = text->line_start_cache; + GtkPropertyMark* before_mark = NULL; + GtkPropertyMark* after_mark = NULL; + + gtk_text_show_props (text, msg, line); + + for (; cache->prev; cache = cache->prev) + /* nothing */; + + g_print ("*** line markers ***\n"); + + for (; cache; cache = cache->next) + { + after_mark = &CACHE_DATA(cache).end; + gtk_text_assert_mark (text, &CACHE_DATA(cache).start, before_mark, after_mark, msg, "start", line); + before_mark = &CACHE_DATA(cache).start; + + if (cache->next) + after_mark = &CACHE_DATA(cache->next).start; + else + after_mark = NULL; + + gtk_text_assert_mark (text, &CACHE_DATA(cache).end, before_mark, after_mark, msg, "end", line); + before_mark = &CACHE_DATA(cache).end; + } +} + +static void +gtk_text_show_adj (GtkText *text, + GtkAdjustment *adj, + const char* what, + const char* func, + gint line) +{ + g_print ("*** adjustment ***\n"); + + g_print ("%s:%d: %s adjustment l=%.1f u=%.1f v=%.1f si=%.1f pi=%.1f ps=%.1f\n", + func, + line, + what, + adj->lower, + adj->upper, + adj->value, + adj->step_increment, + adj->page_increment, + adj->page_size); +} + +static void +gtk_text_show_props (GtkText *text, + const char* msg, + int line) +{ + GList* props = text->text_properties; + int proplen = 0; + + g_print ("%s:%d: ", msg, line); + + for (; props; props = props->next) + { + TextProperty *p = (TextProperty*)props->data; + + proplen += p->length; + + g_print ("[%d,%p,%p,%p,%p] ", p->length, p, p->font, p->fore_color, p->back_color); + } + + g_print ("\n"); + + if (proplen - 1 != TEXT_LENGTH(text)) + g_warning ("incorrect property list length in %s:%d -- bad!", msg, line); +} +#endif diff --git a/gtk/gtktext.h b/gtk/gtktext.h new file mode 100644 index 0000000000..012d679a3b --- /dev/null +++ b/gtk/gtktext.h @@ -0,0 +1,204 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_TEXT_H__ +#define __GTK_TEXT_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkadjustment.h> +#include <gtk/gtkwidget.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TEXT(obj) GTK_CHECK_CAST (obj, gtk_text_get_type (), GtkText) +#define GTK_TEXT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_text_get_type (), GtkTextClass) +#define GTK_IS_TEXT(obj) GTK_CHECK_TYPE (obj, gtk_text_get_type ()) + + +typedef struct _GtkPropertyMark GtkPropertyMark; +typedef struct _GtkText GtkText; +typedef struct _GtkTextClass GtkTextClass; + +typedef void (*GtkTextFunction) (GtkText *text); + +struct _GtkPropertyMark +{ + /* Position in list. */ + GList* property; + + /* Offset into that property. */ + guint offset; + + /* Current index. */ + guint index; +}; + +struct _GtkText +{ + GtkWidget widget; + + GdkWindow *text_area; + + GtkAdjustment *hadj; + GtkAdjustment *vadj; + + GdkGC *gc; + + GdkPixmap* line_wrap_bitmap; + GdkPixmap* line_arrow_bitmap; + + /* GAPPED TEXT SEGMENT */ + + /* The text, a single segment of text a'la emacs, with a gap + * where insertion occurs. */ + guchar* text; + /* The allocated length of the text segment. */ + guint text_len; + /* The gap position, index into address where a char + * should be inserted. */ + guint gap_position; + /* The gap size, s.t. *(text + gap_position + gap_size) is + * the first valid character following the gap. */ + guint gap_size; + /* The last character position, index into address where a + * character should be appeneded. Thus, text_end - gap_size + * is the length of the actual data. */ + guint text_end; + /* LINE START CACHE */ + + /* A cache of line-start information. Data is a LineParam*. */ + GList *line_start_cache; + /* Index to the start of the first visible line. */ + guint first_line_start_index; + /* The number of pixels cut off of the top line. */ + guint first_cut_pixels; + /* First visible horizontal pixel. */ + guint first_onscreen_hor_pixel; + /* First visible vertical pixel. */ + guint first_onscreen_ver_pixel; + + /* FLAGS */ + + /* True iff the cursor has been placed yet. */ + guint has_cursor : 1; + /* True iff this buffer is editable. (Allowing a cursor to be placed). */ + guint is_editable : 1; + /* True iff this buffer is wrapping lines, otherwise it is using a + * horizontal scrollbar. */ + guint line_wrap : 1; + /* Frozen, don't do updates. @@@ fixme */ + guint freeze : 1; + /* Whether a selection. */ + guint has_selection : 1; + /* Whether the selection is in the clipboard. */ + guint own_selection : 1; + /* Whether it has been realized yet. */ + + /* TEXT PROPERTIES */ + + /* A doubly-linked-list containing TextProperty objects. */ + GList *text_properties; + /* The end of this list. */ + GList *text_properties_end; + /* The first node before or on the point along with its offset to + * the point and the buffer's current point. This is the only + * PropertyMark whose index is guaranteed to remain correct + * following a buffer insertion or deletion. */ + GtkPropertyMark point; + + /* SCRATCH AREA */ + + guchar* scratch_buffer; + guint scratch_buffer_len; + + /* SCROLLING */ + + gint last_ver_value; + + /* CURSOR */ + + gint cursor_pos_x; /* Position of cursor. */ + gint cursor_pos_y; /* Baseline of line cursor is drawn on. */ + GtkPropertyMark cursor_mark; /* Where it is in the buffer. */ + gchar cursor_char; /* Character to redraw. */ + gchar cursor_char_offset; /* Distance from baseline of the font. */ + gint cursor_virtual_x; /* Where it would be if it could be. */ + gint cursor_drawn_level; /* How many people have undrawn. */ + + /* Current Line */ + + GList *current_line; + + /* Tab Stops */ + + GList *tab_stops; + gint default_tab_width; + + /* Key bindings */ + + GtkTextFunction control_keys[26]; + GtkTextFunction alt_keys[26]; + + /* Selection nonsense. */ + + guint selection_start; + guint selection_stop; +}; + +struct _GtkTextClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_text_get_type (void); +GtkWidget* gtk_text_new (GtkAdjustment *hadj, + GtkAdjustment *vadj); +void gtk_text_set_editable (GtkText *text, + gint editable); +void gtk_text_set_adjustments (GtkText *text, + GtkAdjustment *hadj, + GtkAdjustment *vadj); +void gtk_text_set_point (GtkText *text, + guint index); +guint gtk_text_get_point (GtkText *text); +guint gtk_text_get_length (GtkText *text); +void gtk_text_freeze (GtkText *text); +void gtk_text_thaw (GtkText *text); +void gtk_text_insert (GtkText *text, + GdkFont *font, + GdkColor *fore, + GdkColor *back, + const char *chars, + gint length); +gint gtk_text_backward_delete (GtkText *text, + guint nchars); +gint gtk_text_foreward_delete (GtkText *text, + guint nchars); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TEXT_H__ */ diff --git a/gtk/gtktogglebutton.c b/gtk/gtktogglebutton.c new file mode 100644 index 0000000000..eabcb1b266 --- /dev/null +++ b/gtk/gtktogglebutton.c @@ -0,0 +1,372 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtklabel.h" +#include "gtkmain.h" +#include "gtksignal.h" +#include "gtktogglebutton.h" + + +#define DEFAULT_LEFT_POS 4 +#define DEFAULT_TOP_POS 4 +#define DEFAULT_SPACING 7 + +enum { + TOGGLED, + LAST_SIGNAL +}; + + +static void gtk_toggle_button_class_init (GtkToggleButtonClass *klass); +static void gtk_toggle_button_init (GtkToggleButton *toggle_button); +static void gtk_toggle_button_draw_focus (GtkWidget *widget); +static void gtk_toggle_button_pressed (GtkButton *button); +static void gtk_toggle_button_released (GtkButton *button); +static void gtk_toggle_button_clicked (GtkButton *button); +static void gtk_toggle_button_enter (GtkButton *button); +static void gtk_toggle_button_leave (GtkButton *button); + + +static gint toggle_button_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_toggle_button_get_type () +{ + static guint toggle_button_type = 0; + + if (!toggle_button_type) + { + GtkTypeInfo toggle_button_info = + { + "GtkToggleButton", + sizeof (GtkToggleButton), + sizeof (GtkToggleButtonClass), + (GtkClassInitFunc) gtk_toggle_button_class_init, + (GtkObjectInitFunc) gtk_toggle_button_init, + (GtkArgFunc) NULL, + }; + + toggle_button_type = gtk_type_unique (gtk_button_get_type (), &toggle_button_info); + } + + return toggle_button_type; +} + +static void +gtk_toggle_button_class_init (GtkToggleButtonClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + GtkButtonClass *button_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + button_class = (GtkButtonClass*) class; + + toggle_button_signals[TOGGLED] = + gtk_signal_new ("toggled", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkToggleButtonClass, toggled), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, toggle_button_signals, LAST_SIGNAL); + + widget_class->draw_focus = gtk_toggle_button_draw_focus; + widget_class->draw_default = NULL; + + button_class->pressed = gtk_toggle_button_pressed; + button_class->released = gtk_toggle_button_released; + button_class->clicked = gtk_toggle_button_clicked; + button_class->enter = gtk_toggle_button_enter; + button_class->leave = gtk_toggle_button_leave; + + class->toggled = NULL; +} + +static void +gtk_toggle_button_init (GtkToggleButton *toggle_button) +{ + toggle_button->active = FALSE; + toggle_button->draw_indicator = FALSE; +} + + +GtkWidget* +gtk_toggle_button_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_toggle_button_get_type ())); +} + +GtkWidget* +gtk_toggle_button_new_with_label (const gchar *label) +{ + GtkWidget *toggle_button; + GtkWidget *label_widget; + + toggle_button = gtk_toggle_button_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5); + + gtk_container_add (GTK_CONTAINER (toggle_button), label_widget); + gtk_widget_show (label_widget); + + return toggle_button; +} + +void +gtk_toggle_button_set_mode (GtkToggleButton *toggle_button, + gint draw_indicator) +{ + g_return_if_fail (toggle_button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); + + draw_indicator = draw_indicator ? TRUE : FALSE; + + if (toggle_button->draw_indicator != draw_indicator) + { + toggle_button->draw_indicator = draw_indicator; + + if (GTK_WIDGET_VISIBLE (toggle_button)) + gtk_widget_queue_resize (GTK_WIDGET (toggle_button)); + } +} + +void +gtk_toggle_button_set_state (GtkToggleButton *toggle_button, + gint state) +{ + g_return_if_fail (toggle_button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); + + if (toggle_button->active != state) + gtk_button_clicked (GTK_BUTTON (toggle_button)); +} + +void +gtk_toggle_button_toggled (GtkToggleButton *toggle_button) +{ + gtk_signal_emit (GTK_OBJECT (toggle_button), toggle_button_signals[TOGGLED]); +} + + +static void +gtk_toggle_button_draw_focus (GtkWidget *widget) +{ + GtkButton *button; + GtkToggleButton *toggle_button; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + button = GTK_BUTTON (widget); + toggle_button = GTK_TOGGLE_BUTTON (widget); + + x = 0; + y = 0; + width = widget->allocation.width; + height = widget->allocation.height; + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + x += widget->style->klass->xthickness; + y += widget->style->klass->ythickness; + width -= 2 * x + DEFAULT_SPACING; + height -= 2 * y + DEFAULT_SPACING; + x += DEFAULT_LEFT_POS; + y += DEFAULT_TOP_POS; + } + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + else + { + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 1, y + 1, width - 4, height - 4); + else + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 2, y + 2, width - 5, height - 5); + } + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) && toggle_button->active) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x -= 1; + y -= 1; + width += 2; + height += 2; + + gdk_draw_rectangle (widget->window, + widget->style->black_gc, FALSE, + x, y, width - 1, height - 1); + } + } +} + +static void +gtk_toggle_button_pressed (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + + button->button_down = TRUE; + + if (toggle_button->active) + new_state = (button->in_button ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE); + else + new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_toggle_button_released (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + if (button->button_down) + { + toggle_button = GTK_TOGGLE_BUTTON (button); + + button->button_down = FALSE; + + if (button->in_button) + { + gtk_button_clicked (button); + } + else + { + if (toggle_button->active) + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + else + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } + } + } +} + +static void +gtk_toggle_button_clicked (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + toggle_button->active = !toggle_button->active; + + gtk_toggle_button_toggled (toggle_button); + + if (toggle_button->active) + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + else + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); +} + +static void +gtk_toggle_button_enter (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + + if (toggle_button->active) + new_state = (button->button_down ? GTK_STATE_NORMAL : GTK_STATE_PRELIGHT); + else + new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_toggle_button_leave (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + + new_state = (toggle_button->active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} diff --git a/gtk/gtktogglebutton.h b/gtk/gtktogglebutton.h new file mode 100644 index 0000000000..e48d1cf5a2 --- /dev/null +++ b/gtk/gtktogglebutton.h @@ -0,0 +1,70 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_TOGGLE_BUTTON_H__ +#define __GTK_TOGGLE_BUTTON_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbutton.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TOGGLE_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_toggle_button_get_type (), GtkToggleButton) +#define GTK_TOGGLE_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_toggle_button_get_type (), GtkToggleButtonClass) +#define GTK_IS_TOGGLE_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_toggle_button_get_type ()) + + +typedef struct _GtkToggleButton GtkToggleButton; +typedef struct _GtkToggleButtonClass GtkToggleButtonClass; + +struct _GtkToggleButton +{ + GtkButton button; + + guint active : 1; + guint draw_indicator : 1; +}; + +struct _GtkToggleButtonClass +{ + GtkButtonClass parent_class; + + void (* toggled) (GtkToggleButton *toggle_button); +}; + + +guint gtk_toggle_button_get_type (void); +GtkWidget* gtk_toggle_button_new (void); +GtkWidget* gtk_toggle_button_new_with_label (const gchar *label); +void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button, + gint draw_indicator); +void gtk_toggle_button_set_state (GtkToggleButton *toggle_button, + gint state); +void gtk_toggle_button_toggled (GtkToggleButton *toggle_button); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TOGGLE_BUTTON_H__ */ diff --git a/gtk/gtktooltips.c b/gtk/gtktooltips.c new file mode 100644 index 0000000000..953d425923 --- /dev/null +++ b/gtk/gtktooltips.c @@ -0,0 +1,632 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdlib.h> +#include <string.h> + +#include "gtkmain.h" +#include "gtkwidget.h" +#include "gtkwindow.h" +#include "gtksignal.h" +#include "gtkstyle.h" +#include "gtktooltips.h" + + +#define DEFAULT_DELAY 500 /* Default delay in ms */ + + +static gint gtk_tooltips_event_handler (GtkWidget *widget, + GdkEvent *event); +static void gtk_tooltips_widget_unmap (GtkWidget *widget, + gpointer data); +static void gtk_tooltips_widget_remove (GtkWidget *widget, + gpointer data); +static void gtk_tooltips_set_active_widget (GtkTooltips *tooltips, + GtkWidget *widget); +static gint gtk_tooltips_widget_visible (GtkWidget *widget); +static gint gtk_tooltips_timeout (gpointer data); +static void gtk_tooltips_draw_tips (GtkTooltips *tooltips); + + +GtkTooltips * +gtk_tooltips_new () +{ + GtkTooltips *tooltips; + + tooltips = g_new0 (GtkTooltips, 1); + + if (tooltips != NULL) + { + tooltips->ref_count = 0; + tooltips->pending_destroy = 0; + + tooltips->enabled = TRUE; + tooltips->numwidgets = 0; + tooltips->delay = DEFAULT_DELAY; + tooltips->widget_list = NULL; + tooltips->gc = NULL; + tooltips->foreground = NULL; + tooltips->background = NULL; + tooltips->tip_window = NULL; + } + + return tooltips; +} + +GtkTooltips* +gtk_tooltips_ref (GtkTooltips *tooltips) +{ + g_return_val_if_fail (tooltips != NULL, NULL); + tooltips->ref_count += 1; + return tooltips; +} + +void +gtk_tooltips_unref (GtkTooltips *tooltips) +{ + g_return_if_fail (tooltips != NULL); + tooltips->ref_count -= 1; + if (tooltips->ref_count == 0 && tooltips->pending_destroy) + gtk_tooltips_destroy (tooltips); +} + +void +gtk_tooltips_free_string (gpointer data, gpointer user_data) +{ + if (data) + g_free (data); +} + +static void +gtk_tooltips_destroy_data (GtkTooltips *tooltips, + GtkTooltipsData *tooltipsdata) +{ + g_free (tooltipsdata->tips_text); + g_list_foreach (tooltipsdata->row, gtk_tooltips_free_string, 0); + if (tooltipsdata->row) + g_list_free (tooltipsdata->row); + gtk_signal_disconnect_by_data (GTK_OBJECT (tooltipsdata->widget), + (gpointer) tooltips); + gtk_widget_set_events(tooltipsdata->widget,tooltipsdata->old_event_mask); + g_free (tooltipsdata); +} + +void +gtk_tooltips_destroy (GtkTooltips *tooltips) +{ + GList *current; + GtkTooltipsData *tooltipsdata; + + g_return_if_fail (tooltips != NULL); + + if (tooltips->ref_count > 0) + { + tooltips->pending_destroy = 1; + return; + } + + if (tooltips->timer_active == TRUE) + { + tooltips->timer_active = FALSE; + gtk_timeout_remove (tooltips->timer_tag); + } + + if (tooltips->widget_list != NULL) + { + current = g_list_first (tooltips->widget_list); + while (current != NULL) + { + tooltipsdata = (GtkTooltipsData*) current->data; + gtk_tooltips_destroy_data (tooltips, tooltipsdata); + current = current->next; + } + g_list_free (tooltips->widget_list); + } + + if (tooltips->tip_window != NULL) + gtk_widget_destroy (tooltips->tip_window); + + if (tooltips->gc != NULL) + gdk_gc_destroy (tooltips->gc); + + g_free (tooltips); +} + +static void +gtk_tooltips_layout_text (GtkTooltips *tooltips, GtkTooltipsData *data) +{ + GtkStyle *style = gtk_widget_get_default_style (); + gchar *row_end, *text, *row_text, *break_pos; + gint i, row_width, window_width = 0; + size_t len; + + g_list_foreach (data->row, gtk_tooltips_free_string, 0); + if (data->row) + g_list_free (data->row); + data->row = 0; + data->font = style->font; + data->width = 0; + + text = data->tips_text; + if (!text) + return; + + while (*text) + { + row_end = strchr (text, '\n'); + if (!row_end) + row_end = strchr (text, '\0'); + + len = row_end - text + 1; + row_text = g_new(gchar, len); + memcpy (row_text, text, len - 1); + row_text[len - 1] = '\0'; + + /* now either adjust the window's width or shorten the row until + it fits in the window */ + + while (1) + { + row_width = gdk_string_width (data->font, row_text); + if (!window_width) + { + /* make an initial guess at window's width: */ + + if (row_width > gdk_screen_width () / 4) + window_width = gdk_screen_width () / 4; + else + window_width = row_width; + } + if (row_width <= window_width) + break; + + if (strchr (row_text, ' ')) + { + /* the row is currently too wide, but we have blanks in + the row so we can break it into smaller pieces */ + + gint avg_width = row_width / strlen (row_text); + + i = window_width; + if (avg_width) + i /= avg_width; + if ((size_t) i >= len) + i = len - 1; + + break_pos = strchr (row_text + i, ' '); + if (!break_pos) + { + break_pos = row_text + i; + while (*--break_pos != ' '); + } + *break_pos = '\0'; + } + else + { + /* we can't break this row into any smaller pieces, so + we have no choice but to widen the window: */ + + window_width = row_width; + break; + } + } + if (row_width > data->width) + data->width = row_width; + data->row = g_list_append (data->row, row_text); + text += strlen (row_text); + if (!*text) + break; + + if (text[0] == '\n' && text[1]) + /* end of paragraph and there is more text to come */ + data->row = g_list_append (data->row, 0); + ++text; /* skip blank or newline */ + } + data->width += 8; /* leave some border */ +} + +void +gtk_tooltips_enable (GtkTooltips *tooltips) +{ + g_return_if_fail (tooltips != NULL); + + tooltips->enabled = TRUE; +} + +void +gtk_tooltips_disable (GtkTooltips *tooltips) +{ + g_return_if_fail (tooltips != NULL); + + tooltips->enabled = FALSE; + + if (tooltips->timer_active == TRUE) + { + gtk_timeout_remove (tooltips->timer_tag); + tooltips->timer_active = FALSE; + } + + if (tooltips->active_widget != NULL) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + tooltips->active_widget = NULL; + } +} + +void +gtk_tooltips_set_delay (GtkTooltips *tooltips, + gint delay) +{ + g_return_if_fail (tooltips != NULL); + + tooltips->delay = delay; +} + +void +gtk_tooltips_set_tips (GtkTooltips *tooltips, + GtkWidget *widget, + const gchar *tips_text) +{ + GtkTooltipsData *tooltipsdata; + + g_return_if_fail (tooltips != NULL); + g_return_if_fail (widget != NULL); + + if (gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips") != NULL) + gtk_tooltips_widget_remove (widget, NULL); + + if (gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips") != NULL) + gtk_tooltips_widget_remove (widget, NULL); + + tooltipsdata = g_new(GtkTooltipsData, 1); + + if (tooltipsdata != NULL) + { + memset (tooltipsdata, 0, sizeof (*tooltipsdata)); + tooltipsdata->widget = widget; + + tooltipsdata->tips_text = g_strdup (tips_text); + if (!tooltipsdata->tips_text) + { + g_free (tooltipsdata); + return; + } + + gtk_tooltips_layout_text (tooltips, tooltipsdata); + tooltips->widget_list = g_list_append (tooltips->widget_list, + tooltipsdata); + tooltips->numwidgets++; + tooltipsdata->old_event_mask = gtk_widget_get_events (widget); + + gtk_signal_connect_after(GTK_OBJECT (widget), "event", + (GtkSignalFunc) gtk_tooltips_event_handler, + (gpointer) tooltips); + + gtk_object_set_data (GTK_OBJECT (widget), "_GtkTooltips", + (gpointer) tooltips); + + gtk_signal_connect (GTK_OBJECT (widget), "destroy", + (GtkSignalFunc) gtk_tooltips_widget_remove, + (gpointer) tooltips); + + gtk_signal_connect (GTK_OBJECT (widget), "unmap", + (GtkSignalFunc) gtk_tooltips_widget_unmap, + (gpointer) tooltips); + + gtk_signal_connect (GTK_OBJECT (widget), "unrealize", + (GtkSignalFunc) gtk_tooltips_widget_unmap, + (gpointer) tooltips); + } +} + +void +gtk_tooltips_set_colors (GtkTooltips *tooltips, + GdkColor *background, + GdkColor *foreground) +{ + g_return_if_fail (tooltips != NULL); + + if (background != NULL) + tooltips->foreground = foreground; + if (foreground != NULL) + tooltips->background = background; +} + +static void +gtk_tooltips_draw_tips (GtkTooltips * tooltips) +{ + GtkWidget *widget; + GtkStyle *style = gtk_widget_get_default_style (); + gint gap, x, y, w, h, scr_w, scr_h, baseline_skip; + GtkTooltipsData *data; + GList *el; + + if (tooltips->tip_window == NULL) + { + tooltips->tip_window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_policy (GTK_WINDOW (tooltips->tip_window), FALSE, FALSE, TRUE); + } + else + gtk_widget_hide (tooltips->tip_window); + + widget = tooltips->active_widget->widget; + + scr_w = gdk_screen_width (); + scr_h = gdk_screen_height (); + + data = tooltips->active_widget; + if (data->font != style->font) + gtk_tooltips_layout_text (tooltips, data); + + gap = (style->font->ascent + style->font->descent) / 4; + if (gap < 2) + gap = 2; + baseline_skip = style->font->ascent + style->font->descent + gap; + w = data->width; + h = 8 - gap; + for (el = data->row; el; el = el->next) + if (el->data) + h += baseline_skip; + else + h += baseline_skip / 2; + if (h < 8) + h = 8; + + gdk_window_get_pointer (NULL, &x, NULL, NULL); + gdk_window_get_origin (widget->window, NULL, &y); + + x -= ((w >> 1) + 4); + + if ((x + w) > scr_w) + x -= (x + w) - scr_w; + else if (x < 0) + x = 0; + + if ((y + h + widget->allocation.height + 4) > scr_h) + y = y - h - 4; + else + y = y + widget->allocation.height + 4; + + gtk_widget_set_usize (tooltips->tip_window, w + 1, h + 1); + gtk_widget_popup (tooltips->tip_window, x, y); + + if (tooltips->gc == NULL) + tooltips->gc = gdk_gc_new (tooltips->tip_window->window); + + if (tooltips->background != NULL) + { + gdk_gc_set_foreground (tooltips->gc, tooltips->background); + gdk_gc_set_background (tooltips->gc, tooltips->foreground); + } + else + { + gdk_gc_set_foreground (tooltips->gc, &style->bg[GTK_STATE_NORMAL]); + gdk_gc_set_background (tooltips->gc, &style->fg[GTK_STATE_NORMAL]); + } + + gdk_gc_set_font (tooltips->gc, style->font); + gdk_draw_rectangle (tooltips->tip_window->window, tooltips->gc, TRUE, 0, 0, w, h); + + if (tooltips->foreground != NULL) + { + gdk_gc_set_foreground (tooltips->gc, tooltips->foreground); + gdk_gc_set_background (tooltips->gc, tooltips->background); + } + else + { + gdk_gc_set_foreground (tooltips->gc, &style->fg[GTK_STATE_NORMAL]); + gdk_gc_set_background (tooltips->gc, &style->bg[GTK_STATE_NORMAL]); + } + + gdk_draw_rectangle (tooltips->tip_window->window, tooltips->gc, FALSE, 0, 0, w, h); + y = style->font->ascent + 4; + + for (el = data->row; el; el = el->next) + { + if (el->data) + { + gdk_draw_string (tooltips->tip_window->window, style->font, + tooltips->gc, 4, y, el->data); + y += baseline_skip; + } + else + y += baseline_skip / 2; + } +} + +static gint +gtk_tooltips_timeout (gpointer data) +{ + GtkTooltips *tooltips = (GtkTooltips *) data; + + if (tooltips->active_widget != NULL && + GTK_WIDGET_DRAWABLE (tooltips->active_widget->widget)) + gtk_tooltips_draw_tips (tooltips); + + return FALSE; +} + +static gint +gtk_tooltips_widget_visible (GtkWidget *widget) +{ + GtkWidget *current; + + current = widget; + + while (current != NULL) + { + if (!GTK_WIDGET_MAPPED (current) || !GTK_WIDGET_REALIZED (current)) + return FALSE; + current = current->parent; + } + + return TRUE; +} + +static void +gtk_tooltips_set_active_widget (GtkTooltips *tooltips, + GtkWidget *widget) +{ + GtkTooltipsData *tooltipsdata; + GList *current; + + current = g_list_first (tooltips->widget_list); + tooltips->active_widget = NULL; + + while (current != NULL) + { + tooltipsdata = (GtkTooltipsData*) current->data; + + if (widget == tooltipsdata->widget && + gtk_tooltips_widget_visible (tooltipsdata->widget) == TRUE) + { + tooltips->active_widget = tooltipsdata; + return; + } + + current = current->next; + } +} + +static gint +gtk_tooltips_event_handler (GtkWidget *widget, + GdkEvent *event) +{ + GtkTooltips *tooltips; + GtkTooltipsData *old_widget; + gint returnval = FALSE; + + tooltips = (GtkTooltips*) gtk_object_get_data (GTK_OBJECT (widget),"_GtkTooltips"); + + if (tooltips->enabled == FALSE) + return returnval; + + if ((event->type == GDK_LEAVE_NOTIFY || event->type == GDK_ENTER_NOTIFY) && + event->crossing.detail == GDK_NOTIFY_INFERIOR) + return returnval; + + if (event->type == GDK_LEAVE_NOTIFY) + { + if (tooltips->timer_active == TRUE) + { + gtk_timeout_remove (tooltips->timer_tag); + tooltips->timer_active = FALSE; + } + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + tooltips->active_widget = NULL; + } + else if (event->type == GDK_MOTION_NOTIFY || event->type == GDK_ENTER_NOTIFY) + { + old_widget = tooltips->active_widget; +#if 0 + if (widget->window != event->crossing.window) + tooltips->active_widget = NULL; + else +#endif + gtk_tooltips_set_active_widget (tooltips, widget); + + if (old_widget != tooltips->active_widget) + { + if (tooltips->timer_active == TRUE) + { + gtk_timeout_remove (tooltips->timer_tag); + tooltips->timer_active = FALSE; + } + if (tooltips->active_widget != NULL) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + + tooltips->timer_tag = gtk_timeout_add (tooltips->delay, + gtk_tooltips_timeout, (gpointer) tooltips); + + tooltips->timer_active = TRUE; + } + } + else if (tooltips->active_widget == NULL) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + } + } + else + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + } + + return returnval; +} + +static void +gtk_tooltips_widget_unmap (GtkWidget *widget, + gpointer data) +{ + GtkTooltips *tooltips; + + tooltips = (GtkTooltips*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips"); + + if (tooltips->active_widget && + (tooltips->active_widget->widget == widget)) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + tooltips->active_widget = NULL; + } +} + +static void +gtk_tooltips_widget_remove (GtkWidget *widget, + gpointer data) +{ + GtkTooltips *tooltips; + GtkTooltipsData *tooltipsdata; + GList *list; + + tooltips = (GtkTooltips*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips"); + + gtk_tooltips_widget_unmap (widget, data); + + list = g_list_first (tooltips->widget_list); + while (list) + { + tooltipsdata = (GtkTooltipsData*) list->data; + + if (tooltipsdata->widget == widget) + break; + + list = list->next; + } + + if (list) + { + tooltipsdata = (GtkTooltipsData*) list->data; + + g_free (tooltipsdata->tips_text); + g_list_foreach (tooltipsdata->row, gtk_tooltips_free_string, 0); + g_list_free (tooltipsdata->row); + gtk_signal_disconnect_by_data (GTK_OBJECT (tooltipsdata->widget), (gpointer) tooltips); + gtk_widget_set_events (tooltipsdata->widget,tooltipsdata->old_event_mask); + g_free (tooltipsdata); + + tooltips->widget_list = g_list_remove (tooltips->widget_list, tooltipsdata); + } + + gtk_object_set_data (GTK_OBJECT (widget), "_GtkTooltips", NULL); +} diff --git a/gtk/gtktooltips.h b/gtk/gtktooltips.h new file mode 100644 index 0000000000..e3ac596967 --- /dev/null +++ b/gtk/gtktooltips.h @@ -0,0 +1,88 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_TOOLTIPS_H__ +#define __GTK_TOOLTIPS_H__ + +#include <gdk/gdk.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct +{ + GtkWidget *widget; + gchar *tips_text; + GdkFont *font; + gint width; + GList *row; + gint old_event_mask; +} GtkTooltipsData; + +typedef struct +{ + GtkWidget *tip_window; + GtkTooltipsData *active_widget; + GList *widget_list; + + GdkGC *gc; + GdkColor *foreground; + GdkColor *background; + + gint numwidgets; + gint enabled; + gint inside; + gint delay; + gint timer_tag; + gint timer_active; + + gint ref_count; + gint pending_destroy; +} GtkTooltips; + + +GtkTooltips* gtk_tooltips_new (void); + +void gtk_tooltips_destroy (GtkTooltips *tooltips); +GtkTooltips* gtk_tooltips_ref (GtkTooltips *tooltips); +void gtk_tooltips_unref (GtkTooltips *tooltips); + +void gtk_tooltips_enable (GtkTooltips *tooltips); + +void gtk_tooltips_disable (GtkTooltips *tooltips); + +void gtk_tooltips_set_delay (GtkTooltips *tooltips, + gint delay); + +void gtk_tooltips_set_tips (GtkTooltips *tooltips, + GtkWidget *widget, + const gchar *tips_text); + +void gtk_tooltips_set_colors (GtkTooltips *tooltips, + GdkColor *background, + GdkColor *foreground); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TOOLTIPS_H__ */ diff --git a/gtk/gtktree.c b/gtk/gtktree.c new file mode 100644 index 0000000000..f3981ea0a0 --- /dev/null +++ b/gtk/gtktree.c @@ -0,0 +1,81 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtktree.h" + + +static void gtk_tree_class_init (GtkTreeClass *klass); +static void gtk_tree_init (GtkTree *tree); + + +guint +gtk_tree_get_type () +{ + static guint tree_type = 0; + + if (!tree_type) + { + GtkTypeInfo tree_info = + { + "GtkTree", + sizeof (GtkTree), + sizeof (GtkTreeClass), + (GtkClassInitFunc) gtk_tree_class_init, + (GtkObjectInitFunc) gtk_tree_init, + (GtkArgFunc) NULL, + }; + + tree_type = gtk_type_unique (gtk_container_get_type (), &tree_info); + } + + return tree_type; +} + +static void +gtk_tree_class_init (GtkTreeClass *class) +{ +} + +static void +gtk_tree_init (GtkTree *tree) +{ +} + +GtkWidget* +gtk_tree_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_tree_get_type ())); +} + +void +gtk_tree_append (GtkTree *tree, + GtkWidget *child) +{ +} + +void +gtk_tree_prepend (GtkTree *tree, + GtkWidget *child) +{ +} + +void +gtk_tree_insert (GtkTree *tree, + GtkWidget *child, + gint position) +{ +} diff --git a/gtk/gtktree.h b/gtk/gtktree.h new file mode 100644 index 0000000000..1486a82ab8 --- /dev/null +++ b/gtk/gtktree.h @@ -0,0 +1,68 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_TREE_H__ +#define __GTK_TREE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TREE(obj) GTK_CHECK_CAST (obj, gtk_tree_get_type (), GtkTree) +#define GTK_TREE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_tree_get_type (), GtkTreeClass) +#define GTK_IS_TREE(obj) GTK_CHECK_TYPE (obj, gtk_tree_get_type ()) + + +typedef struct _GtkTree GtkTree; +typedef struct _GtkTreeClass GtkTreeClass; + +struct _GtkTree +{ + GtkContainer container; + + GList *children; +}; + +struct _GtkTreeClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_tree_get_type (void); +GtkWidget* gtk_tree_new (void); +void gtk_tree_append (GtkTree *tree, + GtkWidget *child); +void gtk_tree_prepend (GtkTree *tree, + GtkWidget *child); +void gtk_tree_insert (GtkTree *tree, + GtkWidget *child, + gint position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TREE_H__ */ diff --git a/gtk/gtktreeitem.c b/gtk/gtktreeitem.c new file mode 100644 index 0000000000..8f0d9f078d --- /dev/null +++ b/gtk/gtktreeitem.c @@ -0,0 +1,108 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtklabel.h" +#include "gtktreeitem.h" + + +static void gtk_tree_item_class_init (GtkTreeItemClass *klass); +static void gtk_tree_item_init (GtkTreeItem *tree_item); + + +guint +gtk_tree_item_get_type () +{ + static guint tree_item_type = 0; + + if (!tree_item_type) + { + GtkTypeInfo tree_item_info = + { + "GtkTreeItem", + sizeof (GtkTreeItem), + sizeof (GtkTreeItemClass), + (GtkClassInitFunc) gtk_tree_item_class_init, + (GtkObjectInitFunc) gtk_tree_item_init, + (GtkArgFunc) NULL, + }; + + tree_item_type = gtk_type_unique (gtk_item_get_type (), &tree_item_info); + } + + return tree_item_type; +} + +static void +gtk_tree_item_class_init (GtkTreeItemClass *class) +{ +} + +static void +gtk_tree_item_init (GtkTreeItem *tree_item) +{ +} + + +GtkWidget* +gtk_tree_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_tree_item_get_type ())); +} + +GtkWidget* +gtk_tree_item_new_with_label (gchar *label) +{ + GtkWidget *tree_item; + GtkWidget *label_widget; + + tree_item = gtk_tree_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (tree_item), label_widget); + gtk_widget_show (label_widget); + + return tree_item; +} + +void +gtk_tree_item_set_subtree (GtkTreeItem *tree_item, + GtkWidget *subtree) +{ + g_return_if_fail (tree_item != NULL); + g_return_if_fail (GTK_IS_TREE_ITEM (tree_item)); +} + +void +gtk_tree_item_select (GtkTreeItem *tree_item) +{ +} + +void +gtk_tree_item_deselect (GtkTreeItem *tree_item) +{ +} + +void +gtk_tree_item_expand (GtkTreeItem *tree_item) +{ +} + +void +gtk_tree_item_collapse (GtkTreeItem *tree_item) +{ +} diff --git a/gtk/gtktreeitem.h b/gtk/gtktreeitem.h new file mode 100644 index 0000000000..921f681bc3 --- /dev/null +++ b/gtk/gtktreeitem.h @@ -0,0 +1,72 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_TREE_ITEM_H__ +#define __GTK_TREE_ITEM_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkitem.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TREE_ITEM(obj) GTK_CHECK_CAST (obj, gtk_tree_item_get_type (), GtkTreeItem) +#define GTK_TREE_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_tree_item_get_type (), GtkTreeItemClass) +#define GTK_IS_TREE_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_tree_item_get_type ()) + + +typedef struct _GtkTreeItem GtkTreeItem; +typedef struct _GtkTreeItemClass GtkTreeItemClass; + +struct _GtkTreeItem +{ + GtkItem item; + + GtkWidget *child; + GtkWidget *subtree; +}; + +struct _GtkTreeItemClass +{ + GtkItemClass parent_class; + + void (* expand) (GtkTreeItem *tree_item); + void (* collapse) (GtkTreeItem *tree_item); +}; + + +guint gtk_tree_item_get_type (void); +GtkWidget* gtk_tree_item_new (void); +GtkWidget* gtk_tree_item_new_with_label (gchar *label); +void gtk_tree_item_set_subtree (GtkTreeItem *tree_item, + GtkWidget *subtree); +void gtk_tree_item_select (GtkTreeItem *tree_item); +void gtk_tree_item_deselect (GtkTreeItem *tree_item); +void gtk_tree_item_expand (GtkTreeItem *tree_item); +void gtk_tree_item_collapse (GtkTreeItem *tree_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TREE_ITEM_H__ */ diff --git a/gtk/gtktypebuiltins.c b/gtk/gtktypebuiltins.c new file mode 100644 index 0000000000..e43573119d --- /dev/null +++ b/gtk/gtktypebuiltins.c @@ -0,0 +1,53 @@ +/* generated by gentypeinfo from "gtk.defs" */ + + { "GtkWindowType", GTK_TYPE_ENUM }, + { "GtkStateType", GTK_TYPE_ENUM }, + { "GtkDirectionType", GTK_TYPE_ENUM }, + { "GtkShadowType", GTK_TYPE_ENUM }, + { "GtkArrowType", GTK_TYPE_ENUM }, + { "GtkPackType", GTK_TYPE_ENUM }, + { "GtkPolicyType", GTK_TYPE_ENUM }, + { "GtkUpdateType", GTK_TYPE_ENUM }, + { "GtkAttachOptions", GTK_TYPE_FLAGS }, + { "GtkSignalRunType", GTK_TYPE_FLAGS }, + { "GtkWindowPosition", GTK_TYPE_ENUM }, + { "GtkSubmenuDirection", GTK_TYPE_ENUM }, + { "GtkSubmenuPlacement", GTK_TYPE_ENUM }, + { "GtkMenuFactoryType", GTK_TYPE_ENUM }, + { "GtkMetricType", GTK_TYPE_ENUM }, + { "GtkScrollType", GTK_TYPE_ENUM }, + { "GtkTroughType", GTK_TYPE_ENUM }, + { "GtkPositionType", GTK_TYPE_ENUM }, + { "GtkPreviewType", GTK_TYPE_ENUM }, + { "GtkWidgetFlags", GTK_TYPE_FLAGS }, + { "GdkWindowType", GTK_TYPE_ENUM }, + { "GdkWindowClass", GTK_TYPE_ENUM }, + { "GdkImageType", GTK_TYPE_ENUM }, + { "GdkVisualType", GTK_TYPE_ENUM }, + { "GdkWindowAttributesType", GTK_TYPE_FLAGS }, + { "GdkWindowHints", GTK_TYPE_FLAGS }, + { "GdkFunction", GTK_TYPE_ENUM }, + { "GdkFill", GTK_TYPE_ENUM }, + { "GdkLineStyle", GTK_TYPE_ENUM }, + { "GdkCapStyle", GTK_TYPE_ENUM }, + { "GdkJoinStyle", GTK_TYPE_ENUM }, + { "GdkCursorType", GTK_TYPE_ENUM }, + { "GdkEventType", GTK_TYPE_ENUM }, + { "GdkEventMask", GTK_TYPE_FLAGS }, + { "GdkNotifyType", GTK_TYPE_ENUM }, + { "GdkModifierType", GTK_TYPE_FLAGS }, + { "GdkSubwindowMode", GTK_TYPE_ENUM }, + { "GdkInputCondition", GTK_TYPE_FLAGS }, + { "GdkStatus", GTK_TYPE_ENUM }, + { "GdkByteOrder", GTK_TYPE_ENUM }, + { "GdkGCValuesMask", GTK_TYPE_FLAGS }, + { "GdkSelection", GTK_TYPE_ENUM }, + { "GdkPropertyState", GTK_TYPE_ENUM }, + { "GdkPropMode", GTK_TYPE_ENUM }, + { "GtkAcceleratorTable", GTK_TYPE_BOXED }, + { "GtkStyle", GTK_TYPE_BOXED }, + { "GdkColormap", GTK_TYPE_BOXED }, + { "GdkVisual", GTK_TYPE_BOXED }, + { "GdkFont", GTK_TYPE_BOXED }, + { "GdkWindow", GTK_TYPE_BOXED }, + { "GdkEvent", GTK_TYPE_BOXED }, diff --git a/gtk/gtktypebuiltins.h b/gtk/gtktypebuiltins.h new file mode 100644 index 0000000000..ba9131f0f1 --- /dev/null +++ b/gtk/gtktypebuiltins.h @@ -0,0 +1,54 @@ +/* generated by gentypeinfo from "gtk.defs" */ + +#define GTK_TYPE_WINDOW_TYPE (gtk_type_builtins[0]) +#define GTK_TYPE_STATE_TYPE (gtk_type_builtins[1]) +#define GTK_TYPE_DIRECTION_TYPE (gtk_type_builtins[2]) +#define GTK_TYPE_SHADOW_TYPE (gtk_type_builtins[3]) +#define GTK_TYPE_ARROW_TYPE (gtk_type_builtins[4]) +#define GTK_TYPE_PACK_TYPE (gtk_type_builtins[5]) +#define GTK_TYPE_POLICY_TYPE (gtk_type_builtins[6]) +#define GTK_TYPE_UPDATE_TYPE (gtk_type_builtins[7]) +#define GTK_TYPE_ATTACH_OPTIONS (gtk_type_builtins[8]) +#define GTK_TYPE_SIGNAL_RUN_TYPE (gtk_type_builtins[9]) +#define GTK_TYPE_WINDOW_POSITION (gtk_type_builtins[10]) +#define GTK_TYPE_SUBMENU_DIRECTION (gtk_type_builtins[11]) +#define GTK_TYPE_SUBMENU_PLACEMENT (gtk_type_builtins[12]) +#define GTK_TYPE_MENU_FACTORY_TYPE (gtk_type_builtins[13]) +#define GTK_TYPE_METRIC_TYPE (gtk_type_builtins[14]) +#define GTK_TYPE_SCROLL_TYPE (gtk_type_builtins[15]) +#define GTK_TYPE_TROUGH_TYPE (gtk_type_builtins[16]) +#define GTK_TYPE_POSITION_TYPE (gtk_type_builtins[17]) +#define GTK_TYPE_PREVIEW_TYPE (gtk_type_builtins[18]) +#define GTK_TYPE_WIDGET_FLAGS (gtk_type_builtins[19]) +#define GTK_TYPE_GDK_WINDOW_TYPE (gtk_type_builtins[20]) +#define GTK_TYPE_GDK_WINDOW_CLASS (gtk_type_builtins[21]) +#define GTK_TYPE_GDK_IMAGE_TYPE (gtk_type_builtins[22]) +#define GTK_TYPE_GDK_VISUAL_TYPE (gtk_type_builtins[23]) +#define GTK_TYPE_GDK_WINDOW_ATTRIBUTES_TYPE (gtk_type_builtins[24]) +#define GTK_TYPE_GDK_WINDOW_HINTS (gtk_type_builtins[25]) +#define GTK_TYPE_GDK_FUNCTION (gtk_type_builtins[26]) +#define GTK_TYPE_GDK_FILL (gtk_type_builtins[27]) +#define GTK_TYPE_GDK_LINE_STYLE (gtk_type_builtins[28]) +#define GTK_TYPE_GDK_CAP_STYLE (gtk_type_builtins[29]) +#define GTK_TYPE_GDK_JOIN_STYLE (gtk_type_builtins[30]) +#define GTK_TYPE_GDK_CURSOR_TYPE (gtk_type_builtins[31]) +#define GTK_TYPE_GDK_EVENT_TYPE (gtk_type_builtins[32]) +#define GTK_TYPE_GDK_EVENT_MASK (gtk_type_builtins[33]) +#define GTK_TYPE_GDK_NOTIFY_TYPE (gtk_type_builtins[34]) +#define GTK_TYPE_GDK_MODIFIER_TYPE (gtk_type_builtins[35]) +#define GTK_TYPE_GDK_SUBWINDOW_MODE (gtk_type_builtins[36]) +#define GTK_TYPE_GDK_INPUT_CONDITION (gtk_type_builtins[37]) +#define GTK_TYPE_GDK_STATUS (gtk_type_builtins[38]) +#define GTK_TYPE_GDK_BYTE_ORDER (gtk_type_builtins[39]) +#define GTK_TYPE_GDK_GCVALUES_MASK (gtk_type_builtins[40]) +#define GTK_TYPE_GDK_SELECTION (gtk_type_builtins[41]) +#define GTK_TYPE_GDK_PROPERTY_STATE (gtk_type_builtins[42]) +#define GTK_TYPE_GDK_PROP_MODE (gtk_type_builtins[43]) +#define GTK_TYPE_ACCELERATOR_TABLE (gtk_type_builtins[44]) +#define GTK_TYPE_STYLE (gtk_type_builtins[45]) +#define GTK_TYPE_GDK_COLORMAP (gtk_type_builtins[46]) +#define GTK_TYPE_GDK_VISUAL (gtk_type_builtins[47]) +#define GTK_TYPE_GDK_FONT (gtk_type_builtins[48]) +#define GTK_TYPE_GDK_WINDOW (gtk_type_builtins[49]) +#define GTK_TYPE_GDK_EVENT (gtk_type_builtins[50]) +#define GTK_TYPE_NUM_BUILTINS 51 diff --git a/gtk/gtktypeutils.c b/gtk/gtktypeutils.c new file mode 100644 index 0000000000..46e035fd9a --- /dev/null +++ b/gtk/gtktypeutils.c @@ -0,0 +1,459 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include "gtkobject.h" +#include "gtktypeutils.h" + + +typedef struct _GtkTypeNode GtkTypeNode; + +struct _GtkTypeNode +{ + GtkType type; + gint init_class; + gpointer klass; + GtkTypeInfo type_info; + GtkTypeNode *parent; + GList *children; +}; + + +static void gtk_type_insert (guint parent_type, + GtkType type, + GtkTypeInfo *type_info); +static void gtk_type_class_init (GtkTypeNode *node); +static void gtk_type_object_init (GtkTypeNode *node, + gpointer object); +static guint gtk_type_hash (GtkType *key); +static gint gtk_type_compare (GtkType *a, + GtkType *b); +static guint gtk_type_name_hash (const char *key); +static gint gtk_type_name_compare (const char *a, + const char *b); +static void gtk_type_init_builtin_types (); + + +static int initialize = TRUE; +static GHashTable *type_hash_table = NULL; +static GHashTable *name_hash_table = NULL; + + +void +gtk_type_init () +{ + if (initialize) + { + g_assert (sizeof (GtkType) >= 4); + + initialize = FALSE; + type_hash_table = g_hash_table_new ((GHashFunc) gtk_type_hash, + (GCompareFunc) gtk_type_compare); + name_hash_table = g_hash_table_new ((GHashFunc) gtk_type_name_hash, + (GCompareFunc) gtk_type_name_compare); + gtk_type_init_builtin_types (); + } +} + +GtkType +gtk_type_unique (GtkType parent_type, + GtkTypeInfo *type_info) +{ + static guint next_seqno = 0; + GtkType new_type; + + g_return_val_if_fail (type_info != NULL, 0); + + if (initialize) + gtk_type_init (); + + next_seqno++; + if (parent_type == GTK_TYPE_INVALID) + new_type = next_seqno; + else + new_type = GTK_TYPE_MAKE (GTK_FUNDAMENTAL_TYPE (parent_type), next_seqno); + gtk_type_insert (parent_type, new_type, type_info); + + return new_type; +} + +gchar* +gtk_type_name (GtkType type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + if (node) + return node->type_info.type_name; + + return NULL; +} + +GtkType +gtk_type_from_name (const gchar *name) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (name_hash_table, (gpointer) name); + + if (node) + return node->type; + + return 0; +} + +GtkType +gtk_type_parent (GtkType type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + if (node && node->parent) + return node->parent->type; + + return 0; +} + +gpointer +gtk_type_class (GtkType type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + g_return_val_if_fail (node != NULL, NULL); + + if (node->init_class) + gtk_type_class_init (node); + + return node->klass; +} + +gpointer +gtk_type_new (GtkType type) +{ + GtkTypeNode *node; + gpointer object; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + g_return_val_if_fail (node != NULL, NULL); + + object = g_new0 (guchar, node->type_info.object_size); + ((GtkObject*) object)->klass = gtk_type_class (type); + gtk_type_object_init (node, object); + + return object; +} + +void +gtk_type_describe_heritage (GtkType type) +{ + GtkTypeNode *node; + gint first; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + first = TRUE; + + while (node) + { + if (first) + { + first = FALSE; + g_print ("is a "); + } + + if (node->type_info.type_name) + g_print ("%s\n", node->type_info.type_name); + else + g_print ("<unnamed type>\n"); + + node = node->parent; + } +} + +void +gtk_type_describe_tree (GtkType type, + gint show_size) +{ + static gint indent = 0; + GtkTypeNode *node; + GtkTypeNode *child; + GList *children; + gint old_indent; + gint i; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + for (i = 0; i < indent; i++) + g_print (" "); + + if (node->type_info.type_name) + g_print ("%s", node->type_info.type_name); + else + g_print ("<unnamed type>"); + + if (show_size) + g_print (" ( %d bytes )\n", node->type_info.object_size); + else + g_print ("\n"); + + old_indent = indent; + indent += 4; + + children = node->children; + while (children) + { + child = children->data; + children = children->next; + + gtk_type_describe_tree (child->type, show_size); + } + + indent = old_indent; +} + +gint +gtk_type_is_a (GtkType type, + GtkType is_a_type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + while (node) + { + if (node->type == is_a_type) + return TRUE; + node = node->parent; + } + + return FALSE; +} + +void +gtk_type_set_arg (GtkObject *object, + GtkType type, + GtkArg *arg) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + if (node->type_info.arg_func) + (* node->type_info.arg_func) (object, arg); +} + +static void +gtk_type_insert (GtkType parent_type, + GtkType type, + GtkTypeInfo *type_info) +{ + GtkTypeNode *node; + GtkTypeNode *parent; + + parent = g_hash_table_lookup (type_hash_table, &parent_type); + + node = g_new (GtkTypeNode, 1); + node->type = type; + node->init_class = TRUE; + node->klass = NULL; + node->type_info = *type_info; + node->parent = parent; + node->children = NULL; + + if (node->parent) + node->parent->children = g_list_append (node->parent->children, node); + + g_hash_table_insert (type_hash_table, &node->type, node); + g_hash_table_insert (name_hash_table, node->type_info.type_name, node); +} + +static void +gtk_type_class_init (GtkTypeNode *node) +{ + GtkObjectClass *object_class; + + if (node->init_class) + { + node->init_class = FALSE; + node->klass = g_new0 (guchar, node->type_info.class_size); + + if (node->parent) + { + if (node->parent->init_class) + gtk_type_class_init (node->parent); + + memcpy (node->klass, node->parent->klass, node->parent->type_info.class_size); + } + + object_class = node->klass; + object_class->type = node->type; + + if (node->type_info.class_init_func) + (* node->type_info.class_init_func) (node->klass); + } +} + +static void +gtk_type_object_init (GtkTypeNode *node, + gpointer object) +{ + if (node->parent) + gtk_type_object_init (node->parent, object); + + if (node->type_info.object_init_func) + (* node->type_info.object_init_func) (object); +} + +static guint +gtk_type_hash (GtkType *key) +{ + return GTK_TYPE_SEQNO (*key); +} + +static gint +gtk_type_compare (GtkType *a, + GtkType *b) +{ + g_return_val_if_fail(a != NULL && b != NULL, 0); + return (*a == *b); +} + +static guint +gtk_type_name_hash (const char *key) +{ + guint result; + + result = 0; + while (*key) + result += (result << 3) + *key++; + + return result; +} + +static gint +gtk_type_name_compare (const char *a, + const char *b) +{ + return (strcmp (a, b) == 0); +} + +static GtkType +gtk_type_register_builtin (char *name, + GtkType parent) +{ + GtkTypeInfo info; + + info.type_name = name; + info.object_size = info.class_size = 0; + info.class_init_func = NULL; + info.object_init_func = NULL; + info.arg_func = NULL; + + return gtk_type_unique (parent, &info); +} + +extern void gtk_object_init_type (); + +GtkType gtk_type_builtins[GTK_TYPE_NUM_BUILTINS]; + +static void +gtk_type_init_builtin_types () +{ + /* GTK_TYPE_INVALID has typeid 0. The first type id returned by + gtk_type_unique is 1, which is GTK_TYPE_NONE. And so on. */ + + static struct { + GtkType enum_id; + gchar *name; + } fundamental_info[] = { + { GTK_TYPE_NONE, "void" }, + { GTK_TYPE_CHAR, "char" }, + { GTK_TYPE_BOOL, "bool" }, + { GTK_TYPE_INT, "int" }, + { GTK_TYPE_UINT, "uint" }, + { GTK_TYPE_LONG, "long" }, + { GTK_TYPE_ULONG, "ulong" }, + { GTK_TYPE_FLOAT, "float" }, + { GTK_TYPE_STRING, "string" }, + { GTK_TYPE_ENUM, "enum" }, + { GTK_TYPE_FLAGS, "flags" }, + { GTK_TYPE_BOXED, "boxed" }, + { GTK_TYPE_FOREIGN, "foreign" }, + { GTK_TYPE_CALLBACK, "callback" }, + { GTK_TYPE_ARGS, "args" }, + + { GTK_TYPE_POINTER, "pointer" }, + { GTK_TYPE_SIGNAL, "signal" }, + { GTK_TYPE_C_CALLBACK, "c_callback" } + }; + + static struct { + char *name; + GtkType parent; + } builtin_info[] = { +#include "gtktypebuiltins.c" + { NULL } + }; + + int i; + + for (i = 0; i < sizeof (fundamental_info)/sizeof(fundamental_info[0]); i++) + { + GtkType id; + id = gtk_type_register_builtin (fundamental_info[i].name, + GTK_TYPE_INVALID); + g_assert (id == fundamental_info[i].enum_id); + } + + gtk_object_init_type (); + + for (i = 0; builtin_info[i].name; i++) + { + gtk_type_builtins[i] = + gtk_type_register_builtin (builtin_info[i].name, + builtin_info[i].parent); + } +} diff --git a/gtk/gtktypeutils.h b/gtk/gtktypeutils.h new file mode 100644 index 0000000000..911885be95 --- /dev/null +++ b/gtk/gtktypeutils.h @@ -0,0 +1,196 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_TYPE_UTILS_H__ +#define __GTK_TYPE_UTILS_H__ + + +#include <gdk/gdk.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Fundamental Types */ + +typedef enum +{ + GTK_TYPE_INVALID, + GTK_TYPE_NONE, + GTK_TYPE_CHAR, + GTK_TYPE_BOOL, + GTK_TYPE_INT, + GTK_TYPE_UINT, + GTK_TYPE_LONG, + GTK_TYPE_ULONG, + GTK_TYPE_FLOAT, + GTK_TYPE_STRING, + GTK_TYPE_ENUM, + GTK_TYPE_FLAGS, + GTK_TYPE_BOXED, + GTK_TYPE_FOREIGN, + GTK_TYPE_CALLBACK, + GTK_TYPE_ARGS, + + GTK_TYPE_POINTER, + + /* it'd be great if the next two could be removed eventually */ + GTK_TYPE_SIGNAL, + GTK_TYPE_C_CALLBACK, + + GTK_TYPE_OBJECT + +} GtkFundamentalType; + +typedef guint GtkType; + +/* Builtin Types */ + +extern GtkType gtk_type_builtins[]; +#include <gtk/gtktypebuiltins.h> + +/* General Types */ + +#define GTK_TYPE_MAKE(ft, seqno) (((seqno)<<8)|ft) +#define GTK_FUNDAMENTAL_TYPE(t) ((GtkFundamentalType)((t)&0xFF)) +#define GTK_TYPE_SEQNO(t) ((t)>0xFF? (t)>>8:(t)) + +typedef struct _GtkArg GtkArg; +typedef struct _GtkObject GtkObject; /* forward declaration of object type */ +typedef struct _GtkTypeInfo GtkTypeInfo; + +typedef void (*GtkClassInitFunc) (gpointer klass); +typedef void (*GtkObjectInitFunc) (gpointer object); +typedef void (*GtkArgFunc) (GtkObject *object, GtkArg *arg); +typedef gint (*GtkFunction) (gpointer data); +typedef void (*GtkRemoveFunction) (gpointer data); +typedef void (*GtkCallbackMarshal) (GtkObject *object, + gpointer data, + int n_args, + GtkArg *args); +typedef void (*GtkDestroyNotify) (gpointer data); + +struct _GtkArg +{ + GtkType type; + char *name; + + union { + gchar char_data; + gint int_data; + guint uint_data; + gint bool_data; + glong long_data; + gulong ulong_data; + gfloat float_data; + gchar *string_data; + gpointer pointer_data; + GtkObject *object_data; + struct { + GtkCallbackMarshal marshal; + gpointer data; + GtkDestroyNotify notify; + } callback_data; + struct { + gpointer data; + GtkDestroyNotify notify; + } foreign_data; + struct { + gint n_args; + GtkArg *args; + } args_data; + struct { + GtkFunction f; + gpointer d; + } signal_data; + struct { + GtkFunction func; + gpointer func_data; + } c_callback_data; + } d; +}; + +#define GTK_VALUE_CHAR(a) ((a).d.char_data) +#define GTK_VALUE_BOOL(a) ((a).d.bool_data) +#define GTK_VALUE_INT(a) ((a).d.int_data) +#define GTK_VALUE_UINT(a) ((a).d.uint_data) +#define GTK_VALUE_LONG(a) ((a).d.long_data) +#define GTK_VALUE_ULONG(a) ((a).d.ulong_data) +#define GTK_VALUE_FLOAT(a) ((a).d.float_data) +#define GTK_VALUE_STRING(a) ((a).d.string_data) +#define GTK_VALUE_ENUM(a) ((a).d.int_data) +#define GTK_VALUE_FLAGS(a) ((a).d.int_data) +#define GTK_VALUE_BOXED(a) ((a).d.pointer_data) +#define GTK_VALUE_FOREIGN(a) ((a).d.foreign_data) +#define GTK_VALUE_CALLBACK(a) ((a).d.callback_data) +#define GTK_VALUE_ARGS(a) ((a).d.args_data) +#define GTK_VALUE_OBJECT(a) ((a).d.object_data) +#define GTK_VALUE_POINTER(a) ((a).d.pointer_data) +#define GTK_VALUE_SIGNAL(a) ((a).d.signal_data) +#define GTK_VALUE_C_CALLBACK(a) ((a).d.c_callback_data) + +#define GTK_RETLOC_CHAR(a) ((gchar*)(a).d.pointer_data) +#define GTK_RETLOC_BOOL(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_INT(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_UINT(a) ((guint*)(a).d.pointer_data) +#define GTK_RETLOC_LONG(a) ((glong*)(a).d.pointer_data) +#define GTK_RETLOC_ULONG(a) ((gulong*)(a).d.pointer_data) +#define GTK_RETLOC_FLOAT(a) ((gfloat*)(a).d.pointer_data) +#define GTK_RETLOC_STRING(a) ((gchar**)(a).d.pointer_data) +#define GTK_RETLOC_ENUM(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_FLAGS(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_BOXED(a) ((gpointer*)(a).d.pointer_data) +#define GTK_RETLOC_OBJECT(a) ((GtkObject**)(a).d.pointer_data) +#define GTK_RETLOC_POINTER(a) ((gpointer*)(a).d.pointer_data) + +struct _GtkTypeInfo +{ + gchar *type_name; + guint object_size; + guint class_size; + GtkClassInitFunc class_init_func; + GtkObjectInitFunc object_init_func; + GtkArgFunc arg_func; +}; + + +void gtk_type_init (void); +GtkType gtk_type_unique (guint parent_type, + GtkTypeInfo *type_info); +gchar* gtk_type_name (guint type); +GtkType gtk_type_from_name (const gchar *name); +GtkType gtk_type_parent (GtkType type); +gpointer gtk_type_class (GtkType type); +gpointer gtk_type_new (GtkType type); +void gtk_type_describe_heritage (GtkType type); +void gtk_type_describe_tree (GtkType type, + gint show_size); +gint gtk_type_is_a (GtkType type, + GtkType is_a_type); +void gtk_type_set_arg (GtkObject *object, + GtkType type, + GtkArg *arg); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TYPE_UTILS_H__ */ diff --git a/gtk/gtkvbbox.c b/gtk/gtkvbbox.c new file mode 100644 index 0000000000..4fc867fdf3 --- /dev/null +++ b/gtk/gtkvbbox.c @@ -0,0 +1,272 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkvbbox.h" + + +static void gtk_vbutton_box_class_init (GtkVButtonBoxClass *klass); +static void gtk_vbutton_box_init (GtkVButtonBox *box); +static void gtk_vbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static gint default_spacing = 10; +static gint default_layout_style = GTK_BUTTONBOX_EDGE; + +guint +gtk_vbutton_box_get_type () +{ + static guint vbutton_box_type = 0; + + if (!vbutton_box_type) + { + GtkTypeInfo vbutton_box_info = + { + "GtkVButtonBox", + sizeof (GtkVButtonBox), + sizeof (GtkVButtonBoxClass), + (GtkClassInitFunc) gtk_vbutton_box_class_init, + (GtkObjectInitFunc) gtk_vbutton_box_init, + (GtkArgFunc) NULL, + }; + + vbutton_box_type = gtk_type_unique (gtk_button_box_get_type (), &vbutton_box_info); + } + + return vbutton_box_type; +} + +static void +gtk_vbutton_box_class_init (GtkVButtonBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_vbutton_box_size_request; + widget_class->size_allocate = gtk_vbutton_box_size_allocate; +} + +static void +gtk_vbutton_box_init (GtkVButtonBox *vbutton_box) +{ + /* button_box_init has done everything allready */ +} + +GtkWidget* +gtk_vbutton_box_new () +{ + GtkVButtonBox *vbutton_box; + + vbutton_box = gtk_type_new (gtk_vbutton_box_get_type ()); + return GTK_WIDGET (vbutton_box); +} + + + +/* set default value for spacing */ + +void gtk_vbutton_box_set_spacing_default (gint spacing) +{ + default_spacing = spacing; +} + + +/* set default value for layout style */ + +void gtk_vbutton_box_set_layout_default (gint layout) +{ + default_layout_style = layout; +} + +/* get default value for spacing */ + +gint gtk_vbutton_box_get_spacing_default (void) +{ + return default_spacing; +} + + + +/* get default value for layout style */ + +gint gtk_vbutton_box_get_layout_default (void) +{ + return default_layout_style; +} + + + + +static void +gtk_vbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkButtonBox *bbox; + gint nvis_children; + gint child_width; + gint child_height; + gint spacing; + gint layout; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBUTTON_BOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + bbox = GTK_BUTTON_BOX (widget); + + spacing = bbox->spacing != GTK_BUTTONBOX_DEFAULT + ? bbox->spacing : default_spacing; + layout = bbox->layout_style != GTK_BUTTONBOX_DEFAULT + ? bbox->layout_style : default_layout_style; + + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + + if (nvis_children == 0) + { + requisition->width = 0; + requisition->height = 0; + } + else + { + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + requisition->height = + nvis_children*child_height + ((nvis_children+1)*spacing); + break; + case GTK_BUTTONBOX_EDGE: + case GTK_BUTTONBOX_START: + case GTK_BUTTONBOX_END: + requisition->height = + nvis_children*child_height + ((nvis_children-1)*spacing); + break; + default: + g_assert_not_reached(); + break; + } + + requisition->width = child_width; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + + + +static void +gtk_vbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkButtonBox *box; + GtkVButtonBox *hbox; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint child_width; + gint child_height; + gint x = 0; + gint y = 0; + gint height; + gint childspace; + gint childspacing = 0; + gint layout; + gint spacing; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBUTTON_BOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BUTTON_BOX (widget); + hbox = GTK_VBUTTON_BOX (widget); + spacing = box->spacing != GTK_BUTTONBOX_DEFAULT + ? box->spacing : default_spacing; + layout = box->layout_style != GTK_BUTTONBOX_DEFAULT + ? box->layout_style : default_layout_style; + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + widget->allocation = *allocation; + height = allocation->height - GTK_CONTAINER (box)->border_width*2; + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + childspacing = (height - (nvis_children*child_height)) / (nvis_children+1); + y = allocation->y + GTK_CONTAINER (box)->border_width + childspacing; + break; + case GTK_BUTTONBOX_EDGE: + if (nvis_children >= 2) + { + childspacing = + (height - (nvis_children*child_height)) / (nvis_children-1); + y = allocation->y + GTK_CONTAINER (box)->border_width; + } + else + { + /* one or zero children, just center */ + childspacing = height; + y = allocation->y + (allocation->height - child_height) / 2; + } + break; + case GTK_BUTTONBOX_START: + childspacing = spacing; + y = allocation->y + GTK_CONTAINER (box)->border_width; + break; + case GTK_BUTTONBOX_END: + childspacing = spacing; + y = allocation->x + allocation->height - child_height * nvis_children + - spacing * (nvis_children-1) + - GTK_CONTAINER (box)->border_width; + break; + default: + g_assert_not_reached(); + break; + } + + + x = allocation->x + (allocation->width - child_width) / 2; + childspace = child_height + childspacing; + + children = GTK_BOX (box)->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + child_allocation.width = child_width; + child_allocation.height = child_height; + child_allocation.x = x; + child_allocation.y = y; + gtk_widget_size_allocate (child->widget, &child_allocation); + y += childspace; + } + } +} + + diff --git a/gtk/gtkvbbox.h b/gtk/gtkvbbox.h new file mode 100644 index 0000000000..310553d2ad --- /dev/null +++ b/gtk/gtkvbbox.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VBUTTON_BOX_H__ +#define __GTK_VBUTTON_BOX_H__ + + +#include "gtkbbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VBUTTON_BOX(obj) GTK_CHECK_CAST (obj, gtk_vbutton_box_get_type (), GtkVButtonBox) +#define GTK_VBUTTON_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vbutton_box_get_type (), GtkVButtonBoxClass) +#define GTK_IS_VBUTTON_BOX(obj) GTK_CHECK_TYPE (obj, gtk_vbutton_box_get_type ()) + + +typedef struct _GtkVButtonBox GtkVButtonBox; +typedef struct _GtkVButtonBoxClass GtkVButtonBoxClass; + +struct _GtkVButtonBox +{ + GtkButtonBox button_box; +}; + +struct _GtkVButtonBoxClass +{ + GtkButtonBoxClass parent_class; +}; + + +guint gtk_vbutton_box_get_type (void); +GtkWidget *gtk_vbutton_box_new (void); + +/* buttons can be added by gtk_container_add() */ + +gint gtk_vbutton_box_get_spacing_default (void); +void gtk_vbutton_box_set_spacing_default (gint spacing); + +void gtk_vbutton_box_set_spacing_default (gint spacing); +void gtk_vbutton_box_set_layout_default (gint layout); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VBUTTON_BOX_H__ */ diff --git a/gtk/gtkvbox.c b/gtk/gtkvbox.c new file mode 100644 index 0000000000..585e99b87b --- /dev/null +++ b/gtk/gtkvbox.c @@ -0,0 +1,306 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkvbox.h" + + +static void gtk_vbox_class_init (GtkVBoxClass *klass); +static void gtk_vbox_init (GtkVBox *box); +static void gtk_vbox_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_vbox_get_type () +{ + static guint vbox_type = 0; + + if (!vbox_type) + { + GtkTypeInfo vbox_info = + { + "GtkVBox", + sizeof (GtkVBox), + sizeof (GtkVBoxClass), + (GtkClassInitFunc) gtk_vbox_class_init, + (GtkObjectInitFunc) gtk_vbox_init, + (GtkArgFunc) NULL, + }; + + vbox_type = gtk_type_unique (gtk_box_get_type (), &vbox_info); + } + + return vbox_type; +} + +static void +gtk_vbox_class_init (GtkVBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_vbox_size_request; + widget_class->size_allocate = gtk_vbox_size_allocate; +} + +static void +gtk_vbox_init (GtkVBox *vbox) +{ +} + +GtkWidget* +gtk_vbox_new (gint homogeneous, + gint spacing) +{ + GtkVBox *vbox; + + vbox = gtk_type_new (gtk_vbox_get_type ()); + + GTK_BOX (vbox)->spacing = spacing; + GTK_BOX (vbox)->homogeneous = homogeneous ? TRUE : FALSE; + + return GTK_WIDGET (vbox); +} + + +static void +gtk_vbox_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + gint nvis_children; + gint height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + requisition->width = 0; + requisition->height = 0; + nvis_children = 0; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + gtk_widget_size_request (child->widget, &child->widget->requisition); + + if (box->homogeneous) + { + height = child->widget->requisition.height + child->padding * 2; + requisition->height = MAX (requisition->height, height); + } + else + { + requisition->height += child->widget->requisition.height + child->padding * 2; + } + + requisition->width = MAX (requisition->width, child->widget->requisition.width); + + nvis_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + requisition->height *= nvis_children; + requisition->height += (nvis_children - 1) * box->spacing; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + +static void +gtk_vbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint nexpand_children; + gint child_height; + gint height; + gint extra; + gint y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BOX (widget); + widget->allocation = *allocation; + + nvis_children = 0; + nexpand_children = 0; + children = box->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + nvis_children += 1; + if (child->expand) + nexpand_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + { + height = (allocation->height - + GTK_CONTAINER (box)->border_width * 2 - + (nvis_children - 1) * box->spacing); + extra = height / nvis_children; + } + else if (nexpand_children > 0) + { + height = allocation->height - widget->requisition.height; + extra = height / nexpand_children; + } + else + { + height = 0; + extra = 0; + } + + y = allocation->y + GTK_CONTAINER (box)->border_width; + child_allocation.x = allocation->x + GTK_CONTAINER (box)->border_width; + child_allocation.width = allocation->width - GTK_CONTAINER (box)->border_width * 2; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_height = height; + else + child_height = extra; + + nvis_children -= 1; + height -= extra; + } + else + { + child_height = child->widget->requisition.height + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_height += height; + else + child_height += extra; + + nexpand_children -= 1; + height -= extra; + } + } + + if (child->fill) + { + child_allocation.height = child_height - child->padding * 2; + child_allocation.y = y + child->padding; + } + else + { + child_allocation.height = child->widget->requisition.height; + child_allocation.y = y + (child_height - child_allocation.height) / 2; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + y += child_height + box->spacing; + } + } + + y = allocation->y + allocation->height - GTK_CONTAINER (box)->border_width; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_height = height; + else + child_height = extra; + + nvis_children -= 1; + height -= extra; + } + else + { + child_height = child->widget->requisition.height + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_height += height; + else + child_height += extra; + + nexpand_children -= 1; + height -= extra; + } + } + + if (child->fill) + { + child_allocation.height = child_height - child->padding * 2; + child_allocation.y = y + child->padding - child_height; + } + else + { + child_allocation.height = child->widget->requisition.height; + child_allocation.y = y + (child_height - child_allocation.height) / 2 - child_height; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + y -= (child_height + box->spacing); + } + } + } +} diff --git a/gtk/gtkvbox.h b/gtk/gtkvbox.h new file mode 100644 index 0000000000..aad32c914d --- /dev/null +++ b/gtk/gtkvbox.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VBOX_H__ +#define __GTK_VBOX_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbox.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VBOX(obj) GTK_CHECK_CAST (obj, gtk_vbox_get_type (), GtkVBox) +#define GTK_VBOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vbox_get_type (), GtkVBoxClass) +#define GTK_IS_VBOX(obj) GTK_CHECK_TYPE (obj, gtk_vbox_get_type ()) + + +typedef struct _GtkVBox GtkVBox; +typedef struct _GtkVBoxClass GtkVBoxClass; + +struct _GtkVBox +{ + GtkBox box; +}; + +struct _GtkVBoxClass +{ + GtkBoxClass parent_class; +}; + + +guint gtk_vbox_get_type (void); +GtkWidget* gtk_vbox_new (gint homogeneous, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VBOX_H__ */ diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c new file mode 100644 index 0000000000..dfa00c4b08 --- /dev/null +++ b/gtk/gtkviewport.c @@ -0,0 +1,616 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtksignal.h" +#include "gtkviewport.h" + + +static void gtk_viewport_class_init (GtkViewportClass *klass); +static void gtk_viewport_init (GtkViewport *viewport); +static void gtk_viewport_map (GtkWidget *widget); +static void gtk_viewport_unmap (GtkWidget *widget); +static void gtk_viewport_realize (GtkWidget *widget); +static void gtk_viewport_unrealize (GtkWidget *widget); +static void gtk_viewport_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_viewport_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_viewport_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_viewport_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_viewport_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_viewport_need_resize (GtkContainer *container); +static void gtk_viewport_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); + + +guint +gtk_viewport_get_type () +{ + static guint viewport_type = 0; + + if (!viewport_type) + { + GtkTypeInfo viewport_info = + { + "GtkViewport", + sizeof (GtkViewport), + sizeof (GtkViewportClass), + (GtkClassInitFunc) gtk_viewport_class_init, + (GtkObjectInitFunc) gtk_viewport_init, + (GtkArgFunc) NULL, + }; + + viewport_type = gtk_type_unique (gtk_bin_get_type (), &viewport_info); + } + + return viewport_type; +} + +static void +gtk_viewport_class_init (GtkViewportClass *class) +{ + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + widget_class->map = gtk_viewport_map; + widget_class->unmap = gtk_viewport_unmap; + widget_class->realize = gtk_viewport_realize; + widget_class->unrealize = gtk_viewport_unrealize; + widget_class->draw = gtk_viewport_draw; + widget_class->expose_event = gtk_viewport_expose; + widget_class->size_request = gtk_viewport_size_request; + widget_class->size_allocate = gtk_viewport_size_allocate; + + container_class->need_resize = gtk_viewport_need_resize; +} + +static void +gtk_viewport_init (GtkViewport *viewport) +{ + GTK_WIDGET_UNSET_FLAGS (viewport, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (viewport, GTK_BASIC); + + viewport->shadow_type = GTK_SHADOW_IN; + viewport->main_window = NULL; + viewport->view_window = NULL; + viewport->hadjustment = NULL; + viewport->vadjustment = NULL; +} + +GtkWidget* +gtk_viewport_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment) +{ + GtkViewport *viewport; + + viewport = gtk_type_new (gtk_viewport_get_type ()); + + if (!hadjustment) + hadjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + if (!vadjustment) + vadjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_viewport_set_hadjustment (viewport, hadjustment); + gtk_viewport_set_vadjustment (viewport, vadjustment); + + return GTK_WIDGET (viewport); +} + +GtkAdjustment* +gtk_viewport_get_hadjustment (GtkViewport *viewport) +{ + g_return_val_if_fail (viewport != NULL, NULL); + g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL); + + return viewport->hadjustment; +} + +GtkAdjustment* +gtk_viewport_get_vadjustment (GtkViewport *viewport) +{ + g_return_val_if_fail (viewport != NULL, NULL); + g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL); + + return viewport->vadjustment; +} + +void +gtk_viewport_set_hadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment) +{ + g_return_if_fail (viewport != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (viewport)); + g_return_if_fail (adjustment != NULL); + + if (viewport->hadjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), (gpointer) viewport); + gtk_object_unref (GTK_OBJECT (viewport->hadjustment)); + } + + viewport->hadjustment = adjustment; + gtk_object_ref (GTK_OBJECT (viewport->hadjustment)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_viewport_adjustment_changed, + (gpointer) viewport); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_viewport_adjustment_value_changed, + (gpointer) viewport); + + gtk_viewport_adjustment_changed (adjustment, (gpointer) viewport); +} + +void +gtk_viewport_set_vadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment) +{ + g_return_if_fail (viewport != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (viewport)); + g_return_if_fail (adjustment != NULL); + + if (viewport->vadjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), (gpointer) viewport); + gtk_object_unref (GTK_OBJECT (viewport->vadjustment)); + } + + viewport->vadjustment = adjustment; + gtk_object_ref (GTK_OBJECT (viewport->vadjustment)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_viewport_adjustment_changed, + (gpointer) viewport); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_viewport_adjustment_value_changed, + (gpointer) viewport); + + gtk_viewport_adjustment_changed (adjustment, (gpointer) viewport); +} + +void +gtk_viewport_set_shadow_type (GtkViewport *viewport, + GtkShadowType type) +{ + g_return_if_fail (viewport != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (viewport)); + + if ((GtkShadowType) viewport->shadow_type != type) + { + viewport->shadow_type = type; + + if (GTK_WIDGET_VISIBLE (viewport)) + { + gtk_widget_size_allocate (GTK_WIDGET (viewport), &(GTK_WIDGET (viewport)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (viewport)); + } + } +} + + +static void +gtk_viewport_map (GtkWidget *widget) +{ + GtkViewport *viewport; + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + gdk_window_show (viewport->main_window); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); +} + +static void +gtk_viewport_unmap (GtkWidget *widget) +{ + GtkViewport *viewport; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + viewport = GTK_VIEWPORT (widget); + + gdk_window_hide (viewport->main_window); +} + +static void +gtk_viewport_realize (GtkWidget *widget) +{ + GtkViewport *viewport; + GdkWindowAttr attributes; + GtkRequisition *child_requisition; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + viewport = GTK_VIEWPORT (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x + GTK_CONTAINER (widget)->border_width; + attributes.y = widget->allocation.y + GTK_CONTAINER (widget)->border_width; + attributes.width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2; + attributes.height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + viewport->main_window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (viewport->main_window, viewport); + + attributes.x += widget->style->klass->xthickness; + attributes.y += widget->style->klass->ythickness; + attributes.width -= widget->style->klass->xthickness * 2; + attributes.height -= widget->style->klass->ythickness * 2; + + viewport->view_window = gdk_window_new (viewport->main_window, &attributes, attributes_mask); + gdk_window_set_user_data (viewport->view_window, viewport); + + attributes.x = 0; + attributes.y = 0; + + if (GTK_BIN (viewport)->child) + { + child_requisition = >K_WIDGET (GTK_BIN (viewport)->child)->requisition; + attributes.width = child_requisition->width; + attributes.height = child_requisition->height; + } + + widget->window = gdk_window_new (viewport->view_window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, viewport); + + widget->style = gtk_style_attach (widget->style, viewport->main_window); + gtk_style_set_background (widget->style, viewport->main_window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + gdk_window_show (widget->window); + gdk_window_show (viewport->view_window); +} + +static void +gtk_viewport_unrealize (GtkWidget *widget) +{ + GtkViewport *viewport; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + viewport = GTK_VIEWPORT (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + + gdk_window_destroy (widget->window); + gdk_window_destroy (viewport->view_window); + gdk_window_destroy (viewport->main_window); + + widget->window = NULL; + viewport->view_window = NULL; + viewport->main_window = NULL; +} + +static void +gtk_viewport_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkViewport *viewport; + GtkStateType state; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + x = GTK_CONTAINER (viewport)->border_width; + y = GTK_CONTAINER (viewport)->border_width; + + gtk_draw_shadow (widget->style, viewport->main_window, + GTK_STATE_NORMAL, viewport->shadow_type, + 0, 0, -1, -1); + } +} + +static void +gtk_viewport_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkViewport *viewport; + GtkBin *bin; + GdkRectangle tmp_area; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + gtk_viewport_paint (widget, area); + + if (bin->child) + { + tmp_area = *area; + tmp_area.x += viewport->hadjustment->value; + tmp_area.y += viewport->vadjustment->value; + + if (gtk_widget_intersect (bin->child, &tmp_area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } + } +} + +static gint +gtk_viewport_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkViewport *viewport; + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VIEWPORT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + if (event->window == viewport->main_window) + gtk_viewport_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_viewport_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkViewport *viewport; + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (requisition != NULL); + + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness) * 2 + 5; + + requisition->height = (GTK_CONTAINER (widget)->border_width * 2 + + GTK_WIDGET (widget)->style->klass->ythickness) * 2 + 5; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + gtk_widget_size_request (bin->child, &bin->child->requisition); +} + +static void +gtk_viewport_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkViewport *viewport; + GtkBin *bin; + GtkAllocation child_allocation; + gint hval, vval; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + child_allocation.x = GTK_WIDGET (viewport)->style->klass->xthickness; + child_allocation.width = allocation->width - child_allocation.x * 2; + + child_allocation.y = GTK_WIDGET (viewport)->style->klass->ythickness; + child_allocation.height = allocation->height - child_allocation.y * 2; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (viewport->main_window, + allocation->x + GTK_CONTAINER (viewport)->border_width, + allocation->y + GTK_CONTAINER (viewport)->border_width, + allocation->width - GTK_CONTAINER (viewport)->border_width * 2, + allocation->height - GTK_CONTAINER (viewport)->border_width * 2); + + gdk_window_move_resize (viewport->view_window, + child_allocation.x, + child_allocation.y, + child_allocation.width, + child_allocation.height); + } + + viewport->hadjustment->page_size = child_allocation.width; + viewport->hadjustment->page_increment = viewport->hadjustment->page_size / 2; + viewport->hadjustment->step_increment = 10; + + viewport->vadjustment->page_size = child_allocation.height; + viewport->vadjustment->page_increment = viewport->vadjustment->page_size / 2; + viewport->vadjustment->step_increment = 10; + + hval = viewport->hadjustment->value; + vval = viewport->vadjustment->value; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + viewport->hadjustment->lower = 0; + viewport->hadjustment->upper = MAX (bin->child->requisition.width, + child_allocation.width); + + hval = CLAMP (hval, 0, + viewport->hadjustment->upper - + viewport->hadjustment->page_size); + + viewport->vadjustment->lower = 0; + viewport->vadjustment->upper = MAX (bin->child->requisition.height, + child_allocation.height); + + vval = CLAMP (vval, 0, + viewport->vadjustment->upper - + viewport->vadjustment->page_size); + } + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + child_allocation.x = 0; + child_allocation.y = 0; + + child_allocation.width = viewport->hadjustment->upper; + child_allocation.height = viewport->vadjustment->upper; + + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + gdk_window_resize (widget->window, + child_allocation.width, + child_allocation.height); + + child_allocation.x = 0; + child_allocation.y = 0; + gtk_widget_size_allocate (bin->child, &child_allocation); + } + + gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed"); + gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed"); + if (viewport->hadjustment->value != hval) + { + viewport->hadjustment->value = hval; + gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed"); + } + if (viewport->vadjustment->value != vval) + { + viewport->vadjustment->value = vval; + gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed"); + } +} + +static gint +gtk_viewport_need_resize (GtkContainer *container) +{ + GtkBin *bin; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VIEWPORT (container), FALSE); + + if (GTK_WIDGET_REALIZED (container)) + { + bin = GTK_BIN (container); + + gtk_widget_size_request (bin->child, &bin->child->requisition); + + gtk_widget_size_allocate (GTK_WIDGET (container), + &(GTK_WIDGET (container)->allocation)); + } + + return FALSE; +} + +static void +gtk_viewport_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkViewport *viewport; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (data)); + + viewport = GTK_VIEWPORT (data); +} + +static void +gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkViewport *viewport; + GtkBin *bin; + GtkAllocation child_allocation; + gint width, height; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (data)); + + viewport = GTK_VIEWPORT (data); + bin = GTK_BIN (data); + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gdk_window_get_size (viewport->view_window, &width, &height); + + child_allocation.x = 0; + child_allocation.y = 0; + + if (viewport->hadjustment->lower != (viewport->hadjustment->upper - + viewport->hadjustment->page_size)) + child_allocation.x = viewport->hadjustment->lower - viewport->hadjustment->value; + + if (viewport->vadjustment->lower != (viewport->vadjustment->upper - + viewport->vadjustment->page_size)) + child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value; + + if (GTK_WIDGET_REALIZED (viewport)) + gdk_window_move (GTK_WIDGET (viewport)->window, + child_allocation.x, + child_allocation.y); + } +} diff --git a/gtk/gtkviewport.h b/gtk/gtkviewport.h new file mode 100644 index 0000000000..9af4e8720a --- /dev/null +++ b/gtk/gtkviewport.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VIEWPORT_H__ +#define __GTK_VIEWPORT_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkadjustment.h> +#include <gtk/gtkbin.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VIEWPORT(obj) GTK_CHECK_CAST (obj, gtk_viewport_get_type (), GtkViewport) +#define GTK_VIEWPORT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_viewport_get_type (), GtkViewportClass) +#define GTK_IS_VIEWPORT(obj) GTK_CHECK_TYPE (obj, gtk_viewport_get_type ()) + + +typedef struct _GtkViewport GtkViewport; +typedef struct _GtkViewportClass GtkViewportClass; + +struct _GtkViewport +{ + GtkBin bin; + + gint shadow_type; + GdkWindow *main_window; + GdkWindow *view_window; + GtkAdjustment *hadjustment; + GtkAdjustment *vadjustment; +}; + +struct _GtkViewportClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_viewport_get_type (void); +GtkWidget* gtk_viewport_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +GtkAdjustment* gtk_viewport_get_hadjustment (GtkViewport *viewport); +GtkAdjustment* gtk_viewport_get_vadjustment (GtkViewport *viewport); +void gtk_viewport_set_hadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment); +void gtk_viewport_set_vadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment); +void gtk_viewport_set_shadow_type (GtkViewport *viewport, + GtkShadowType type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VIEWPORT_H__ */ diff --git a/gtk/gtkvpaned.c b/gtk/gtkvpaned.c new file mode 100644 index 0000000000..2dae03209e --- /dev/null +++ b/gtk/gtkvpaned.c @@ -0,0 +1,356 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkvpaned.h" +#include "gtkmain.h" +#include "gtksignal.h" + +static void gtk_vpaned_class_init (GtkVPanedClass *klass); +static void gtk_vpaned_init (GtkVPaned *vpaned); +static void gtk_vpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_vpaned_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_vpaned_xor_line (GtkPaned *paned); +static gint gtk_vpaned_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_vpaned_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_vpaned_motion (GtkWidget *widget, + GdkEventMotion *event); + +guint +gtk_vpaned_get_type () +{ + static guint vpaned_type = 0; + + if (!vpaned_type) + { + GtkTypeInfo vpaned_info = + { + "GtkVPaned", + sizeof (GtkVPaned), + sizeof (GtkVPanedClass), + (GtkClassInitFunc) gtk_vpaned_class_init, + (GtkObjectInitFunc) gtk_vpaned_init, + (GtkArgFunc) NULL, + }; + + vpaned_type = gtk_type_unique (gtk_paned_get_type (), &vpaned_info); + } + + return vpaned_type; +} + +static void +gtk_vpaned_class_init (GtkVPanedClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_vpaned_size_request; + widget_class->size_allocate = gtk_vpaned_size_allocate; + widget_class->draw = gtk_vpaned_draw; + widget_class->button_press_event = gtk_vpaned_button_press; + widget_class->button_release_event = gtk_vpaned_button_release; + widget_class->motion_notify_event = gtk_vpaned_motion; +} + +static void +gtk_vpaned_init (GtkVPaned *vpaned) +{ +} + +GtkWidget* +gtk_vpaned_new () +{ + GtkVPaned *vpaned; + + vpaned = gtk_type_new (gtk_vpaned_get_type ()); + + return GTK_WIDGET (vpaned); +} + +static void +gtk_vpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VPANED (widget)); + g_return_if_fail (requisition != NULL); + + paned = GTK_PANED (widget); + requisition->width = 0; + requisition->height = 0; + + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + { + gtk_widget_size_request (paned->child1, &paned->child1->requisition); + + requisition->height = paned->child1->requisition.height; + requisition->width = paned->child1->requisition.width; + } + + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + { + gtk_widget_size_request (paned->child2, &paned->child2->requisition); + + requisition->width = MAX (requisition->width, + paned->child2->requisition.width); + requisition->height += paned->child2->requisition.height; + } + + requisition->height += GTK_CONTAINER (paned)->border_width * 2 + paned->gutter_size; + requisition->width += GTK_CONTAINER (paned)->border_width * 2; +} + +static void +gtk_vpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkPaned *paned; + GtkAllocation child1_allocation; + GtkAllocation child2_allocation; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VPANED (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (!paned->position_set) + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + paned->child1_size = paned->child1->requisition.height; + else + paned->child1_size = 0; + } + + /* Move the handle first so we don't get extra expose events */ + + paned->handle_xpos = allocation->x + allocation->width - border_width - 2 * paned->handle_size; + paned->handle_ypos = allocation->y + paned->child1_size + border_width + paned->gutter_size / 2 - paned->handle_size / 2; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move (paned->handle, paned->handle_xpos, paned->handle_ypos); + gdk_window_raise (paned->handle); + } + + if (GTK_WIDGET_MAPPED (widget)) + { + gdk_window_clear_area (widget->window, + paned->groove_rectangle.x, + paned->groove_rectangle.y, + paned->groove_rectangle.width, + paned->groove_rectangle.height); + } + + child1_allocation.width = child2_allocation.width = allocation->width - border_width * 2; + child1_allocation.height = paned->child1_size; + child1_allocation.x = child2_allocation.x = allocation->x + border_width; + child1_allocation.y = allocation->y + border_width; + + paned->groove_rectangle.y = child1_allocation.y + + child1_allocation.height + paned->gutter_size / 2 - 1; + paned->groove_rectangle.x = allocation->x; + paned->groove_rectangle.height = 2; + paned->groove_rectangle.width = allocation->width; + + child2_allocation.y = paned->groove_rectangle.y + paned->gutter_size / 2 + 1; + child2_allocation.height = allocation->y + allocation->height + - child2_allocation.y - border_width; + + /* Now allocate the childen, making sure, when resizing not to + * overlap the windows */ + if (GTK_WIDGET_MAPPED(widget) && + paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) && + paned->child1->allocation.height < child1_allocation.height) + { + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + gtk_widget_size_allocate (paned->child1, &child1_allocation); + } + else + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + gtk_widget_size_allocate (paned->child1, &child1_allocation); + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + } +} + +static void +gtk_vpaned_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkPaned *paned; + GdkRectangle child_area; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (paned->child1 && + gtk_widget_intersect (paned->child1, area, &child_area)) + gtk_widget_draw (paned->child1, &child_area); + if (paned->child2 && + gtk_widget_intersect (paned->child2, area, &child_area)) + gtk_widget_draw (paned->child2, &child_area); + + gdk_draw_line (widget->window, + widget->style->dark_gc[widget->state], + widget->allocation.x, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2 - 1, + widget->allocation.x + widget->allocation.width - 1, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2 - 1); + gdk_draw_line (widget->window, + widget->style->light_gc[widget->state], + widget->allocation.x, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2, + widget->allocation.x + widget->allocation.width - 1, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2); + } +} + +static void +gtk_vpaned_xor_line (GtkPaned *paned) +{ + GtkWidget *widget; + GdkGCValues values; + guint16 ypos; + + widget = GTK_WIDGET(paned); + + if (!paned->xor_gc) + { + values.foreground = widget->style->white; + values.function = GDK_XOR; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + paned->xor_gc = gdk_gc_new_with_values (widget->window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_FUNCTION | + GDK_GC_SUBWINDOW); + } + + ypos = widget->allocation.y + paned->child1_size + + GTK_CONTAINER (paned)->border_width + paned->gutter_size / 2; + + gdk_draw_line (widget->window, paned->xor_gc, + widget->allocation.x, + ypos, + widget->allocation.x + widget->allocation.width - 1, + ypos); +} + +static gint +gtk_vpaned_button_press (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL,FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget),FALSE); + + paned = GTK_PANED (widget); + + if (!paned->in_drag && + (event->window == paned->handle) && (event->button == 1)) + { + paned->in_drag = TRUE; + /* We need a server grab here, not gtk_grab_add(), since + * we don't want to pass events on to the widget's children */ + gdk_pointer_grab (paned->handle, FALSE, + GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON1_MOTION_MASK + | GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time); + paned->child1_size += event->y - paned->handle_size / 2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.height - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_vpaned_xor_line (paned); + } + + return TRUE; +} + +static gint +gtk_vpaned_button_release (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + + paned = GTK_PANED (widget); + + if (paned->in_drag && (event->button == 1)) + { + gtk_vpaned_xor_line (paned); + paned->in_drag = FALSE; + paned->position_set = TRUE; + gdk_pointer_ungrab (event->time); + gtk_widget_queue_resize (GTK_WIDGET (paned)); + } + + return TRUE; +} + +static gint +gtk_vpaned_motion (GtkWidget *widget, GdkEventMotion *event) +{ + GtkPaned *paned; + gint y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + + if (event->is_hint || event->window != widget->window) + gtk_widget_get_pointer(widget, NULL, &y); + else + y = event->y; + + paned = GTK_PANED (widget); + + if (paned->in_drag) + { + gtk_vpaned_xor_line (paned); + paned->child1_size = y - GTK_CONTAINER (paned)->border_width - + paned->gutter_size/2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.height - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_vpaned_xor_line (paned); + } + + return TRUE; +} diff --git a/gtk/gtkvpaned.h b/gtk/gtkvpaned.h new file mode 100644 index 0000000000..9e66c1255a --- /dev/null +++ b/gtk/gtkvpaned.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VPANED_H__ +#define __GTK_VPANED_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkpaned.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VPANED(obj) GTK_CHECK_CAST (obj, gtk_vpaned_get_type (), GtkVPaned) +#define GTK_VPANED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vpaned_get_type (), GtkVPanedClass) +#define GTK_IS_VPANED(obj) GTK_CHECK_TYPE (obj, gtk_vpaned_get_type ()) + + +typedef struct _GtkVPaned GtkVPaned; +typedef struct _GtkVPanedClass GtkVPanedClass; + +struct _GtkVPaned +{ + GtkPaned paned; +}; + +struct _GtkVPanedClass +{ + GtkPanedClass parent_class; +}; + + +guint gtk_vpaned_get_type (void); +GtkWidget* gtk_vpaned_new (); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VPANED_H__ */ diff --git a/gtk/gtkvruler.c b/gtk/gtkvruler.c new file mode 100644 index 0000000000..43fe16bb7b --- /dev/null +++ b/gtk/gtkvruler.c @@ -0,0 +1,282 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <math.h> +#include <stdio.h> +#include <string.h> +#include "gtkvruler.h" + + +#define RULER_WIDTH 14 +#define MINIMUM_INCR 5 +#define MAXIMUM_SUBDIVIDE 5 +#define MAXIMUM_SCALES 10 + +#define ROUND(x) ((int) ((x) + 0.5)) + + +static void gtk_vruler_class_init (GtkVRulerClass *klass); +static void gtk_vruler_init (GtkVRuler *vruler); +static gint gtk_vruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_vruler_draw_ticks (GtkRuler *ruler); +static void gtk_vruler_draw_pos (GtkRuler *ruler); + + +guint +gtk_vruler_get_type () +{ + static guint vruler_type = 0; + + if (!vruler_type) + { + GtkTypeInfo vruler_info = + { + "GtkVRuler", + sizeof (GtkVRuler), + sizeof (GtkVRulerClass), + (GtkClassInitFunc) gtk_vruler_class_init, + (GtkObjectInitFunc) gtk_vruler_init, + (GtkArgFunc) NULL, + }; + + vruler_type = gtk_type_unique (gtk_ruler_get_type (), &vruler_info); + } + + return vruler_type; +} + +static void +gtk_vruler_class_init (GtkVRulerClass *klass) +{ + GtkWidgetClass *widget_class; + GtkRulerClass *ruler_class; + + widget_class = (GtkWidgetClass*) klass; + ruler_class = (GtkRulerClass*) klass; + + widget_class->motion_notify_event = gtk_vruler_motion_notify; + + ruler_class->draw_ticks = gtk_vruler_draw_ticks; + ruler_class->draw_pos = gtk_vruler_draw_pos; +} + +static void +gtk_vruler_init (GtkVRuler *vruler) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (vruler); + widget->requisition.width = widget->style->klass->xthickness * 2 + RULER_WIDTH; + widget->requisition.height = widget->style->klass->ythickness * 2 + 1; +} + +GtkWidget* +gtk_vruler_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_vruler_get_type ())); +} + + +static gint +gtk_vruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkRuler *ruler; + gint y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VRULER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + ruler = GTK_RULER (widget); + + if (event->is_hint) + gdk_window_get_pointer (widget->window, NULL, &y, NULL); + else + y = event->y; + + ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * y) / widget->allocation.height; + + /* Make sure the ruler has been allocated already */ + if (ruler->backing_store != NULL) + gtk_ruler_draw_pos (ruler); + + return FALSE; +} + +static void +gtk_vruler_draw_ticks (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + gint i, j; + gint width, height; + gint xthickness; + gint ythickness; + gint length; + gfloat subd_incr; + gfloat step_incr; + gfloat increment; + gfloat start, end, cur; + gchar unit_str[12]; + gchar digit_str[2] = { '\0', '\0' }; + gint text_height; + gint digit_height; + gint pos; + gint scale; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_VRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + digit_height = widget->style->font->ascent; + + width = widget->allocation.height; + height = widget->allocation.width - ythickness * 2; + gdk_draw_line (ruler->backing_store, gc, + height + xthickness, + ythickness, + height + xthickness, + widget->allocation.height - ythickness); + + if ((ruler->upper - ruler->lower) == 0) + return; + + increment = (gfloat) width * ruler->metric->pixels_per_unit / (ruler->upper - ruler->lower); + + /* determine the scale + * use the maximum extents of the ruler to determine the largest possible + * number to be displayed. calculate the height in pixels of this displayed + * text as for the vertical ruler case. use this height to find a scale + * which leaves sufficient room for drawing the ruler. + */ + scale = ceil (ruler->max_size / ruler->metric->pixels_per_unit); + sprintf (unit_str, "%d", scale); + text_height = strlen (unit_str) * digit_height + 1; + + for (scale = 0; scale < MAXIMUM_SCALES; scale++) + if (ruler->metric->ruler_scale[scale] * increment > 2 * text_height) + break; + + if (scale == MAXIMUM_SCALES) + scale = MAXIMUM_SCALES - 1; + + for (i = 0; i < MAXIMUM_SUBDIVIDE; i++) + { + subd_incr = (gfloat) ruler->metric->ruler_scale[scale] / (gfloat) ruler->metric->subdivide[i]; + step_incr = subd_incr * increment; + if (step_incr <= MINIMUM_INCR) + break; + + start = floor ((ruler->lower / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + end = ceil ((ruler->upper / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + + length = height / (i + 1) - 1; + + cur = start; + while (cur <= end) + { + pos = ROUND ((cur - (ruler->lower / ruler->metric->pixels_per_unit)) * increment); + + gdk_draw_line (ruler->backing_store, gc, + height + xthickness - length, + pos, + height + xthickness, + pos); + + if (i == 0) + { + sprintf (unit_str, "%d", (int) cur); + for (j = 0; j < (int) strlen (unit_str); j++) + { + digit_str[0] = unit_str[j]; + gdk_draw_string (ruler->backing_store, widget->style->font, gc, + xthickness + 1, + pos + digit_height * (j + 1) + 1, + digit_str); + } + } + + cur += subd_incr; + } + } + } +} + +static void +gtk_vruler_draw_pos (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + int i; + gint x, y; + gint width, height; + gint bs_width, bs_height; + gint xthickness; + gint ythickness; + gfloat increment; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_VRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + width = widget->allocation.width - xthickness * 2; + height = widget->allocation.height; + + bs_height = width / 2; + bs_height |= 1; /* make sure it's odd */ + bs_width = bs_height / 2 + 1; + + if ((bs_width > 0) && (bs_height > 0)) + { + /* If a backing store exists, restore the ruler */ + if (ruler->backing_store && ruler->non_gr_exp_gc) + gdk_draw_pixmap (ruler->widget.window, + ruler->non_gr_exp_gc, + ruler->backing_store, + ruler->xsrc, ruler->ysrc, + ruler->xsrc, ruler->ysrc, + bs_width, bs_height); + + increment = (gfloat) height / (ruler->upper - ruler->lower); + + x = (width + bs_width) / 2 + xthickness; + y = ROUND ((ruler->position - ruler->lower) * increment) + (ythickness - bs_height) / 2 - 1; + + for (i = 0; i < bs_width; i++) + gdk_draw_line (widget->window, gc, + x + i, y + i, + x + i, y + bs_height - 1 - i); + + ruler->xsrc = x; + ruler->ysrc = y; + } + } +} diff --git a/gtk/gtkvruler.h b/gtk/gtkvruler.h new file mode 100644 index 0000000000..22bef7164e --- /dev/null +++ b/gtk/gtkvruler.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VRULER_H__ +#define __GTK_VRULER_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkruler.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VRULER(obj) GTK_CHECK_CAST (obj, gtk_vruler_get_type (), GtkVRuler) +#define GTK_VRULER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vruler_get_type (), GtkVRulerClass) +#define GTK_IS_VRULER(obj) GTK_CHECK_TYPE (obj, gtk_vruler_get_type ()) + + +typedef struct _GtkVRuler GtkVRuler; +typedef struct _GtkVRulerClass GtkVRulerClass; + +struct _GtkVRuler +{ + GtkRuler ruler; +}; + +struct _GtkVRulerClass +{ + GtkRulerClass parent_class; +}; + + +guint gtk_vruler_get_type (void); +GtkWidget* gtk_vruler_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VRULER_H__ */ diff --git a/gtk/gtkvscale.c b/gtk/gtkvscale.c new file mode 100644 index 0000000000..9c2e3058fb --- /dev/null +++ b/gtk/gtkvscale.c @@ -0,0 +1,441 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include "gtkvscale.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define SCALE_CLASS(w) GTK_SCALE_CLASS (GTK_OBJECT (w)->klass) +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_vscale_class_init (GtkVScaleClass *klass); +static void gtk_vscale_init (GtkVScale *vscale); +static void gtk_vscale_realize (GtkWidget *widget); +static void gtk_vscale_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_vscale_pos_trough (GtkVScale *vscale, + gint *x, + gint *y, + gint *w, + gint *h); +static void gtk_vscale_draw_slider (GtkRange *range); +static void gtk_vscale_draw_value (GtkScale *scale); +static gint gtk_vscale_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + + +guint +gtk_vscale_get_type () +{ + static guint vscale_type = 0; + + if (!vscale_type) + { + GtkTypeInfo vscale_info = + { + "GtkVScale", + sizeof (GtkVScale), + sizeof (GtkVScaleClass), + (GtkClassInitFunc) gtk_vscale_class_init, + (GtkObjectInitFunc) gtk_vscale_init, + (GtkArgFunc) NULL, + }; + + vscale_type = gtk_type_unique (gtk_scale_get_type (), &vscale_info); + } + + return vscale_type; +} + +static void +gtk_vscale_class_init (GtkVScaleClass *class) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + GtkScaleClass *scale_class; + + widget_class = (GtkWidgetClass*) class; + range_class = (GtkRangeClass*) class; + scale_class = (GtkScaleClass*) class; + + widget_class->realize = gtk_vscale_realize; + widget_class->size_request = gtk_vscale_size_request; + widget_class->size_allocate = gtk_vscale_size_allocate; + + range_class->slider_update = gtk_range_default_vslider_update; + range_class->trough_click = gtk_range_default_vtrough_click; + range_class->motion = gtk_range_default_vmotion; + range_class->draw_slider = gtk_vscale_draw_slider; + range_class->trough_keys = gtk_vscale_trough_keys; + + scale_class->draw_value = gtk_vscale_draw_value; +} + +static void +gtk_vscale_init (GtkVScale *vscale) +{ +} + +GtkWidget* +gtk_vscale_new (GtkAdjustment *adjustment) +{ + GtkVScale *vscale; + + vscale = gtk_type_new (gtk_vscale_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (vscale), adjustment); + + return GTK_WIDGET (vscale); +} + + +static void +gtk_vscale_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + gint x, y, w, h; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCALE (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + + gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &w, &h); + attributes.x = x; + attributes.y = y; + attributes.width = w; + attributes.height = h; + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + range->trough = gdk_window_new (widget->window, &attributes, attributes_mask); + + attributes.width = RANGE_CLASS (range)->slider_width; + attributes.height = SCALE_CLASS (range)->slider_length; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (widget->window, widget); + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + + gtk_range_slider_update (GTK_RANGE (widget)); + + gdk_window_show (range->slider); + gdk_window_show (range->trough); +} + +static void +gtk_vscale_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkScale *scale; + gint value_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCALE (widget)); + g_return_if_fail (requisition != NULL); + + scale = GTK_SCALE (widget); + + requisition->width = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->ythickness * 2); + requisition->height = (SCALE_CLASS (scale)->slider_length + + widget->style->klass->xthickness) * 2; + + if (scale->draw_value) + { + value_width = gtk_scale_value_width (scale); + + if ((scale->value_pos == GTK_POS_LEFT) || + (scale->value_pos == GTK_POS_RIGHT)) + { + requisition->width += value_width + SCALE_CLASS (scale)->value_spacing; + if (requisition->height < (widget->style->font->ascent + widget->style->font->descent)) + requisition->height = widget->style->font->ascent + widget->style->font->descent; + } + else if ((scale->value_pos == GTK_POS_TOP) || + (scale->value_pos == GTK_POS_BOTTOM)) + { + if (requisition->width < value_width) + requisition->width = value_width; + requisition->height += widget->style->font->ascent + widget->style->font->descent; + } + } +} + +static void +gtk_vscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + GtkScale *scale; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCALE (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + scale = GTK_SCALE (widget); + + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &width, &height); + + gdk_window_move_resize (range->trough, x, y, width, height); + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_vscale_pos_trough (GtkVScale *vscale, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GtkWidget *widget; + GtkScale *scale; + + g_return_if_fail (vscale != NULL); + g_return_if_fail (GTK_IS_VSCALE (vscale)); + g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL)); + + widget = GTK_WIDGET (vscale); + scale = GTK_SCALE (vscale); + + *w = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->xthickness * 2); + *h = widget->allocation.height; + + if (scale->draw_value) + { + *x = 0; + *y = 0; + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + *x = (gtk_scale_value_width (scale) + + (widget->allocation.width - widget->requisition.width) / 2); + break; + case GTK_POS_RIGHT: + *x = (widget->allocation.width - widget->requisition.width) / 2; + break; + case GTK_POS_TOP: + *x = (widget->allocation.width - *w) / 2; + *y = widget->style->font->ascent + widget->style->font->descent; + *h -= *y; + break; + case GTK_POS_BOTTOM: + *x = (widget->allocation.width - *w) / 2; + *h -= widget->style->font->ascent + widget->style->font->descent; + break; + } + } + else + { + *x = (widget->allocation.width - *w) / 2; + *y = 0; + } + *y += 1; + *h -= 2; +} + +static void +gtk_vscale_draw_slider (GtkRange *range) +{ + GtkStateType state_type; + gint width, height; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCALE (range)); + + if (range->slider) + { + if ((range->in_child == RANGE_CLASS (range)->slider) || + (range->click_child == RANGE_CLASS (range)->slider)) + state_type = GTK_STATE_PRELIGHT; + else + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type); + gdk_window_clear (range->slider); + + gdk_window_get_size (range->slider, &width, &height); + gtk_draw_hline (GTK_WIDGET (range)->style, range->slider, + state_type, 1, width - 2, height / 2); + + gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider, + state_type, GTK_SHADOW_OUT, + 0, 0, -1, -1); + } +} + +static void +gtk_vscale_draw_value (GtkScale *scale) +{ + GtkStateType state_type; + gchar buffer[16]; + gint text_width; + gint width, height; + gint x, y; + + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_VSCALE (scale)); + + if (scale->draw_value) + { + gdk_window_get_size (GTK_WIDGET (scale)->window, &width, &height); + gdk_window_clear_area (GTK_WIDGET (scale)->window, 1, 1, width - 3, height - 3); + + sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value); + text_width = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height); + + x -= SCALE_CLASS (scale)->value_spacing + text_width; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_RIGHT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height); + + x += width + SCALE_CLASS (scale)->value_spacing; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_TOP: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y -= GTK_WIDGET (scale)->style->font->descent; + break; + case GTK_POS_BOTTOM: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y += height + GTK_WIDGET (scale)->style->font->ascent; + break; + } + + state_type = GTK_STATE_NORMAL; + if (!GTK_WIDGET_IS_SENSITIVE (scale)) + state_type = GTK_STATE_INSENSITIVE; + + gtk_draw_string (GTK_WIDGET (scale)->style, + GTK_WIDGET (scale)->window, + state_type, x, y, buffer); + } +} + +static gint +gtk_vscale_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Up: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Down: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Page_Up: + return_val = TRUE; + *scroll = GTK_SCROLL_PAGE_BACKWARD; + break; + case GDK_Page_Down: + return_val = TRUE; + *scroll = GTK_SCROLL_PAGE_FORWARD; + break; + case GDK_Home: + return_val = TRUE; + *pos = GTK_TROUGH_START; + break; + case GDK_End: + return_val = TRUE; + *pos = GTK_TROUGH_END; + break; + } + return return_val; +} diff --git a/gtk/gtkvscale.h b/gtk/gtkvscale.h new file mode 100644 index 0000000000..75862d389d --- /dev/null +++ b/gtk/gtkvscale.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VSCALE_H__ +#define __GTK_VSCALE_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkscale.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VSCALE(obj) GTK_CHECK_CAST (obj, gtk_vscale_get_type (), GtkVScale) +#define GTK_VSCALE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vscale_get_type (), GtkVScaleClass) +#define GTK_IS_VSCALE(obj) GTK_CHECK_TYPE (obj, gtk_vscale_get_type ()) + + +typedef struct _GtkVScale GtkVScale; +typedef struct _GtkVScaleClass GtkVScaleClass; + +struct _GtkVScale +{ + GtkScale scale; +}; + +struct _GtkVScaleClass +{ + GtkScaleClass parent_class; +}; + + +guint gtk_vscale_get_type (void); +GtkWidget* gtk_vscale_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VSCALE_H__ */ diff --git a/gtk/gtkvscrollbar.c b/gtk/gtkvscrollbar.c new file mode 100644 index 0000000000..87421c7bfb --- /dev/null +++ b/gtk/gtkvscrollbar.c @@ -0,0 +1,387 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkvscrollbar.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define EPSILON 0.01 + +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_vscrollbar_class_init (GtkVScrollbarClass *klass); +static void gtk_vscrollbar_init (GtkVScrollbar *vscrollbar); +static void gtk_vscrollbar_realize (GtkWidget *widget); +static void gtk_vscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_vscrollbar_draw_step_forw (GtkRange *range); +static void gtk_vscrollbar_draw_step_back (GtkRange *range); +static void gtk_vscrollbar_slider_update (GtkRange *range); +static void gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar); +static gint gtk_vscrollbar_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + +guint +gtk_vscrollbar_get_type () +{ + static guint vscrollbar_type = 0; + + if (!vscrollbar_type) + { + GtkTypeInfo vscrollbar_info = + { + "GtkVScrollbar", + sizeof (GtkVScrollbar), + sizeof (GtkVScrollbarClass), + (GtkClassInitFunc) gtk_vscrollbar_class_init, + (GtkObjectInitFunc) gtk_vscrollbar_init, + (GtkArgFunc) NULL, + }; + + vscrollbar_type = gtk_type_unique (gtk_scrollbar_get_type (), &vscrollbar_info); + } + + return vscrollbar_type; +} + +static void +gtk_vscrollbar_class_init (GtkVScrollbarClass *klass) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + + widget_class = (GtkWidgetClass*) klass; + range_class = (GtkRangeClass*) klass; + + widget_class->realize = gtk_vscrollbar_realize; + widget_class->size_allocate = gtk_vscrollbar_size_allocate; + + range_class->draw_step_forw = gtk_vscrollbar_draw_step_forw; + range_class->draw_step_back = gtk_vscrollbar_draw_step_back; + range_class->slider_update = gtk_vscrollbar_slider_update; + range_class->trough_click = gtk_range_default_vtrough_click; + range_class->trough_keys = gtk_vscrollbar_trough_keys; + range_class->motion = gtk_range_default_vmotion; +} + +static void +gtk_vscrollbar_init (GtkVScrollbar *vscrollbar) +{ + GtkWidget *widget; + GtkRequisition *requisition; + + widget = GTK_WIDGET (vscrollbar); + requisition = &widget->requisition; + + requisition->width = (RANGE_CLASS (widget)->slider_width + + widget->style->klass->xthickness * 2); + requisition->height = (RANGE_CLASS (widget)->min_slider_size + + RANGE_CLASS (widget)->stepper_size + + RANGE_CLASS (widget)->stepper_slider_spacing + + widget->style->klass->ythickness) * 2; +} + +GtkWidget* +gtk_vscrollbar_new (GtkAdjustment *adjustment) +{ + GtkVScrollbar *vscrollbar; + + vscrollbar = gtk_type_new (gtk_vscrollbar_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (vscrollbar), adjustment); + + return GTK_WIDGET (vscrollbar); +} + + +static void +gtk_vscrollbar_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x + (widget->allocation.width - widget->requisition.width) / 2; + attributes.y = widget->allocation.y; + attributes.width = widget->requisition.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + range->trough = widget->window; + + attributes.x = widget->style->klass->xthickness; + attributes.y = widget->style->klass->ythickness; + attributes.width = RANGE_CLASS (widget)->stepper_size; + attributes.height = RANGE_CLASS (widget)->stepper_size; + + range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.y = (widget->allocation.height - + widget->style->klass->ythickness - + RANGE_CLASS (widget)->stepper_size); + + range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.x = widget->style->klass->ythickness; + attributes.y = 0; + attributes.width = RANGE_CLASS (widget)->slider_width; + attributes.height = RANGE_CLASS (widget)->min_slider_size; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (widget)); + gtk_range_slider_update (GTK_RANGE (widget)); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + gdk_window_set_user_data (range->step_forw, widget); + gdk_window_set_user_data (range->step_back, widget); + + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE); + + gdk_window_show (range->slider); + gdk_window_show (range->step_forw); + gdk_window_show (range->step_back); +} + +static void +gtk_vscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + + gdk_window_move_resize (range->trough, + allocation->x + (allocation->width - widget->requisition.width) / 2, + allocation->y, + widget->requisition.width, allocation->height); + gdk_window_move_resize (range->step_back, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + widget->requisition.width - widget->style->klass->xthickness * 2, + RANGE_CLASS (widget)->stepper_size); + gdk_window_move_resize (range->step_forw, + widget->style->klass->xthickness, + allocation->height - widget->style->klass->ythickness - + RANGE_CLASS (widget)->stepper_size, + widget->requisition.width - widget->style->klass->xthickness * 2, + RANGE_CLASS (widget)->stepper_size); + gdk_window_resize (range->slider, + widget->requisition.width - widget->style->klass->xthickness * 2, + RANGE_CLASS (range)->min_slider_size); + + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_vscrollbar_draw_step_forw (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_forw) + { + if (range->click_child == RANGE_CLASS (range)->step_forw) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_forw) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_forw, + state_type, shadow_type, GTK_ARROW_DOWN, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_vscrollbar_draw_step_back (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_back) + { + if (range->click_child == RANGE_CLASS (range)->step_back) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_back) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_back, + state_type, shadow_type, GTK_ARROW_UP, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_vscrollbar_slider_update (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (range)); + + gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (range)); + gtk_range_default_vslider_update (range); +} + +static void +gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar) +{ + GtkRange *range; + gint step_back_y; + gint step_back_height; + gint step_forw_y; + gint slider_width; + gint slider_height; + gint top, bottom; + gint height; + + g_return_if_fail (vscrollbar != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (vscrollbar)); + + if (GTK_WIDGET_REALIZED (vscrollbar)) + { + range = GTK_RANGE (vscrollbar); + + gdk_window_get_size (range->step_back, NULL, &step_back_height); + gdk_window_get_position (range->step_back, NULL, &step_back_y); + gdk_window_get_position (range->step_forw, NULL, &step_forw_y); + + top = (step_back_y + + step_back_height + + RANGE_CLASS (vscrollbar)->stepper_slider_spacing); + bottom = step_forw_y - RANGE_CLASS (vscrollbar)->stepper_slider_spacing; + height = bottom - top; + + if ((range->adjustment->page_size > 0) && + (range->adjustment->lower != range->adjustment->upper)) + { + if (range->adjustment->page_size > + (range->adjustment->upper - range->adjustment->lower)) + range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower; + + height = (height * range->adjustment->page_size / + (range->adjustment->upper - range->adjustment->lower)); + + if (height < RANGE_CLASS (vscrollbar)->min_slider_size) + height = RANGE_CLASS (vscrollbar)->min_slider_size; + } + + gdk_window_get_size (range->slider, &slider_width, &slider_height); + + if (slider_height != height) + gdk_window_resize (range->slider, slider_width, height); + } +} + +static gint +gtk_vscrollbar_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Up: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Down: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Page_Up: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *pos = GTK_TROUGH_START; + else + *scroll = GTK_SCROLL_PAGE_BACKWARD; + break; + case GDK_Page_Down: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *pos = GTK_TROUGH_END; + else + *scroll = GTK_SCROLL_PAGE_FORWARD; + break; + } + return return_val; +} diff --git a/gtk/gtkvscrollbar.h b/gtk/gtkvscrollbar.h new file mode 100644 index 0000000000..3160fc0758 --- /dev/null +++ b/gtk/gtkvscrollbar.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VSCROLLBAR_H__ +#define __GTK_VSCROLLBAR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkscrollbar.h> + + +#define GTK_VSCROLLBAR(obj) GTK_CHECK_CAST (obj, gtk_vscrollbar_get_type (), GtkVScrollbar) +#define GTK_VSCROLLBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vscrollbar_get_type (), GtkVScrollbarClass) +#define GTK_IS_VSCROLLBAR(obj) GTK_CHECK_TYPE (obj, gtk_vscrollbar_get_type ()) + + +typedef struct _GtkVScrollbar GtkVScrollbar; +typedef struct _GtkVScrollbarClass GtkVScrollbarClass; + +struct _GtkVScrollbar +{ + GtkScrollbar scrollbar; +}; + +struct _GtkVScrollbarClass +{ + GtkScrollbarClass parent_class; +}; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +guint gtk_vscrollbar_get_type (void); +GtkWidget* gtk_vscrollbar_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VSCROLLBAR_H__ */ diff --git a/gtk/gtkvseparator.c b/gtk/gtkvseparator.c new file mode 100644 index 0000000000..fbbba19ffe --- /dev/null +++ b/gtk/gtkvseparator.c @@ -0,0 +1,90 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkvseparator.h" + + +static void gtk_vseparator_class_init (GtkVSeparatorClass *klass); +static void gtk_vseparator_init (GtkVSeparator *vseparator); +static gint gtk_vseparator_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_vseparator_get_type () +{ + static guint vseparator_type = 0; + + if (!vseparator_type) + { + GtkTypeInfo vseparator_info = + { + "GtkVSeparator", + sizeof (GtkVSeparator), + sizeof (GtkVSeparatorClass), + (GtkClassInitFunc) gtk_vseparator_class_init, + (GtkObjectInitFunc) gtk_vseparator_init, + (GtkArgFunc) NULL, + }; + + vseparator_type = gtk_type_unique (gtk_separator_get_type (), &vseparator_info); + } + + return vseparator_type; +} + +static void +gtk_vseparator_class_init (GtkVSeparatorClass *klass) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) klass; + + widget_class->expose_event = gtk_vseparator_expose; +} + +static void +gtk_vseparator_init (GtkVSeparator *vseparator) +{ + GTK_WIDGET (vseparator)->requisition.width = GTK_WIDGET (vseparator)->style->klass->xthickness; + GTK_WIDGET (vseparator)->requisition.height = 1; +} + +GtkWidget* +gtk_vseparator_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_vseparator_get_type ())); +} + + +static gint +gtk_vseparator_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VSEPARATOR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_draw_vline (widget->style, widget->window, GTK_STATE_NORMAL, + widget->allocation.y, + widget->allocation.y + widget->allocation.height, + widget->allocation.x + (widget->allocation.width - + widget->style->klass->xthickness) / 2); + + return FALSE; +} diff --git a/gtk/gtkvseparator.h b/gtk/gtkvseparator.h new file mode 100644 index 0000000000..74d07dd687 --- /dev/null +++ b/gtk/gtkvseparator.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_VSEPARATOR_H__ +#define __GTK_VSEPARATOR_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkseparator.h> + + +#define GTK_VSEPARATOR(obj) GTK_CHECK_CAST (obj, gtk_vseparator_get_type (), GtkVSeparator) +#define GTK_VSEPARATOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vseparator_get_type (), GtkVSeparatorClass) +#define GTK_IS_VSEPARATOR(obj) GTK_CHECK_TYPE (obj, gtk_vseparator_get_type ()) + + +typedef struct _GtkVSeparator GtkVSeparator; +typedef struct _GtkVSeparatorClass GtkVSeparatorClass; + +struct _GtkVSeparator +{ + GtkSeparator separator; +}; + +struct _GtkVSeparatorClass +{ + GtkSeparatorClass parent_class; +}; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +guint gtk_vseparator_get_type (void); +GtkWidget* gtk_vseparator_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SEPARATOR_H__ */ diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c new file mode 100644 index 0000000000..26e0c9bbc2 --- /dev/null +++ b/gtk/gtkwidget.c @@ -0,0 +1,3390 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdarg.h> +#include <string.h> +#include "gtkcontainer.h" +#include "gtkmain.h" +#include "gtkrc.h" +#include "gtkselection.h" +#include "gtksignal.h" +#include "gtkwidget.h" +#include "gtkwindow.h" +#include "gdk/gdk.h" +#include "gdk/gdkx.h" + + +#define WIDGET_CLASS(w) GTK_WIDGET_CLASS (GTK_OBJECT (w)->klass) + + +enum { + SHOW, + HIDE, + MAP, + UNMAP, + REALIZE, + UNREALIZE, + DRAW, + DRAW_FOCUS, + DRAW_DEFAULT, + SIZE_REQUEST, + SIZE_ALLOCATE, + STATE_CHANGED, + INSTALL_ACCELERATOR, + REMOVE_ACCELERATOR, + EVENT, + BUTTON_PRESS_EVENT, + BUTTON_RELEASE_EVENT, + MOTION_NOTIFY_EVENT, + DELETE_EVENT, + DESTROY_EVENT, + EXPOSE_EVENT, + KEY_PRESS_EVENT, + KEY_RELEASE_EVENT, + ENTER_NOTIFY_EVENT, + LEAVE_NOTIFY_EVENT, + CONFIGURE_EVENT, + FOCUS_IN_EVENT, + FOCUS_OUT_EVENT, + MAP_EVENT, + UNMAP_EVENT, + PROPERTY_NOTIFY_EVENT, + SELECTION_CLEAR_EVENT, + SELECTION_REQUEST_EVENT, + SELECTION_NOTIFY_EVENT, + SELECTION_RECEIVED, + PROXIMITY_IN_EVENT, + PROXIMITY_OUT_EVENT, + DRAG_BEGIN_EVENT, + DRAG_REQUEST_EVENT, + DROP_ENTER_EVENT, + DROP_LEAVE_EVENT, + DROP_DATA_AVAILABLE_EVENT, + OTHER_EVENT, + LAST_SIGNAL +}; + + +typedef void (*GtkWidgetSignal1) (GtkObject *object, + gpointer arg1, + gpointer data); +typedef gint (*GtkWidgetSignal2) (GtkObject *object, + gpointer arg1, + gchar arg2, + gchar arg3, + gpointer data); +typedef void (*GtkWidgetSignal3) (GtkObject *object, + gpointer arg1, + gpointer data); +typedef gint (*GtkWidgetSignal4) (GtkObject *object, + gpointer arg1, + gpointer data); + + +static void gtk_widget_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_widget_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_widget_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_widget_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + +static void gtk_widget_class_init (GtkWidgetClass *klass); +static void gtk_widget_init (GtkWidget *widget); +static void gtk_widget_arg (GtkWidget *widget, + GtkArg *arg); +static void gtk_real_widget_destroy (GtkObject *object); +static void gtk_real_widget_show (GtkWidget *widget); +static void gtk_real_widget_hide (GtkWidget *widget); +static void gtk_real_widget_map (GtkWidget *widget); +static void gtk_real_widget_unmap (GtkWidget *widget); +static void gtk_real_widget_realize (GtkWidget *widget); +static void gtk_real_widget_unrealize (GtkWidget *widget); +static void gtk_real_widget_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_real_widget_queue_draw (GtkWidget *widget); +static gint gtk_real_widget_queue_resize (GtkWidget *widget); +static void gtk_real_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static GdkColormap* gtk_widget_peek_colormap (void); +static GdkVisual* gtk_widget_peek_visual (void); +static GtkStyle* gtk_widget_peek_style (void); + +static void gtk_widget_set_parent_sensitive (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_propagate_restore (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_propagate_state (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_draw_children_recurse (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_set_style_internal (GtkWidget *widget, + GtkStyle *style); +static void gtk_widget_set_style_recurse (GtkWidget *widget, + gpointer client_data); + +extern GtkArg* gtk_object_collect_args (gint *nargs, + va_list args1, + va_list args2); + +static GtkWidgetAuxInfo* gtk_widget_aux_info_new (void); +static void gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info); + +static GtkObjectClass *parent_class = NULL; +static gint widget_signals[LAST_SIGNAL] = { 0 }; + +static GMemChunk *aux_info_mem_chunk = NULL; + +static GdkColormap *default_colormap = NULL; +static GdkVisual *default_visual = NULL; +static GtkStyle *default_style = NULL; + +static GSList *colormap_stack = NULL; +static GSList *visual_stack = NULL; +static GSList *style_stack = NULL; + +static const char *aux_info_key = "aux_info"; +static const char *colormap_key = "colormap"; +static const char *visual_key = "visual"; +static const char *event_key = "event_mask"; +static const char *resize_widgets_key = "resize_widgets"; +static const char *extension_event_key = "extension_event_mode"; +static const char *redraw_handler_key = "redraw_handler_tag"; +static const char *resize_handler_key = "resize_handler_tag"; +static const char *shape_info_key = "shape_info"; + + + +/***************************************** + * gtk_widget_get_type: + * + * arguments: + * + * results: + *****************************************/ + +guint +gtk_widget_get_type () +{ + static guint widget_type = 0; + + if (!widget_type) + { + GtkTypeInfo widget_info = + { + "GtkWidget", + sizeof (GtkWidget), + sizeof (GtkWidgetClass), + (GtkClassInitFunc) gtk_widget_class_init, + (GtkObjectInitFunc) gtk_widget_init, + (GtkArgFunc) gtk_widget_arg, + }; + + widget_type = gtk_type_unique (gtk_object_get_type (), &widget_info); + } + + return widget_type; +} + +/***************************************** + * gtk_widget_class_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_class_init (GtkWidgetClass *klass) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) klass; + + parent_class = gtk_type_class (gtk_object_get_type ()); + + gtk_object_add_arg_type ("GtkWidget::x", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::y", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::width", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::height", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::visible", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWidget::sensitive", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWidget::events", GTK_TYPE_GDK_EVENT_MASK); + gtk_object_add_arg_type ("GtkWidget::extension_events", GTK_TYPE_GDK_EVENT_MASK); + gtk_object_add_arg_type ("GtkWidget::name", GTK_TYPE_STRING); + gtk_object_add_arg_type ("GtkWidget::style", GTK_TYPE_STYLE); + gtk_object_add_arg_type ("GtkWidget::parent", GTK_TYPE_CONTAINER); + + widget_signals[SHOW] = + gtk_signal_new ("show", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, show), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[HIDE] = + gtk_signal_new ("hide", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, hide), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[MAP] = + gtk_signal_new ("map", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, map), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[UNMAP] = + gtk_signal_new ("unmap", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, unmap), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[REALIZE] = + gtk_signal_new ("realize", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, realize), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[UNREALIZE] = + gtk_signal_new ("unrealize", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, unrealize), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[DRAW] = + gtk_signal_new ("draw", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, draw), + gtk_widget_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_POINTER); + widget_signals[DRAW_FOCUS] = + gtk_signal_new ("draw_focus", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, draw_focus), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[DRAW_DEFAULT] = + gtk_signal_new ("draw_default", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, draw_default), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[SIZE_REQUEST] = + gtk_signal_new ("size_request", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, size_request), + gtk_widget_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_POINTER); + widget_signals[SIZE_ALLOCATE] = + gtk_signal_new ("size_allocate", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, size_allocate), + gtk_widget_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_POINTER); + widget_signals[STATE_CHANGED] = + gtk_signal_new ("state_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, state_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[INSTALL_ACCELERATOR] = + gtk_signal_new ("install_accelerator", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, install_accelerator), + gtk_widget_marshal_signal_2, + GTK_TYPE_BOOL, 3, + GTK_TYPE_STRING, + GTK_TYPE_CHAR, + GTK_TYPE_INT); + widget_signals[REMOVE_ACCELERATOR] = + gtk_signal_new ("remove_accelerator", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, remove_accelerator), + gtk_widget_marshal_signal_3, + GTK_TYPE_NONE, 1, + GTK_TYPE_STRING); + widget_signals[EVENT] = + gtk_signal_new ("event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[BUTTON_PRESS_EVENT] = + gtk_signal_new ("button_press_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, button_press_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[BUTTON_RELEASE_EVENT] = + gtk_signal_new ("button_release_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, button_release_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[MOTION_NOTIFY_EVENT] = + gtk_signal_new ("motion_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, motion_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DELETE_EVENT] = + gtk_signal_new ("delete_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, delete_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DESTROY_EVENT] = + gtk_signal_new ("destroy_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, destroy_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[EXPOSE_EVENT] = + gtk_signal_new ("expose_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, expose_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[KEY_PRESS_EVENT] = + gtk_signal_new ("key_press_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, key_press_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[KEY_RELEASE_EVENT] = + gtk_signal_new ("key_release_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, key_release_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[ENTER_NOTIFY_EVENT] = + gtk_signal_new ("enter_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, enter_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[LEAVE_NOTIFY_EVENT] = + gtk_signal_new ("leave_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, leave_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[CONFIGURE_EVENT] = + gtk_signal_new ("configure_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, configure_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[FOCUS_IN_EVENT] = + gtk_signal_new ("focus_in_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, focus_in_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[FOCUS_OUT_EVENT] = + gtk_signal_new ("focus_out_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, focus_out_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[MAP_EVENT] = + gtk_signal_new ("map_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, map_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[UNMAP_EVENT] = + gtk_signal_new ("unmap_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, unmap_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[PROPERTY_NOTIFY_EVENT] = + gtk_signal_new ("property_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, property_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_CLEAR_EVENT] = + gtk_signal_new ("selection_clear_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_clear_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_REQUEST_EVENT] = + gtk_signal_new ("selection_request_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_request_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_NOTIFY_EVENT] = + gtk_signal_new ("selection_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_RECEIVED] = + gtk_signal_new ("selection_received", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_received), + gtk_widget_marshal_signal_1, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[PROXIMITY_IN_EVENT] = + gtk_signal_new ("proximity_in_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, proximity_in_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[PROXIMITY_OUT_EVENT] = + gtk_signal_new ("proximity_out_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, proximity_out_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DRAG_BEGIN_EVENT] = + gtk_signal_new ("drag_begin_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drag_begin_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DRAG_REQUEST_EVENT] = + gtk_signal_new ("drag_request_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drag_request_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DROP_ENTER_EVENT] = + gtk_signal_new ("drop_enter_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drop_enter_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DROP_LEAVE_EVENT] = + gtk_signal_new ("drop_leave_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drop_leave_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DROP_DATA_AVAILABLE_EVENT] = + gtk_signal_new ("drop_data_available_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, + drop_data_available_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[OTHER_EVENT] = + gtk_signal_new ("other_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, other_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + + gtk_object_class_add_signals (object_class, widget_signals, LAST_SIGNAL); + + object_class->destroy = gtk_real_widget_destroy; + + klass->activate_signal = 0; + klass->show = gtk_real_widget_show; + klass->hide = gtk_real_widget_hide; + klass->map = gtk_real_widget_map; + klass->unmap = gtk_real_widget_unmap; + klass->realize = gtk_real_widget_realize; + klass->unrealize = gtk_real_widget_unrealize; + klass->draw = gtk_real_widget_draw; + klass->draw_focus = NULL; + klass->size_request = NULL; + klass->size_allocate = gtk_real_widget_size_allocate; + klass->state_changed = NULL; + klass->install_accelerator = NULL; + klass->remove_accelerator = NULL; + klass->event = NULL; + klass->button_press_event = NULL; + klass->button_release_event = NULL; + klass->motion_notify_event = NULL; + klass->delete_event = NULL; + klass->destroy_event = NULL; + klass->expose_event = NULL; + klass->key_press_event = NULL; + klass->key_release_event = NULL; + klass->enter_notify_event = NULL; + klass->leave_notify_event = NULL; + klass->configure_event = NULL; + klass->focus_in_event = NULL; + klass->focus_out_event = NULL; + klass->map_event = NULL; + klass->unmap_event = NULL; + klass->property_notify_event = gtk_selection_property_notify; + klass->selection_clear_event = gtk_selection_clear; + klass->selection_request_event = gtk_selection_request; + klass->selection_notify_event = gtk_selection_notify; + klass->selection_received = NULL; + klass->proximity_in_event = NULL; + klass->proximity_out_event = NULL; + klass->drag_begin_event = NULL; + klass->drag_request_event = NULL; + klass->drop_enter_event = NULL; + klass->drop_leave_event = NULL; + klass->drop_data_available_event = NULL; + klass->other_event = NULL; +} + +/***************************************** + * gtk_widget_arg: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_arg (GtkWidget *widget, + GtkArg *arg) +{ + if (strcmp (arg->name, "x") == 0) + { + gtk_widget_set_uposition (widget, GTK_VALUE_INT(*arg), -2); + } + else if (strcmp (arg->name, "y") == 0) + { + gtk_widget_set_uposition (widget, -2, GTK_VALUE_INT(*arg)); + } + else if (strcmp (arg->name, "width") == 0) + { + gtk_widget_set_usize (widget, GTK_VALUE_INT(*arg), -1); + } + else if (strcmp (arg->name, "height") == 0) + { + gtk_widget_set_usize (widget, -1, GTK_VALUE_INT(*arg)); + } + else if (strcmp (arg->name, "visible") == 0) + { + if (GTK_VALUE_BOOL(*arg)) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); + } + else if (strcmp (arg->name, "sensitive") == 0) + { + gtk_widget_set_sensitive (widget, GTK_VALUE_BOOL(*arg)); + } + else if (strcmp (arg->name, "events") == 0) + { + gtk_widget_set_events (widget, GTK_VALUE_FLAGS(*arg)); + } + else if (strcmp (arg->name, "extension_events") == 0) + { + gtk_widget_set_extension_events (widget, GTK_VALUE_FLAGS(*arg)); + } + else if (strcmp (arg->name, "name") == 0) + { + gtk_widget_set_name (widget, GTK_VALUE_STRING(*arg)); + } + else if (strcmp (arg->name, "style") == 0) + { + gtk_widget_set_style (widget, (GtkStyle*)GTK_VALUE_BOXED(*arg)); + } + else if (strcmp (arg->name, "parent") == 0) + { + gtk_container_add (GTK_CONTAINER (GTK_VALUE_OBJECT(*arg)), widget); + } +} + +/***************************************** + * gtk_widget_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_init (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkVisual *visual; + + GTK_OBJECT_FLAGS (widget) = GTK_SENSITIVE | GTK_PARENT_SENSITIVE; + widget->state = GTK_STATE_NORMAL; + widget->saved_state = GTK_STATE_NORMAL; + widget->name = NULL; + widget->requisition.width = 0; + widget->requisition.height = 0; + widget->allocation.x = -1; + widget->allocation.y = -1; + widget->allocation.width = 1; + widget->allocation.height = 1; + widget->window = NULL; + widget->parent = NULL; + + widget->style = gtk_widget_peek_style (); + gtk_style_ref (widget->style); + + colormap = gtk_widget_peek_colormap (); + visual = gtk_widget_peek_visual (); + + if (colormap != gtk_widget_get_default_colormap ()) + gtk_object_set_data (GTK_OBJECT (widget), colormap_key, colormap); + + if (visual != gtk_widget_get_default_visual ()) + gtk_object_set_data (GTK_OBJECT (widget), visual_key, visual); +} + +/***************************************** + * gtk_widget_new: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_new (guint type, + ...) +{ + GtkObject *obj; + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + g_return_val_if_fail (gtk_type_is_a (type, gtk_widget_get_type ()), NULL); + + obj = gtk_type_new (type); + + va_start (args1, type); + va_start (args2, type); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (obj, nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); + + return GTK_WIDGET (obj); +} + +/***************************************** + * gtk_widget_newv: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_newv (guint type, + gint nargs, + GtkArg *args) +{ + g_return_val_if_fail (gtk_type_is_a (type, gtk_widget_get_type ()), NULL); + + return GTK_WIDGET (gtk_object_newv (type, nargs, args)); +} + +/***************************************** + * gtk_widget_set: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set (GtkWidget *widget, + ...) +{ + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + g_return_if_fail (widget != NULL); + + va_start (args1, widget); + va_start (args2, widget); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (GTK_OBJECT (widget), nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); +} + +/***************************************** + * gtk_widget_setv: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_setv (GtkWidget *widget, + gint nargs, + GtkArg *args) +{ + gtk_object_setv (GTK_OBJECT (widget), nargs, args); +} + +/***************************************** + * gtk_widget_destroy: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_destroy (GtkWidget *widget) +{ + GSList *resize_widgets; + GSList *tmp_list; + gint tag; + + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_REDRAW_PENDING (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REDRAW_PENDING); + gtk_object_unref (GTK_OBJECT (widget)); + tag = (gint) gtk_object_get_data (GTK_OBJECT (widget), redraw_handler_key); + gtk_idle_remove (tag); + gtk_object_set_data (GTK_OBJECT (widget), redraw_handler_key, (gpointer) 0); + } + + if (GTK_WIDGET_ANCHORED (widget) && + GTK_WIDGET_RESIZE_PENDING (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_PENDING); + gtk_object_unref (GTK_OBJECT (widget)); + tag = (gint) gtk_object_get_data (GTK_OBJECT (widget), resize_handler_key); + gtk_idle_remove (tag); + gtk_object_set_data (GTK_OBJECT (widget), resize_handler_key, (gpointer) 0); + + resize_widgets = gtk_object_get_data (GTK_OBJECT (widget), resize_widgets_key); + + tmp_list = resize_widgets; + while (tmp_list) + { + GtkWidget *child; + + child = tmp_list->data; + tmp_list = tmp_list->next; + + /* referencing needed? */ + GTK_WIDGET_UNSET_FLAGS (child, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (child)); + } + + if (resize_widgets) + { + gtk_object_set_data (GTK_OBJECT (widget), resize_widgets_key, NULL); + g_slist_free (resize_widgets); + } + } + + if (GTK_WIDGET_RESIZE_NEEDED (widget)) + { + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (widget); + resize_widgets = gtk_object_get_data (GTK_OBJECT (toplevel), resize_widgets_key); + + if (resize_widgets) + { + resize_widgets = g_slist_remove (resize_widgets, widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (widget)); + + gtk_object_set_data (GTK_OBJECT (toplevel), resize_widgets_key, resize_widgets); + } + } + + + if (widget->parent) + { + if (!GTK_OBJECT_BEING_DESTROYED (widget->parent)) + gtk_container_remove (GTK_CONTAINER (widget->parent), widget); + else + gtk_object_unref (GTK_OBJECT (widget)); + } + gtk_object_destroy (GTK_OBJECT (widget)); +} + +/***************************************** + * gtk_widget_unparent: do any cleanup necessary necessary before + * setting parent = NULL. In particular, remove + * the focus properly. + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_unparent (GtkWidget *widget) +{ + GtkWidget *toplevel; + GtkWidget *child; + + g_return_if_fail (widget != NULL); + + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_IS_WINDOW (toplevel)) + { + child = GTK_WINDOW (toplevel)->focus_widget; + + while (child && child != widget) + child = child->parent; + + if (child == widget) + gtk_window_set_focus (GTK_WINDOW (toplevel), NULL); + } + + if (widget->window && + GTK_WIDGET_NO_WINDOW (widget) && + GTK_WIDGET_DRAWABLE (widget)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->parent = NULL; + + gtk_object_unref (GTK_OBJECT (widget)); +} + +/***************************************** + * gtk_widget_show: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_VISIBLE (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[SHOW]); +} + +/***************************************** + * gtk_widget_hide: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_hide (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_VISIBLE (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[HIDE]); +} + +/***************************************** + * gtk_widget_map: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_map (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_MAPPED (widget)) + { + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[MAP]); + } +} + +/***************************************** + * gtk_widget_unmap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_MAPPED (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[UNMAP]); +} + +/***************************************** + * gtk_widget_realize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_realize (GtkWidget *widget) +{ + GtkStyle *new_style; + gint events; + GdkExtensionMode mode; + GtkWidgetShapeInfo *shape_info; + + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_REALIZED (widget)) + { + /* + if (GTK_IS_CONTAINER (widget) && !GTK_WIDGET_NO_WINDOW (widget)) + g_print ("%s\n", gtk_type_name (GTK_WIDGET_TYPE (widget))); + */ + + if (widget->parent && !GTK_WIDGET_REALIZED (widget->parent)) + gtk_widget_realize (widget->parent); + + if (!GTK_WIDGET_USER_STYLE (widget)) + { + new_style = gtk_rc_get_style (widget); + if (new_style != widget->style) + gtk_widget_set_style_internal (widget, new_style); + } + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[REALIZE]); + + if (GTK_WIDGET_HAS_SHAPE_MASK(widget)) + { + shape_info = gtk_object_get_data (GTK_OBJECT (widget), + shape_info_key); + g_assert (shape_info != 0); + gdk_window_shape_combine_mask (widget->window, + shape_info->shape_mask, + shape_info->offset_x, + shape_info->offset_y); + } + + if (!GTK_WIDGET_NO_WINDOW (widget)) + { + mode = gtk_widget_get_extension_events (widget); + if (mode != GDK_EXTENSION_EVENTS_NONE) + { + events = gtk_widget_get_events (widget); + gdk_input_set_extension_events (widget->window, events, mode); + } + } + + } +} + +/***************************************** + * gtk_widget_unrealize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_REALIZED (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[UNREALIZE]); +} + +/***************************************** + * gtk_widget_queue_draw: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_queue_draw (GtkWidget *widget) +{ + GtkWidget *parent; + gint tag; + + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + /* We queue the redraw if: + * a) the widget is not already queued for redraw and + * b) non of the widgets ancestors are queued for redraw. + */ + parent = widget; + while (parent) + { + if (GTK_WIDGET_REDRAW_PENDING (parent)) + return; + parent = parent->parent; + } + + GTK_WIDGET_SET_FLAGS (widget, GTK_REDRAW_PENDING); + gtk_object_ref (GTK_OBJECT (widget)); + tag = gtk_idle_add ((GtkFunction) gtk_real_widget_queue_draw, widget); + gtk_object_set_data (GTK_OBJECT (widget), redraw_handler_key, (gpointer) tag); + } +} + +/***************************************** + * gtk_widget_queue_resize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_queue_resize (GtkWidget *widget) +{ + GtkWidget *toplevel; + GSList *resize_widgets; + gint tag; + + g_return_if_fail (widget != NULL); + + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_WIDGET_ANCHORED (toplevel)) + { + if (GTK_WIDGET_VISIBLE (toplevel)) + { + if (!GTK_WIDGET_RESIZE_PENDING (toplevel)) + { + GTK_WIDGET_SET_FLAGS (toplevel, GTK_RESIZE_PENDING); + gtk_object_ref (GTK_OBJECT (toplevel)); + tag = gtk_idle_add ((GtkFunction) gtk_real_widget_queue_resize, toplevel); + gtk_object_set_data (GTK_OBJECT (toplevel), resize_handler_key, (gpointer) tag); + } + + resize_widgets = gtk_object_get_data (GTK_OBJECT (toplevel), resize_widgets_key); + if (g_slist_find (resize_widgets, widget) == NULL) + { + /* referencing needed? */ + GTK_WIDGET_SET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_object_ref (GTK_OBJECT (widget)); + resize_widgets = g_slist_prepend (resize_widgets, widget); + + gtk_object_set_data (GTK_OBJECT (toplevel), resize_widgets_key, resize_widgets); + } + } + else + { + gtk_container_need_resize (GTK_CONTAINER (toplevel)); + } + } +} + +/***************************************** + * gtk_widget_draw: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GdkRectangle temp_area; + + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_DRAWABLE (widget) && + !GTK_WIDGET_REDRAW_PENDING (widget)) + { + if (!area) + { + if (GTK_WIDGET_NO_WINDOW (widget)) + { + temp_area.x = widget->allocation.x; + temp_area.y = widget->allocation.y; + } + else + { + temp_area.x = 0; + temp_area.y = 0; + } + + temp_area.width = widget->allocation.width; + temp_area.height = widget->allocation.height; + area = &temp_area; + } + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[DRAW], area); + } +} + +/***************************************** + * gtk_widget_draw_focus: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw_focus (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[DRAW_FOCUS]); +} + +/***************************************** + * gtk_widget_draw_default: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw_default (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[DRAW_DEFAULT]); +} + +/***************************************** + * gtk_widget_draw_children: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw_children (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_draw_children_recurse, + NULL); +} + +/***************************************** + * gtk_widget_size_request: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWidgetAuxInfo *aux_info; + + g_return_if_fail (widget != NULL); + + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[SIZE_REQUEST], requisition)) + { + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (aux_info) + { + if (aux_info->width > 0) + requisition->width = aux_info->width; + if (aux_info->height > 0) + requisition->height = aux_info->height; + } + } +} + +/***************************************** + * gtk_widget_size_allocate: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWidgetAuxInfo *aux_info; + GtkAllocation real_allocation; + + g_return_if_fail (widget != NULL); + + real_allocation = *allocation; + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + + if (aux_info) + { + if (aux_info->x != -1) + real_allocation.x = aux_info->x; + if (aux_info->y != -1) + real_allocation.y = aux_info->y; + } + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[SIZE_ALLOCATE], &real_allocation); +} + +/***************************************** + * gtk_widget_install_accelerator: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_install_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name, + gchar key, + guint8 modifiers) +{ + gint return_val; + + g_return_if_fail (widget != NULL); + + return_val = TRUE; + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[INSTALL_ACCELERATOR], + signal_name, key, modifiers, &return_val) && return_val) + gtk_accelerator_table_install (table, GTK_OBJECT (widget), signal_name, key, modifiers); +} + +/***************************************** + * gtk_widget_remove_accelerator: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_remove_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name) +{ + g_return_if_fail (widget != NULL); + + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[REMOVE_ACCELERATOR], signal_name)) + gtk_accelerator_table_remove (table, GTK_OBJECT (widget), signal_name); +} + +/***************************************** + * gtk_widget_event: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_event (GtkWidget *widget, + GdkEvent *event) +{ + gint return_val; + gint signal_num; + + g_return_val_if_fail (widget != NULL, FALSE); + + return_val = FALSE; + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[EVENT], event, &return_val)) + { + if (return_val) + return TRUE; + + switch (event->type) + { + case GDK_NOTHING: + signal_num = -1; + break; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + signal_num = BUTTON_PRESS_EVENT; + break; + case GDK_BUTTON_RELEASE: + signal_num = BUTTON_RELEASE_EVENT; + break; + case GDK_MOTION_NOTIFY: + signal_num = MOTION_NOTIFY_EVENT; + break; + case GDK_DELETE: + signal_num = DELETE_EVENT; + break; + case GDK_DESTROY: + signal_num = DESTROY_EVENT; + break; + case GDK_EXPOSE: + signal_num = EXPOSE_EVENT; + break; + case GDK_KEY_PRESS: + signal_num = KEY_PRESS_EVENT; + break; + case GDK_KEY_RELEASE: + signal_num = KEY_RELEASE_EVENT; + break; + case GDK_ENTER_NOTIFY: + signal_num = ENTER_NOTIFY_EVENT; + break; + case GDK_LEAVE_NOTIFY: + signal_num = LEAVE_NOTIFY_EVENT; + break; + case GDK_FOCUS_CHANGE: + if (event->focus_change.in) + signal_num = FOCUS_IN_EVENT; + else + signal_num = FOCUS_OUT_EVENT; + break; + case GDK_CONFIGURE: + signal_num = CONFIGURE_EVENT; + break; + case GDK_MAP: + signal_num = MAP_EVENT; + break; + case GDK_UNMAP: + signal_num = UNMAP_EVENT; + break; + case GDK_PROPERTY_NOTIFY: + signal_num = PROPERTY_NOTIFY_EVENT; + break; + case GDK_SELECTION_CLEAR: + signal_num = SELECTION_CLEAR_EVENT; + break; + case GDK_SELECTION_REQUEST: + signal_num = SELECTION_REQUEST_EVENT; + break; + case GDK_SELECTION_NOTIFY: + signal_num = SELECTION_NOTIFY_EVENT; + break; + case GDK_PROXIMITY_IN: + signal_num = PROXIMITY_IN_EVENT; + break; + case GDK_PROXIMITY_OUT: + signal_num = PROXIMITY_OUT_EVENT; + break; + case GDK_DRAG_BEGIN: + signal_num = DRAG_BEGIN_EVENT; + break; + case GDK_DRAG_REQUEST: + signal_num = DRAG_REQUEST_EVENT; + break; + case GDK_DROP_ENTER: + signal_num = DROP_ENTER_EVENT; + break; + case GDK_DROP_LEAVE: + signal_num = DROP_LEAVE_EVENT; + break; + case GDK_DROP_DATA_AVAIL: + signal_num = DROP_DATA_AVAILABLE_EVENT; + break; + case GDK_OTHER_EVENT: + signal_num = OTHER_EVENT; + break; + default: + g_warning ("could not determine signal number for event: %d", event->type); + return return_val; + } + + if (signal_num != -1) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[signal_num], event, &return_val); + } + + return return_val; +} + +/***************************************** + * gtk_widget_activate: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_activate (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (WIDGET_CLASS (widget)->activate_signal) + gtk_signal_emit (GTK_OBJECT (widget), WIDGET_CLASS (widget)->activate_signal); +} + +/***************************************** + * gtk_widget_reparent: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_reparent (GtkWidget *widget, + GtkWidget *new_parent) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (new_parent != NULL); + g_return_if_fail (GTK_IS_CONTAINER (new_parent)); + + if (widget->parent != new_parent) + { + gtk_container_remove (GTK_CONTAINER (widget->parent), widget); + gtk_container_add (GTK_CONTAINER (new_parent), widget); + + if (GTK_WIDGET_REALIZED (widget)) + { + if (GTK_WIDGET_REALIZED (new_parent) && !GTK_WIDGET_NO_WINDOW (widget)) + { + gdk_window_reparent (widget->window, widget->parent->window, 0, 0); + } + else + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_destroy (widget->window); + widget->window = NULL; + + if (GTK_WIDGET_REALIZED (new_parent)) + gtk_widget_realize (widget); + if (GTK_WIDGET_MAPPED (new_parent)) + gtk_widget_map (widget); + } + } + + if (!GTK_WIDGET_REALIZED (widget) && GTK_WIDGET_REALIZED (new_parent)) + gtk_widget_realize (widget); + if (!GTK_WIDGET_MAPPED (widget) && GTK_WIDGET_MAPPED (new_parent)) + gtk_widget_map (widget); + + gtk_widget_queue_resize (widget); + } +} + +/***************************************** + * gtk_widget_popup: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_popup (GtkWidget *widget, + gint x, + gint y) +{ + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_VISIBLE (widget)) + { + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_move (widget->window, x, y); + gtk_widget_show (widget); + } +} + +/***************************************** + * gtk_widget_intersect: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_intersect (GtkWidget *widget, + GdkRectangle *area, + GdkRectangle *intersection) +{ + GdkRectangle *dest; + GdkRectangle tmp; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (area != NULL, FALSE); + + if (intersection) + dest = intersection; + else + dest = &tmp; + + return_val = gdk_rectangle_intersect ((GdkRectangle*) &widget->allocation, area, dest); + + if (return_val && intersection && !GTK_WIDGET_NO_WINDOW (widget)) + { + intersection->x -= widget->allocation.x; + intersection->y -= widget->allocation.y; + } + + return return_val; +} + + +gint +gtk_widget_basic (GtkWidget *widget) +{ + GList *children; + GList *tmp_list; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + + if (!GTK_WIDGET_BASIC (widget)) + return FALSE; + else if (GTK_IS_CONTAINER (widget)) + { + children = gtk_container_children (GTK_CONTAINER (widget)); + if (children) + { + return_val = TRUE; + tmp_list = children; + + while (tmp_list) + { + if (!gtk_widget_basic (GTK_WIDGET (tmp_list->data))) + { + return_val = FALSE; + break; + } + + tmp_list = tmp_list->next; + } + + g_list_free (children); + return return_val; + } + } + + return TRUE; +} + + +/***************************************** + * gtk_widget_grab_focus: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_grab_focus (GtkWidget *widget) +{ + GtkWidget *window; + GtkWidget *child; + gint window_type; + + g_return_if_fail (widget != NULL); + + window_type = gtk_window_get_type (); + window = widget->parent; + child = widget; + + while (window && !gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + { + GTK_CONTAINER (window)->focus_child = child; + child = window; + window = window->parent; + } + + if (window && gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + { + GTK_CONTAINER (window)->focus_child = child; + gtk_window_set_focus (GTK_WINDOW (window), widget); + } +} + +/***************************************** + * gtk_widget_grab_default: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_grab_default (GtkWidget *widget) +{ + GtkWidget *window; + gint window_type; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (widget)); + + window_type = gtk_window_get_type (); + window = widget->parent; + + while (window && !gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + window = window->parent; + + if (window && gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + gtk_window_set_default (GTK_WINDOW (window), widget); +} + +/***************************************** + * gtk_widget_restore_state: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_restore_state (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + widget->state = widget->saved_state; + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[STATE_CHANGED])) + { + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_propagate_restore, + NULL); + } +} + +/***************************************** + * gtk_widget_set_name: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_name (GtkWidget *widget, + const gchar *name) +{ + GtkStyle *new_style; + + g_return_if_fail (widget != NULL); + + if (widget->name) + g_free (widget->name); + widget->name = g_strdup (name); + + if (!GTK_WIDGET_USER_STYLE (widget)) + { + new_style = gtk_rc_get_style (widget); + gtk_widget_set_style_internal (widget, new_style); + } +} + +/***************************************** + * gtk_widget_get_name: + * + * arguments: + * + * results: + *****************************************/ + +gchar* +gtk_widget_get_name (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, NULL); + + if (widget->name) + return widget->name; + return gtk_type_name (GTK_WIDGET_TYPE (widget)); +} + +/***************************************** + * gtk_widget_set_state: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_state (GtkWidget *widget, + GtkStateType state) +{ + g_return_if_fail (widget != NULL); + + if (widget->state != state) + { + widget->saved_state = widget->state; + widget->state = state; + + if (!gtk_signal_emit (GTK_OBJECT (widget), widget_signals[STATE_CHANGED])) + return; + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_propagate_state, + (gpointer) &state); +} + +/***************************************** + * gtk_widget_set_sensitive: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_sensitive (GtkWidget *widget, + gint sensitive) +{ + GtkWidget *window; + gint old_val; + + g_return_if_fail (widget != NULL); + + old_val = GTK_WIDGET_IS_SENSITIVE (widget); + + if (sensitive) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_SENSITIVE); + } + else + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_SENSITIVE); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + window = gtk_widget_get_ancestor (widget, gtk_window_get_type ()); + if (window) + gtk_window_set_focus (GTK_WINDOW (window), NULL); + } + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_parent_sensitive, + &sensitive); + + if (old_val != GTK_WIDGET_IS_SENSITIVE (widget)) + gtk_widget_queue_draw (widget); +} + +/***************************************** + * gtk_widget_set_parent: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_parent (GtkWidget *widget, + GtkWidget *parent) +{ + GtkStyle *style; + gint sensitive; + + g_return_if_fail (widget != NULL); + g_return_if_fail (parent != NULL); + + gtk_object_ref (GTK_OBJECT (widget)); + + widget->parent = parent; + + sensitive = GTK_WIDGET_IS_SENSITIVE (parent); + gtk_widget_set_parent_sensitive (widget, &sensitive); + + if ((widget->parent->state != GTK_STATE_NORMAL) && + (widget->parent->state != widget->state)) + gtk_widget_set_state (widget, widget->parent->state); + + while (parent->parent != NULL) + parent = parent->parent; + + if (GTK_WIDGET_ANCHORED (parent)) + { + if (!GTK_WIDGET_USER_STYLE (widget)) + { + style = gtk_rc_get_style (widget); + if (style != widget->style) + gtk_widget_set_style_internal (widget, style); + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_style_recurse, + NULL); + } +} + +/***************************************** + * gtk_widget_set_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_style (GtkWidget *widget, + GtkStyle *style) +{ + g_return_if_fail (widget != NULL); + + GTK_WIDGET_SET_FLAGS (widget, GTK_USER_STYLE); + gtk_widget_set_style_internal (widget, style); +} + +/***************************************** + * gtk_widget_set_uposition: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_uposition (GtkWidget *widget, + gint x, + gint y) +{ + GtkWidgetAuxInfo *aux_info; + + g_return_if_fail (widget != NULL); + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (!aux_info) + { + aux_info = gtk_widget_aux_info_new (); + gtk_object_set_data (GTK_OBJECT (widget), aux_info_key, aux_info); + } + + if (x > -2) + aux_info->x = x; + if (y > -2) + aux_info->y = y; + + if (GTK_WIDGET_REALIZED (widget) && GTK_IS_WINDOW (widget) && + (aux_info->x != -1) && (aux_info->y != -1)) + { + gdk_window_set_hints (widget->window, aux_info->x, aux_info->y, 0, 0, 0, 0, GDK_HINT_POS); + gdk_window_move (widget->window, aux_info->x, aux_info->y); + } + + if (GTK_WIDGET_VISIBLE (widget) && widget->parent) + gtk_widget_size_allocate (widget, &widget->allocation); +} + +/***************************************** + * gtk_widget_set_usize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_usize (GtkWidget *widget, + gint width, + gint height) +{ + GtkWidgetAuxInfo *aux_info; + + g_return_if_fail (widget != NULL); + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (!aux_info) + { + aux_info = gtk_widget_aux_info_new (); + gtk_object_set_data (GTK_OBJECT (widget), aux_info_key, aux_info); + } + + if (width > -1) + aux_info->width = width; + if (height > -1) + aux_info->height = height; + + if (GTK_WIDGET_VISIBLE (widget)) + gtk_widget_queue_resize (widget); +} + +/***************************************** + * gtk_widget_set_events: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_events (GtkWidget *widget, + gint events) +{ + gint *eventp; + + g_return_if_fail (widget != NULL); + g_return_if_fail (!GTK_WIDGET_NO_WINDOW (widget)); + g_return_if_fail (!GTK_WIDGET_REALIZED (widget)); + + eventp = gtk_object_get_data (GTK_OBJECT (widget), event_key); + + if (events) + { + if (!eventp) + eventp = g_new (gint, 1); + + *eventp = events; + gtk_object_set_data (GTK_OBJECT (widget), event_key, eventp); + } + else + { + if (eventp) + g_free (eventp); + + gtk_object_remove_data (GTK_OBJECT (widget), event_key); + } +} + +/***************************************** + * gtk_widget_set_extension_events: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_extension_events (GtkWidget *widget, + GdkExtensionMode mode) +{ + GdkExtensionMode *modep; + + g_return_if_fail (widget != NULL); + + modep = gtk_object_get_data (GTK_OBJECT (widget), extension_event_key); + + if (!modep) + modep = g_new (GdkExtensionMode, 1); + + *modep = mode; + gtk_object_set_data (GTK_OBJECT (widget), extension_event_key, modep); +} + + +/***************************************** + * gtk_widget_get_toplevel: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_get_toplevel (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, NULL); + + while (widget->parent) + widget = widget->parent; + + return widget; +} + +/***************************************** + * gtk_widget_get_ancestor: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_get_ancestor (GtkWidget *widget, + gint type) +{ + g_return_val_if_fail (widget != NULL, NULL); + + while (widget && !gtk_type_is_a (GTK_WIDGET_TYPE (widget), type)) + widget = widget->parent; + + if (!(widget && gtk_type_is_a (GTK_WIDGET_TYPE (widget), type))) + return NULL; + + return widget; +} + +/***************************************** + * gtk_widget_get_colormap: + * + * arguments: + * + * results: + *****************************************/ + +GdkColormap* +gtk_widget_get_colormap (GtkWidget *widget) +{ + GdkColormap *colormap; + + g_return_val_if_fail (widget != NULL, NULL); + + if (!widget->window) + { + colormap = gtk_object_get_data (GTK_OBJECT (widget), colormap_key); + if (colormap) + return colormap; + return gtk_widget_get_default_colormap (); + } + + return gdk_window_get_colormap (widget->window); +} + +/***************************************** + * gtk_widget_get_visual: + * + * arguments: + * + * results: + *****************************************/ + +GdkVisual* +gtk_widget_get_visual (GtkWidget *widget) +{ + GdkVisual *visual; + + g_return_val_if_fail (widget != NULL, NULL); + + if (!widget->window) + { + visual = gtk_object_get_data (GTK_OBJECT (widget), visual_key); + if (visual) + return visual; + return gtk_widget_get_default_visual (); + } + + return gdk_window_get_visual (widget->window); +} + +/***************************************** + * gtk_widget_get_style: + * + * arguments: + * + * results: + *****************************************/ + +GtkStyle* +gtk_widget_get_style (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, NULL); + + return widget->style; +} + +/***************************************** + * gtk_widget_get_events: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_get_events (GtkWidget *widget) +{ + gint *events; + + g_return_val_if_fail (widget != NULL, 0); + + events = gtk_object_get_data (GTK_OBJECT (widget), event_key); + if (events) + return *events; + + return 0; +} + +/***************************************** + * gtk_widget_get_extension_events: + * + * arguments: + * + * results: + *****************************************/ + +GdkExtensionMode +gtk_widget_get_extension_events (GtkWidget *widget) +{ + GdkExtensionMode *mode; + + g_return_val_if_fail (widget != NULL, 0); + + mode = gtk_object_get_data (GTK_OBJECT (widget), extension_event_key); + if (mode) + return *mode; + + return 0; +} + +/***************************************** + * gtk_widget_get_pointer: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_get_pointer (GtkWidget *widget, + gint *x, + gint *y) +{ + g_return_if_fail (widget != NULL); + + if (x) + *x = -1; + if (y) + *y = -1; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_get_pointer (widget->window, x, y, NULL); + + if (GTK_WIDGET_NO_WINDOW (widget)) + { + if (x) + *x -= widget->allocation.x; + if (y) + *y -= widget->allocation.y; + } + } +} + +/***************************************** + * gtk_widget_is_ancestor: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_is_ancestor (GtkWidget *widget, + GtkWidget *ancestor) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (ancestor != NULL, FALSE); + + while (widget) + { + if (widget->parent == ancestor) + return TRUE; + widget = widget->parent; + } + + return FALSE; +} + +/***************************************** + * gtk_widget_is_child: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_is_child (GtkWidget *widget, + GtkWidget *child) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (child != NULL, FALSE); + + return (child->parent == widget); +} + +/***************************************** + * gtk_widget_push_colormap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_push_colormap (GdkColormap *cmap) +{ + colormap_stack = g_slist_prepend (colormap_stack, cmap); +} + +/***************************************** + * gtk_widget_push_visual: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_push_visual (GdkVisual *visual) +{ + visual_stack = g_slist_prepend (visual_stack, visual); +} + +/***************************************** + * gtk_widget_push_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_push_style (GtkStyle *style) +{ + gtk_style_ref (style); + style_stack = g_slist_prepend (style_stack, style); +} + +/***************************************** + * gtk_widget_pop_colormap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_pop_colormap () +{ + GSList *tmp; + + if (colormap_stack) + { + tmp = colormap_stack; + colormap_stack = colormap_stack->next; + g_slist_free_1 (tmp); + } +} + +/***************************************** + * gtk_widget_pop_visual: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_pop_visual () +{ + GSList *tmp; + + if (visual_stack) + { + tmp = visual_stack; + visual_stack = visual_stack->next; + g_slist_free_1 (tmp); + } +} + +/***************************************** + * gtk_widget_pop_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_pop_style () +{ + GSList *tmp; + + if (style_stack) + { + tmp = style_stack; + style_stack = style_stack->next; + gtk_style_unref ((GtkStyle*) tmp->data); + g_slist_free_1 (tmp); + } +} + +/***************************************** + * gtk_widget_set_default_colormap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_default_colormap (GdkColormap *colormap) +{ + if (default_colormap && (default_colormap != colormap)) + gdk_colormap_destroy (default_colormap); + default_colormap = colormap; +} + +/***************************************** + * gtk_widget_set_default_visual: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_default_visual (GdkVisual *visual) +{ + default_visual = visual; +} + +/***************************************** + * gtk_widget_set_default_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_default_style (GtkStyle *style) +{ + if (default_style) + gtk_style_unref (default_style); + + default_style = style; + gtk_style_ref (default_style); +} + +/* Basically, send a message to all toplevel windows telling them + that a new _GTK_STYLE_COLORS property is available on the root + window */ +void +gtk_widget_propagate_default_style(void) +{ + GdkEventClient sev; + int i; + + /* Set the property on the root window */ + gdk_property_change(GDK_ROOT_PARENT(), + gdk_atom_intern("_GTK_DEFAULT_COLORS", FALSE), + GDK_NONE, sizeof(gushort), + GDK_PROP_MODE_REPLACE, + gtk_widget_get_default_style(), + GTK_STYLE_NUM_STYLECOLORS() * sizeof(GdkColor)); + + for(i = 0; i < 5; i++) sev.data.l[i] = 0; + sev.data_format = 32; + sev.message_type = gdk_atom_intern("_GTK_STYLE_CHANGED", FALSE); + gdk_event_send_clientmessage_toall(&sev); +} + +/***************************************** + * gtk_widget_get_default_colormap: + * + * arguments: + * + * results: + *****************************************/ + +GdkColormap* +gtk_widget_get_default_colormap () +{ + if (!default_colormap) + default_colormap = gdk_colormap_get_system (); + + return default_colormap; +} + +/***************************************** + * gtk_widget_get_default_visual: + * + * arguments: + * + * results: + *****************************************/ + +GdkVisual* +gtk_widget_get_default_visual () +{ + if (!default_visual) + default_visual = gdk_visual_get_system (); + + return default_visual; +} + +/***************************************** + * gtk_widget_get_default_style: + * + * arguments: + * + * results: + *****************************************/ + +GtkStyle* +gtk_widget_get_default_style () +{ + if (!default_style) + { + default_style = gtk_style_new (); + gtk_style_ref (default_style); + } + + return default_style; +} + + +/***************************************** + * gtk_widget_marshal_signal_1: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal1 rfunc; + + rfunc = (GtkWidgetSignal1) func; + + (* rfunc) (object, GTK_VALUE_POINTER (args[0]), func_data); +} + +/***************************************** + * gtk_widget_marshal_signal_2: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal2 rfunc; + gint *return_val; + + rfunc = (GtkWidgetSignal2) func; + return_val = GTK_RETLOC_BOOL (args[3]); + + *return_val = (* rfunc) (object, GTK_VALUE_STRING (args[0]), + GTK_VALUE_CHAR (args[1]), GTK_VALUE_INT (args[2]), + func_data); +} + +/***************************************** + * gtk_widget_marshal_signal_3: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal3 rfunc; + + rfunc = (GtkWidgetSignal3) func; + + (* rfunc) (object, GTK_VALUE_STRING (args[0]), func_data); +} + +/***************************************** + * gtk_widget_marshal_signal_4: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal4 rfunc; + gint *return_val; + + rfunc = (GtkWidgetSignal4) func; + return_val = GTK_RETLOC_BOOL (args[1]); + + *return_val = (* rfunc) (object, GTK_VALUE_BOXED (args[0]), func_data); +} + +/***************************************** + * gtk_real_widget_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_destroy (GtkObject *object) +{ + GtkWidget *widget; + GtkWidgetAuxInfo *aux_info; + gint *events; + GdkExtensionMode *mode; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_WIDGET (object)); + + widget = GTK_WIDGET (object); + + if (GTK_WIDGET_REDRAW_PENDING (widget)) + g_warning ("redraw pending\n"); + if (GTK_WIDGET_RESIZE_PENDING (widget)) + g_warning ("resize pending\n"); + if (GTK_WIDGET_RESIZE_NEEDED (widget)) + g_warning ("resize needed\n"); + + gtk_grab_remove (widget); + + gtk_selection_remove_all (widget); + + if (widget->name) + g_free (widget->name); + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (aux_info) + { + gtk_widget_aux_info_destroy (aux_info); + gtk_object_remove_data (GTK_OBJECT (widget), aux_info_key); + } + + events = gtk_object_get_data (GTK_OBJECT (object), event_key); + if (events) + g_free (events); + + mode = gtk_object_get_data (GTK_OBJECT (object), extension_event_key); + if (mode) + g_free (mode); + + if (GTK_WIDGET_REALIZED (widget)) + gtk_widget_unrealize (widget); + gtk_style_unref (widget->style); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/***************************************** + * gtk_real_widget_show: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (!GTK_WIDGET_VISIBLE (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + + if (widget->parent) + { + gtk_widget_queue_resize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent)) + gtk_widget_map (widget); + } + } +} + +/***************************************** + * gtk_real_widget_hide: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_hide (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_VISIBLE (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); + + if (GTK_WIDGET_MAPPED (widget)) + gtk_widget_unmap (widget); + + if (widget->parent) + gtk_widget_queue_resize (widget); + } +} + +/***************************************** + * gtk_real_widget_map: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_map (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_show (widget->window); + else + gtk_widget_queue_draw (widget); + } +} + +/***************************************** + * gtk_real_widget_unmap: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + if (GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + else + gdk_window_hide (widget->window); + } +} + +/***************************************** + * gtk_real_widget_realize: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_realize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + if(widget->parent) + widget->window = widget->parent->window; + widget->style = gtk_style_attach (widget->style, widget->window); +} + +/***************************************** + * gtk_real_widget_unrealize: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + if (!GTK_WIDGET_NO_WINDOW (widget)) + { + gdk_window_set_user_data (widget->window, NULL); + gdk_window_destroy (widget->window); + } + widget->window = NULL; +} + +/***************************************** + * gtk_real_widget_draw: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GdkEventExpose event; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + event.type = GDK_EXPOSE; + event.window = widget->window; + event.area = *area; + + gtk_widget_event (widget, (GdkEvent*) &event); + } +} + +/***************************************** + * gtk_real_widget_queue_draw: + * + * arguments: + * + * results: + *****************************************/ + +static gint +gtk_real_widget_queue_draw (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REDRAW_PENDING); + + gtk_object_unref (GTK_OBJECT (widget)); + if (GTK_OBJECT_NEED_DESTROY (widget) && + (GTK_OBJECT (widget)->ref_count == 0)) + gtk_widget_destroy (widget); + else + gtk_widget_draw (widget, NULL); + + return FALSE; +} + +/***************************************** + * gtk_real_widget_queue_resize: + * + * arguments: + * + * results: + *****************************************/ + +static gint +gtk_real_widget_queue_resize (GtkWidget *widget) +{ + GSList *resize_widgets; + GSList *tmp_list; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_PENDING); + + gtk_object_unref (GTK_OBJECT (widget)); + if (GTK_OBJECT_NEED_DESTROY (widget) && + (GTK_OBJECT (widget)->ref_count == 0)) + { + gtk_widget_destroy (widget); + } + else + { + gtk_container_need_resize (GTK_CONTAINER (widget)); + + if (!GTK_WIDGET_RESIZE_PENDING (widget)) + { + resize_widgets = gtk_object_get_data (GTK_OBJECT (widget), resize_widgets_key); + + tmp_list = resize_widgets; + while (tmp_list) + { + GtkWidget *child; + + child = tmp_list->data; + tmp_list = tmp_list->next; + + /* referencing needed? */ + GTK_WIDGET_UNSET_FLAGS (child, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (child)); + } + + if (resize_widgets) + { + gtk_object_set_data (GTK_OBJECT (widget), resize_widgets_key, NULL); + g_slist_free (resize_widgets); + } + } + } + + return FALSE; +} + +/***************************************** + * gtk_real_widget_size_allocate: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_NO_WINDOW (widget) && + GTK_WIDGET_MAPPED (widget) && + ((widget->allocation.x != allocation->x) || + (widget->allocation.y != allocation->y) || + (widget->allocation.width != allocation->width) || + (widget->allocation.height != allocation->height)) && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget) && + !GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); +} + +/***************************************** + * gtk_widget_peek_colormap: + * + * arguments: + * + * results: + *****************************************/ + +static GdkColormap* +gtk_widget_peek_colormap () +{ + if (colormap_stack) + return (GdkColormap*) colormap_stack->data; + return gtk_widget_get_default_colormap (); +} + +/***************************************** + * gtk_widget_peek_visual: + * + * arguments: + * + * results: + *****************************************/ + +static GdkVisual* +gtk_widget_peek_visual () +{ + if (visual_stack) + return (GdkVisual*) visual_stack->data; + return gtk_widget_get_default_visual (); +} + +/***************************************** + * gtk_widget_peek_style: + * + * arguments: + * + * results: + *****************************************/ + +static GtkStyle* +gtk_widget_peek_style () +{ + if (style_stack) + return (GtkStyle*) style_stack->data; + return gtk_widget_get_default_style (); +} + + +/***************************************** + * gtk_widget_set_parent_sensitive: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_set_parent_sensitive (GtkWidget *widget, + gpointer client_data) +{ + GtkWidget *window; + gint *sensitive; + + sensitive = client_data; + if (*sensitive) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_PARENT_SENSITIVE); + + if (GTK_IS_CONTAINER (widget) && GTK_WIDGET_SENSITIVE (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_parent_sensitive, + client_data); + } + else + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_PARENT_SENSITIVE); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + window = gtk_widget_get_ancestor (widget, gtk_window_get_type ()); + if (window) + gtk_window_set_focus (GTK_WINDOW (window), NULL); + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_parent_sensitive, + client_data); + } +} + +/***************************************** + * gtk_widget_propagate_restore: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_propagate_restore (GtkWidget *widget, + gpointer client_data) +{ + gtk_widget_restore_state (widget); +} + +/***************************************** + * gtk_widget_propagate_state: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_propagate_state (GtkWidget *widget, + gpointer client_data) +{ + GtkStateType *state; + + state = (GtkStateType*) client_data; + gtk_widget_set_state (widget, *state); +} + +/***************************************** + * gtk_widget_draw_children_recurse: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_draw_children_recurse (GtkWidget *widget, + gpointer client_data) +{ + gtk_widget_draw (widget, NULL); + gtk_widget_draw_children (widget); +} + +/***************************************** + * gtk_widget_set_style_internal: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_set_style_internal (GtkWidget *widget, + GtkStyle *style) +{ + GtkRequisition old_requisition; + + g_return_if_fail (widget != NULL); + + if (widget->style != style) + { + if (GTK_WIDGET_REALIZED (widget)) + gtk_style_detach (widget->style); + + gtk_style_unref (widget->style); + + widget->style = style; + gtk_style_ref (widget->style); + + if (GTK_WIDGET_REALIZED (widget)) + widget->style = gtk_style_attach (widget->style, widget->window); + + if (widget->parent) + { + old_requisition = widget->requisition; + gtk_widget_size_request (widget, &widget->requisition); + + if ((old_requisition.width != widget->requisition.width) || + (old_requisition.height != widget->requisition.height)) + gtk_widget_queue_resize (widget); + else if (GTK_WIDGET_DRAWABLE (widget)) + gtk_widget_queue_draw (widget); + } + } +} + +/***************************************** + * gtk_widget_set_style_recurse: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_set_style_recurse (GtkWidget *widget, + gpointer client_data) +{ + GtkStyle *style; + + style = gtk_rc_get_style (widget); + if (style != widget->style) + gtk_widget_set_style_internal (widget, style); + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_style_recurse, + NULL); +} + +/***************************************** + * gtk_widget_aux_info_new: + * + * arguments: + * + * results: + *****************************************/ + +static GtkWidgetAuxInfo* +gtk_widget_aux_info_new () +{ + GtkWidgetAuxInfo *aux_info; + + if (!aux_info_mem_chunk) + aux_info_mem_chunk = g_mem_chunk_new ("widget aux info mem chunk", + sizeof (GtkWidgetAuxInfo), + 1024, G_ALLOC_AND_FREE); + + aux_info = g_chunk_new (GtkWidgetAuxInfo, aux_info_mem_chunk); + + aux_info->x = -1; + aux_info->y = -1; + aux_info->width = 0; + aux_info->height = 0; + + return aux_info; +} + +/***************************************** + * gtk_widget_aux_info_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info) +{ + g_return_if_fail (aux_info != NULL); + + g_mem_chunk_free (aux_info_mem_chunk, aux_info); +} + +/***************************************** + * gtk_widget_shape_combine_mask: + * set a shape for this widgets' gdk window, this allows for + * transparent windows etc., see gdk_window_shape_combine_mask + * for more information + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_shape_combine_mask (GtkWidget *widget, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y) +{ + GtkWidgetShapeInfo* shape_info; + + g_return_if_fail (widget != NULL); + g_return_if_fail (shape_mask != NULL); + /* set_shape doesn't work on widgets without gdk window */ + g_return_if_fail (!GTK_WIDGET_NO_WINDOW (widget)); + + /* + * remember shape mask for later gtk_widget_realize's + */ + shape_info = gtk_object_get_data (GTK_OBJECT (widget), shape_info_key); + if (!shape_info) + { + shape_info = g_new (GtkWidgetShapeInfo, 1); + gtk_object_set_data (GTK_OBJECT (widget), shape_info_key, shape_info); + } + shape_info->shape_mask = shape_mask; + shape_info->offset_x = offset_x; + shape_info->offset_y = offset_y; + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_SHAPE_MASK); + + /* + * set shape if widget has a gdk window allready. + * otherwise the shape is scheduled to be set by gtk_widget_realize. + */ + if (widget->window) + gdk_window_shape_combine_mask (widget->window, shape_mask, + offset_x, offset_y); + +} + +/***************************************** + * gtk_widget_dnd_drag_add: + * when you get a DRAG_ENTER event, you can use this + * to tell Gtk ofother widgets that are to be dragged as well + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_drag_add (GtkWidget *widget) +{ +} + +/***************************************** + * gtk_widget_dnd_drag_set: + * these two functions enable drag and/or drop on a + * widget and also let Gtk know what data types will be accepted + * use MIME type naming,plus tacking "URL:" on the front for link + * dragging + * + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_drag_set (GtkWidget *widget, + guint8 drag_enable, + gchar **type_accept_list, + guint numtypes) +{ + g_return_if_fail(widget != NULL); + + if (!widget->window) + gtk_widget_realize (widget); + + g_return_if_fail (widget->window != NULL); + gdk_window_dnd_drag_set (widget->window, + drag_enable, + type_accept_list, + numtypes); +} + +/***************************************** + * gtk_widget_dnd_drop_set: + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_drop_set (GtkWidget *widget, + guint8 drop_enable, + gchar **type_accept_list, + guint numtypes, + guint8 is_destructive_operation) +{ + g_return_if_fail(widget != NULL); + + if (!widget->window) + gtk_widget_realize (widget); + + g_return_if_fail (widget->window != NULL); + gdk_window_dnd_drop_set (widget->window, + drop_enable, + type_accept_list, + numtypes, + is_destructive_operation); +} + +/***************************************** + * gtk_widget_dnd_data_set: + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_data_set (GtkWidget *widget, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (widget->window != NULL); + + gdk_window_dnd_data_set (widget->window, event, data, data_numbytes); +} + diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h new file mode 100644 index 0000000000..51ea9940c8 --- /dev/null +++ b/gtk/gtkwidget.h @@ -0,0 +1,505 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_WIDGET_H__ +#define __GTK_WIDGET_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkaccelerator.h> +#include <gtk/gtkobject.h> +#include <gtk/gtkstyle.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* The flags that are used in the flags member of the GtkObject + * structure. + */ +enum +{ + GTK_VISIBLE = 1 << 3, + GTK_MAPPED = 1 << 4, + GTK_UNMAPPED = 1 << 5, + GTK_REALIZED = 1 << 6, + GTK_SENSITIVE = 1 << 7, + GTK_PARENT_SENSITIVE = 1 << 8, + GTK_NO_WINDOW = 1 << 9, + GTK_HAS_FOCUS = 1 << 10, + GTK_CAN_FOCUS = 1 << 11, + GTK_HAS_DEFAULT = 1 << 12, + GTK_CAN_DEFAULT = 1 << 13, + GTK_PROPAGATE_STATE = 1 << 14, + GTK_ANCHORED = 1 << 15, + GTK_BASIC = 1 << 16, + GTK_USER_STYLE = 1 << 17, + GTK_GRAB_ALL = 1 << 18, + GTK_REDRAW_PENDING = 1 << 19, + GTK_RESIZE_PENDING = 1 << 20, + GTK_RESIZE_NEEDED = 1 << 21, + GTK_HAS_SHAPE_MASK = 1 << 22 +}; + + +/* Macro for casting a pointer to a GtkWidget pointer. + */ +#define GTK_WIDGET(obj) GTK_CHECK_CAST (obj, gtk_widget_get_type (), GtkWidget) + +/* Macro for casting the "class" field of an object to + * a GtkWidgetClass pointer. + */ +#define GTK_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_widget_get_type (), GtkWidgetClass) + +/* Macros for extracting various fields from GtkWidget and + * GtkWidgetClass structures. + */ +#define GTK_WIDGET_TYPE(obj) (GTK_OBJECT_TYPE (obj)) +#define GTK_WIDGET_STATE(obj) (GTK_WIDGET (obj)->state) +#define GTK_WIDGET_SAVED_STATE(obj) (GTK_WIDGET (obj)->saved_state) +#define GTK_WIDGET_VISIBLE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_VISIBLE) +#define GTK_WIDGET_MAPPED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_MAPPED) +#define GTK_WIDGET_UNMAPPED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_UNMAPPED) +#define GTK_WIDGET_REALIZED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_REALIZED) +#define GTK_WIDGET_SENSITIVE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_SENSITIVE) +#define GTK_WIDGET_PARENT_SENSITIVE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_PARENT_SENSITIVE) +#define GTK_WIDGET_IS_SENSITIVE(obj) ((GTK_WIDGET_SENSITIVE (obj) && \ + GTK_WIDGET_PARENT_SENSITIVE (obj)) != 0) +#define GTK_WIDGET_NO_WINDOW(obj) (GTK_OBJECT_FLAGS (obj) & GTK_NO_WINDOW) +#define GTK_WIDGET_HAS_FOCUS(obj) (GTK_OBJECT_FLAGS (obj) & GTK_HAS_FOCUS) +#define GTK_WIDGET_CAN_FOCUS(obj) (GTK_OBJECT_FLAGS (obj) & GTK_CAN_FOCUS) +#define GTK_WIDGET_HAS_DEFAULT(obj) (GTK_OBJECT_FLAGS (obj) & GTK_HAS_DEFAULT) +#define GTK_WIDGET_CAN_DEFAULT(obj) (GTK_OBJECT_FLAGS (obj) & GTK_CAN_DEFAULT) +#define GTK_WIDGET_PROPAGATE_STATE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_PROPAGATE_STATE) +#define GTK_WIDGET_DRAWABLE(obj) (GTK_WIDGET_VISIBLE (obj) && GTK_WIDGET_MAPPED (obj)) +#define GTK_WIDGET_ANCHORED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_ANCHORED) +#define GTK_WIDGET_BASIC(obj) (GTK_OBJECT_FLAGS (obj) & GTK_BASIC) +#define GTK_WIDGET_USER_STYLE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_USER_STYLE) +#define GTK_WIDGET_GRAB_ALL(obj) (GTK_OBJECT_FLAGS (obj) & GTK_GRAB_ALL) +#define GTK_WIDGET_REDRAW_PENDING(obj) (GTK_OBJECT_FLAGS (obj) & GTK_REDRAW_PENDING) +#define GTK_WIDGET_RESIZE_PENDING(obj) (GTK_OBJECT_FLAGS (obj) & GTK_RESIZE_PENDING) +#define GTK_WIDGET_RESIZE_NEEDED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_RESIZE_NEEDED) +#define GTK_WIDGET_HAS_SHAPE_MASK(obj) (GTK_OBJECT_FLAGS (obj) & GTK_HAS_SHAPE_MASK) + +#define GTK_TYPE_WIDGET (gtk_widget_get_type ()) + +/* Macro for testing whether "obj" is of type GtkWidget. + */ +#define GTK_IS_WIDGET(obj) GTK_CHECK_TYPE (obj, GTK_TYPE_WIDGET) + +/* Macros for setting and clearing widget flags. Notice + * that these are only wrappers for the macros which + * set and clear the flags in the GtkObject structure. + */ +#define GTK_WIDGET_SET_FLAGS(obj,flag) (GTK_OBJECT_SET_FLAGS (obj, flag)) +#define GTK_WIDGET_UNSET_FLAGS(obj,flag) (GTK_OBJECT_UNSET_FLAGS (obj, flag)) + + + +typedef struct _GtkRequisition GtkRequisition; +typedef struct _GtkAllocation GtkAllocation; +typedef struct _GtkSelectionData GtkSelectionData; +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWidgetClass GtkWidgetClass; +typedef struct _GtkWidgetAuxInfo GtkWidgetAuxInfo; +typedef struct _GtkWidgetShapeInfo GtkWidgetShapeInfo; + +typedef void (*GtkCallback) (GtkWidget *widget, + gpointer data); + +/* A requisition is a desired amount of space which a + * widget may request. + */ +struct _GtkRequisition +{ + guint16 width; + guint16 height; +}; + +/* An allocation is a size and position. Where a widget + * can ask for a desired size, it is actually given + * this amount of space at the specified position. + */ +struct _GtkAllocation +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +/* The contents of a selection are returned in a GtkSelectionData + structure. selection/target identify the request. + type specifies the type of the return; if length < 0, and + the data should be ignored. This structure has object semantics - + no fields should be modified directly, they should not be created + directly, and pointers to them should not be stored beyond the duration of + a callback. (If the last is changed, we'll need to add reference + counting) */ + +struct _GtkSelectionData +{ + GdkAtom selection; + GdkAtom target; + GdkAtom type; + gint format; + guchar *data; + gint length; +}; + +/* The widget is the base of the tree for displayable objects. + * (A displayable object is one which takes up some amount + * of screen real estate). It provides a common base and interface + * which actual widgets must adhere to. + */ +struct _GtkWidget +{ + /* The object structure needs to be the first + * element in the widget structure in order for + * the object mechanism to work correctly. This + * allows a GtkWidget pointer to be cast to a + * GtkObject pointer. + */ + GtkObject object; + + /* The state of the widget. There are actually only + * 5 widget states (defined in "gtkenums.h"). + */ + guint8 state; + + /* The saved state of the widget. When a widgets state + * is changed via "gtk_widget_set_state" the old state + * is kept around in this field. The state may be + * restored using "gtk_widget_restore_state". + */ + guint8 saved_state; + + /* The widgets name. If the widget does not have a name + * (the name is NULL), then its name (as returned by + * "gtk_widget_get_name") is its classes name. + * The widget name is used to determine the style to + * use for a widget. + */ + gchar *name; + + /* The style for the widget. The style contains the + * colors the widget should be drawn in for each state + * along with graphics contexts used to draw with and + * the font to use for text. + */ + GtkStyle *style; + + /* The widgets desired size. + */ + GtkRequisition requisition; + + /* The widgets allocated size. + */ + GtkAllocation allocation; + + /* The widgets window or its parent window if it does + * not have a window. (Which will be indicated by the + * GTK_NO_WINDOW flag being set). + */ + GdkWindow *window; + + /* The widgets parent. + */ + GtkWidget *parent; +}; + +struct _GtkWidgetClass +{ + /* The object class structure needs to be the first + * element in the widget class structure in order for + * the class mechanism to work correctly. This allows a + * GtkWidgetClass pointer to be cast to a GtkObjectClass + * pointer. + */ + GtkObjectClass parent_class; + + /* The signal to emit when an object of this class is activated. + * This is used when activating the current focus widget and + * the default widget. + */ + gint activate_signal; + + /* basics */ + void (* show) (GtkWidget *widget); + void (* hide) (GtkWidget *widget); + void (* map) (GtkWidget *widget); + void (* unmap) (GtkWidget *widget); + void (* realize) (GtkWidget *widget); + void (* unrealize) (GtkWidget *widget); + void (* draw) (GtkWidget *widget, + GdkRectangle *area); + void (* draw_focus) (GtkWidget *widget); + void (* draw_default) (GtkWidget *widget); + void (* size_request) (GtkWidget *widget, + GtkRequisition *requisition); + void (* size_allocate) (GtkWidget *widget, + GtkAllocation *allocation); + void (* state_changed) (GtkWidget *widget); + + /* accelerators */ + gint (* install_accelerator) (GtkWidget *widget, + const gchar *signal_name, + gchar key, + guint8 modifiers); + void (* remove_accelerator) (GtkWidget *widget, + const gchar *signal_name); + + /* events */ + gint (* event) (GtkWidget *widget, + GdkEvent *event); + gint (* button_press_event) (GtkWidget *widget, + GdkEventButton *event); + gint (* button_release_event) (GtkWidget *widget, + GdkEventButton *event); + gint (* motion_notify_event) (GtkWidget *widget, + GdkEventMotion *event); + gint (* delete_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* destroy_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* expose_event) (GtkWidget *widget, + GdkEventExpose *event); + gint (* key_press_event) (GtkWidget *widget, + GdkEventKey *event); + gint (* key_release_event) (GtkWidget *widget, + GdkEventKey *event); + gint (* enter_notify_event) (GtkWidget *widget, + GdkEventCrossing *event); + gint (* leave_notify_event) (GtkWidget *widget, + GdkEventCrossing *event); + gint (* configure_event) (GtkWidget *widget, + GdkEventConfigure *event); + gint (* focus_in_event) (GtkWidget *widget, + GdkEventFocus *event); + gint (* focus_out_event) (GtkWidget *widget, + GdkEventFocus *event); + gint (* map_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* unmap_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* property_notify_event) (GtkWidget *widget, + GdkEventProperty *event); + gint (* selection_clear_event) (GtkWidget *widget, + GdkEventSelection *event); + gint (* selection_request_event) (GtkWidget *widget, + GdkEventSelection *event); + gint (* selection_notify_event) (GtkWidget *widget, + GdkEventSelection *event); + gint (* proximity_in_event) (GtkWidget *widget, + GdkEventProximity *event); + gint (* proximity_out_event) (GtkWidget *widget, + GdkEventProximity *event); + gint (* drag_begin_event) (GtkWidget *widget, + GdkEventDragBegin *event); + gint (* drag_request_event) (GtkWidget *widget, + GdkEventDragRequest *event); + gint (* drop_enter_event) (GtkWidget *widget, + GdkEventDropEnter *event); + gint (* drop_leave_event) (GtkWidget *widget, + GdkEventDropLeave *event); + gint (* drop_data_available_event) (GtkWidget *widget, + GdkEventDropDataAvailable *event); + gint (* other_event) (GtkWidget *widget, + GdkEventOther *event); + + /* selection */ + void (* selection_received) (GtkWidget *widget, + GtkSelectionData *selection_data); + + gint (* client_event) (GtkWidget *widget, + GdkEventClient *event); +}; + +struct _GtkWidgetAuxInfo +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +struct _GtkWidgetShapeInfo +{ + gint16 offset_x; + gint16 offset_y; + GdkBitmap *shape_mask; +}; + + +guint gtk_widget_get_type (void); +GtkWidget* gtk_widget_new (guint type, + ...); +GtkWidget* gtk_widget_newv (guint type, + gint nargs, + GtkArg *args); +void gtk_widget_set (GtkWidget *widget, + ...); +void gtk_widget_setv (GtkWidget *widget, + gint nargs, + GtkArg *args); +void gtk_widget_destroy (GtkWidget *widget); +void gtk_widget_unparent (GtkWidget *widget); +void gtk_widget_show (GtkWidget *widget); +void gtk_widget_hide (GtkWidget *widget); +void gtk_widget_map (GtkWidget *widget); +void gtk_widget_unmap (GtkWidget *widget); +void gtk_widget_realize (GtkWidget *widget); +void gtk_widget_unrealize (GtkWidget *widget); +void gtk_widget_queue_draw (GtkWidget *widget); +void gtk_widget_queue_resize (GtkWidget *widget); +void gtk_widget_draw (GtkWidget *widget, + GdkRectangle *area); +void gtk_widget_draw_focus (GtkWidget *widget); +void gtk_widget_draw_default (GtkWidget *widget); +void gtk_widget_draw_children (GtkWidget *widget); +void gtk_widget_size_request (GtkWidget *widget, + GtkRequisition *requisition); +void gtk_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +void gtk_widget_install_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name, + gchar key, + guint8 modifiers); +void gtk_widget_remove_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name); +gint gtk_widget_event (GtkWidget *widget, + GdkEvent *event); + +void gtk_widget_activate (GtkWidget *widget); +void gtk_widget_reparent (GtkWidget *widget, + GtkWidget *new_parent); +void gtk_widget_popup (GtkWidget *widget, + gint x, + gint y); +gint gtk_widget_intersect (GtkWidget *widget, + GdkRectangle *area, + GdkRectangle *intersection); +gint gtk_widget_basic (GtkWidget *widget); + +void gtk_widget_grab_focus (GtkWidget *widget); +void gtk_widget_grab_default (GtkWidget *widget); + +void gtk_widget_restore_state (GtkWidget *widget); +void gtk_widget_set_name (GtkWidget *widget, + const gchar *name); +gchar* gtk_widget_get_name (GtkWidget *widget); +void gtk_widget_set_state (GtkWidget *widget, + GtkStateType state); +void gtk_widget_set_sensitive (GtkWidget *widget, + gint sensitive); +void gtk_widget_set_parent (GtkWidget *widget, + GtkWidget *parent); +void gtk_widget_set_style (GtkWidget *widget, + GtkStyle *style); +void gtk_widget_set_uposition (GtkWidget *widget, + gint x, + gint y); +void gtk_widget_set_usize (GtkWidget *widget, + gint width, + gint height); +void gtk_widget_set_events (GtkWidget *widget, + gint events); +void gtk_widget_set_extension_events (GtkWidget *widget, + GdkExtensionMode mode); + +GtkWidget* gtk_widget_get_toplevel (GtkWidget *widget); +GtkWidget* gtk_widget_get_ancestor (GtkWidget *widget, + gint type); +GdkColormap* gtk_widget_get_colormap (GtkWidget *widget); +GdkVisual* gtk_widget_get_visual (GtkWidget *widget); +GtkStyle* gtk_widget_get_style (GtkWidget *widget); +gint gtk_widget_get_events (GtkWidget *widget); +GdkExtensionMode gtk_widget_get_extension_events (GtkWidget *widget); +void gtk_widget_get_pointer (GtkWidget *widget, + gint *x, + gint *y); + +gint gtk_widget_is_ancestor (GtkWidget *widget, + GtkWidget *ancestor); +gint gtk_widget_is_child (GtkWidget *widget, + GtkWidget *child); + +void gtk_widget_push_colormap (GdkColormap *cmap); +void gtk_widget_push_visual (GdkVisual *visual); +void gtk_widget_push_style (GtkStyle *style); + +void gtk_widget_pop_colormap (void); +void gtk_widget_pop_visual (void); +void gtk_widget_pop_style (void); + +void gtk_widget_set_default_colormap (GdkColormap *colormap); +void gtk_widget_set_default_visual (GdkVisual *visual); +void gtk_widget_set_default_style (GtkStyle *style); +/* Tells other Gtk applications to use the same default style */ +void gtk_widget_propagate_default_style(void); +GdkColormap* gtk_widget_get_default_colormap (void); +GdkVisual* gtk_widget_get_default_visual (void); +GtkStyle* gtk_widget_get_default_style (void); + +/* + * see gdk_window_shape_combine_mask + */ +void gtk_widget_shape_combine_mask (GtkWidget *widget, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y); + +/* + * When you get a drag_enter event, you can use this to tell Gtk of other + * items that are to be dragged as well... + */ +void gtk_widget_dnd_drag_add (GtkWidget *widget); + +/* + * These two functions enable drag and/or drop on a widget, + * and also let Gtk know what data types will be accepted (use MIME type + * naming, plus tacking "URL:" on the front for link dragging) + */ +void gtk_widget_dnd_drag_set (GtkWidget *widget, + guint8 drag_enable, + gchar **type_accept_list, + guint numtypes); +void gtk_widget_dnd_drop_set (GtkWidget *widget, + guint8 drop_enable, + gchar **type_accept_list, + guint numtypes, + guint8 is_destructive_operation); + +/* + * used to reply to a DRAG_REQUEST event - if you don't want to + * give the data then pass in NULL for it + */ +void gtk_widget_dnd_data_set (GtkWidget *widget, + GdkEvent *event, + gpointer data, + gulong data_numbytes); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_WIDGET_H__ */ diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c new file mode 100644 index 0000000000..e97708a96c --- /dev/null +++ b/gtk/gtkwindow.c @@ -0,0 +1,1195 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <string.h> +#include <limits.h> +#include "gdk/gdk.h" +#include "gdk/gdkkeysyms.h" +#include "gdk/gdkx.h" +#include "gtksignal.h" +#include "gtkwindow.h" + +enum { + MOVE_RESIZE, + LAST_SIGNAL +}; + + +typedef gint (*GtkWindowSignal1) (GtkObject *object, + gpointer arg1, + gpointer arg2, + gint arg3, + gint arg4, + gpointer data); + + +static void gtk_window_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + +static void gtk_window_class_init (GtkWindowClass *klass); +static void gtk_window_init (GtkWindow *window); +static void gtk_window_arg (GtkWindow *window, + GtkArg *arg); +static void gtk_window_destroy (GtkObject *object); +static void gtk_window_show (GtkWidget *widget); +static void gtk_window_hide (GtkWidget *widget); +static void gtk_window_map (GtkWidget *widget); +static void gtk_window_unmap (GtkWidget *widget); +static void gtk_window_realize (GtkWidget *widget); +static void gtk_window_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_window_expose_event (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_window_configure_event (GtkWidget *widget, + GdkEventConfigure *event); +static gint gtk_window_key_press_event (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_window_key_release_event (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_window_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_window_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_window_focus_in_event (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_window_focus_out_event (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_window_client_event (GtkWidget *widget, + GdkEvent *event); +static gint gtk_window_need_resize (GtkContainer *container); +static gint gtk_real_window_move_resize (GtkWindow *window, + gint *x, + gint *y, + gint width, + gint height); +static gint gtk_window_move_resize (GtkWidget *widget); +static void gtk_window_set_hints (GtkWidget *widget, + GtkRequisition *requisition); +static gint gtk_window_check_accelerator (GtkWindow *window, + gint key, + guint mods); + + +static GtkBinClass *parent_class = NULL; +static gint window_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_window_get_type () +{ + static guint window_type = 0; + + if (!window_type) + { + GtkTypeInfo window_info = + { + "GtkWindow", + sizeof (GtkWindow), + sizeof (GtkWindowClass), + (GtkClassInitFunc) gtk_window_class_init, + (GtkObjectInitFunc) gtk_window_init, + (GtkArgFunc) gtk_window_arg, + }; + + window_type = gtk_type_unique (gtk_bin_get_type (), &window_info); + } + + return window_type; +} + +static void +gtk_window_class_init (GtkWindowClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + parent_class = gtk_type_class (gtk_bin_get_type ()); + + gtk_object_add_arg_type ("GtkWindow::type", GTK_TYPE_WINDOW_TYPE); + gtk_object_add_arg_type ("GtkWindow::title", GTK_TYPE_STRING); + gtk_object_add_arg_type ("GtkWindow::auto_shrink", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWindow::allow_shrink", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWindow::allow_grow", GTK_TYPE_BOOL); + + window_signals[MOVE_RESIZE] = + gtk_signal_new ("move_resize", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWindowClass, move_resize), + gtk_window_marshal_signal_1, + GTK_TYPE_BOOL, 4, + GTK_TYPE_POINTER, GTK_TYPE_POINTER, + GTK_TYPE_INT, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, window_signals, LAST_SIGNAL); + + object_class->destroy = gtk_window_destroy; + + widget_class->show = gtk_window_show; + widget_class->hide = gtk_window_hide; + widget_class->map = gtk_window_map; + widget_class->unmap = gtk_window_unmap; + widget_class->realize = gtk_window_realize; + widget_class->size_request = gtk_window_size_request; + widget_class->size_allocate = gtk_window_size_allocate; + widget_class->expose_event = gtk_window_expose_event; + widget_class->configure_event = gtk_window_configure_event; + widget_class->key_press_event = gtk_window_key_press_event; + widget_class->key_release_event = gtk_window_key_release_event; + widget_class->enter_notify_event = gtk_window_enter_notify_event; + widget_class->leave_notify_event = gtk_window_leave_notify_event; + widget_class->focus_in_event = gtk_window_focus_in_event; + widget_class->focus_out_event = gtk_window_focus_out_event; + widget_class->client_event = gtk_window_client_event; + + container_class->need_resize = gtk_window_need_resize; + + klass->move_resize = gtk_real_window_move_resize; +} + +static void +gtk_window_init (GtkWindow *window) +{ + GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (window, GTK_ANCHORED); + + window->title = NULL; + window->wmclass_name = NULL; + window->wmclass_class = NULL; + window->type = GTK_WINDOW_TOPLEVEL; + window->accelerator_tables = NULL; + window->focus_widget = NULL; + window->default_widget = NULL; + window->resize_count = 0; + window->need_resize = FALSE; + window->allow_shrink = FALSE; + window->allow_grow = TRUE; + window->auto_shrink = FALSE; + window->handling_resize = FALSE; + window->position = GTK_WIN_POS_NONE; + window->use_uposition = TRUE; +} + +static void +gtk_window_arg (GtkWindow *window, + GtkArg *arg) +{ + if (strcmp (arg->name, "type") == 0) + { + window->type = GTK_VALUE_ENUM(*arg); + } + else if (strcmp (arg->name, "title") == 0) + { + gtk_window_set_title (window, GTK_VALUE_STRING(*arg)); + } + else if (strcmp (arg->name, "auto_shrink") == 0) + { + window->auto_shrink = (GTK_VALUE_BOOL(*arg) != FALSE); + } + else if (strcmp (arg->name, "allow_shrink") == 0) + { + window->allow_shrink = (GTK_VALUE_BOOL(*arg) != FALSE); + } + else if (strcmp (arg->name, "allow_grow") == 0) + { + window->allow_grow = (GTK_VALUE_BOOL(*arg) != FALSE); + } +} + +GtkWidget* +gtk_window_new (GtkWindowType type) +{ + GtkWindow *window; + + window = gtk_type_new (gtk_window_get_type ()); + + window->type = type; + + return GTK_WIDGET (window); +} + +void +gtk_window_set_title (GtkWindow *window, + const gchar *title) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (window->title) + g_free (window->title); + window->title = g_strdup (title); + + if (GTK_WIDGET_REALIZED (window)) + gdk_window_set_title (GTK_WIDGET (window)->window, window->title); +} + +void +gtk_window_set_wmclass (GtkWindow *window, + gchar *wmclass_name, + gchar *wmclass_class) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (window->wmclass_name) + g_free (window->wmclass_name); + window->wmclass_name = g_strdup (wmclass_name); + + if (window->wmclass_class) + g_free (window->wmclass_class); + window->wmclass_class = g_strdup (wmclass_class); + + if (GTK_WIDGET_REALIZED (window)) + g_warning ("shouldn't set wmclass after window is realized!\n"); +} + +void +gtk_window_set_focus (GtkWindow *window, + GtkWidget *focus) +{ + GdkEventFocus event; + + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (focus && !GTK_WIDGET_CAN_FOCUS (focus)) + return; + + if (window->focus_widget != focus) + { + if (window->focus_widget) + { + event.type = GDK_FOCUS_CHANGE; + event.window = window->focus_widget->window; + event.in = FALSE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &event); + } + + window->focus_widget = focus; + + if (window->focus_widget) + { + event.type = GDK_FOCUS_CHANGE; + event.window = window->focus_widget->window; + event.in = TRUE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &event); + } + } +} + +void +gtk_window_set_default (GtkWindow *window, + GtkWidget *defaultw) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (defaultw)); + + if (window->default_widget != defaultw) + { + if (window->default_widget) + { + GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT); + gtk_widget_draw_default (window->default_widget); + } + + window->default_widget = defaultw; + + if (window->default_widget) + { + GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT); + gtk_widget_draw_default (window->default_widget); + } + } +} + +void +gtk_window_set_policy (GtkWindow *window, + gint allow_shrink, + gint allow_grow, + gint auto_shrink) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + window->allow_shrink = (allow_shrink != FALSE); + window->allow_grow = (allow_grow != FALSE); + window->auto_shrink = (auto_shrink != FALSE); +} + +void +gtk_window_add_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + gtk_accelerator_table_ref (table); + window->accelerator_tables = g_list_prepend (window->accelerator_tables, table); +} + +void +gtk_window_remove_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + window->accelerator_tables = g_list_remove (window->accelerator_tables, table); + gtk_accelerator_table_unref (table); +} + +void +gtk_window_position (GtkWindow *window, + GtkWindowPosition position) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + window->position = position; +} + +static void +gtk_window_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWindowSignal1 rfunc; + gint *return_val; + + rfunc = (GtkWindowSignal1) func; + return_val = GTK_RETLOC_BOOL (args[4]); + + *return_val = (* rfunc) (object, + GTK_VALUE_POINTER (args[0]), + GTK_VALUE_POINTER (args[1]), + GTK_VALUE_INT (args[2]), + GTK_VALUE_INT (args[3]), + func_data); +} + +static void +gtk_window_destroy (GtkObject *object) +{ + GtkWindow *window; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_WINDOW (object)); + + window = GTK_WINDOW (object); + g_free (window->title); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_window_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + gtk_widget_map (widget); +} + +static void +gtk_window_hide (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); + gtk_widget_unmap (widget); +} + +static void +gtk_window_map (GtkWidget *widget) +{ + GtkWindow *window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_UNMAPPED); + + gtk_window_move_resize (widget); + window = GTK_WINDOW (widget); + + if (window->bin.child && + GTK_WIDGET_VISIBLE (window->bin.child) && + !GTK_WIDGET_MAPPED (window->bin.child)) + gtk_widget_map (window->bin.child); + + gtk_window_set_hints (widget, &widget->requisition); + gdk_window_show (widget->window); +} + +static void +gtk_window_unmap (GtkWidget *widget) +{ + GtkWindow *window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + GTK_WIDGET_SET_FLAGS (widget, GTK_UNMAPPED); + gdk_window_hide (widget->window); + + window = GTK_WINDOW (widget); + window->use_uposition = TRUE; +} + +static void +gtk_window_realize (GtkWidget *widget) +{ + GtkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + window = GTK_WINDOW (widget); + + switch (window->type) + { + case GTK_WINDOW_TOPLEVEL: + attributes.window_type = GDK_WINDOW_TOPLEVEL; + break; + case GTK_WINDOW_DIALOG: + attributes.window_type = GDK_WINDOW_DIALOG; + break; + case GTK_WINDOW_POPUP: + attributes.window_type = GDK_WINDOW_TEMP; + break; + } + + attributes.title = window->title; + attributes.wmclass_name = window->wmclass_name; + attributes.wmclass_class = window->wmclass_class; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_KEY_PRESS_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_FOCUS_CHANGE_MASK | + GDK_STRUCTURE_MASK); + + attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes_mask |= (window->title ? GDK_WA_TITLE : 0); + attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0); + + widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, window); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_window_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWindow *window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + g_return_if_fail (requisition != NULL); + + window = GTK_WINDOW (widget); + + if (window->bin.child) + { + requisition->width = GTK_CONTAINER (window)->border_width * 2; + requisition->height = GTK_CONTAINER (window)->border_width * 2; + + gtk_widget_size_request (window->bin.child, &window->bin.child->requisition); + + requisition->width += window->bin.child->requisition.width; + requisition->height += window->bin.child->requisition.height; + } + else + { + if (!GTK_WIDGET_VISIBLE (window)) + window->need_resize = TRUE; + } +} + +static void +gtk_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWindow *window; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + g_return_if_fail (allocation != NULL); + + window = GTK_WINDOW (widget); + widget->allocation = *allocation; + + if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child)) + { + child_allocation.x = GTK_CONTAINER (window)->border_width; + child_allocation.y = GTK_CONTAINER (window)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + + gtk_widget_size_allocate (window->bin.child, &child_allocation); + } +} + +static gint +gtk_window_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (!GTK_WIDGET_UNMAPPED (widget)) + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (GTK_WIDGET_DRAWABLE (widget)) + if (GTK_WIDGET_CLASS (parent_class)->expose_event) + return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); + + return FALSE; +} + +static gint +gtk_window_configure_event (GtkWidget *widget, + GdkEventConfigure *event) +{ + GtkWindow *window; + GtkAllocation allocation; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + window->handling_resize = TRUE; + + allocation.x = 0; + allocation.y = 0; + allocation.width = event->width; + allocation.height = event->height; + + gtk_widget_size_allocate (widget, &allocation); + + if (window->bin.child && + GTK_WIDGET_VISIBLE (window->bin.child) && + !GTK_WIDGET_MAPPED (window->bin.child)) + gtk_widget_map (window->bin.child); + + window->resize_count -= 1; + if (window->resize_count == 0) + { + if ((event->width != widget->requisition.width) || + (event->height != widget->requisition.height)) + { + window->resize_count += 1; + gdk_window_resize (widget->window, + widget->requisition.width, + widget->requisition.height); + } + } + else if (window->resize_count < 0) + { + window->resize_count = 0; + } + + window->handling_resize = FALSE; + + return FALSE; +} + +static gint +gtk_window_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + GtkWindow *window; + GtkDirectionType direction = 0; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + + return_val = FALSE; + if (window->focus_widget) + return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event); + + if (!return_val && gtk_window_check_accelerator (window, event->keyval, event->state)) + return_val = TRUE; + + if (!return_val) + { + switch (event->keyval) + { + case GDK_space: + if (window->focus_widget) + { + gtk_widget_activate (window->focus_widget); + return_val = TRUE; + } + break; + case GDK_Return: + case GDK_KP_Enter: + if (window->default_widget) + { + gtk_widget_activate (window->default_widget); + return_val = TRUE; + } + else if (window->focus_widget) + { + gtk_widget_activate (window->focus_widget); + return_val = TRUE; + } + break; + case GDK_Up: + case GDK_Down: + case GDK_Left: + case GDK_Right: + case GDK_Tab: + switch (event->keyval) + { + case GDK_Up: + direction = GTK_DIR_UP; + break; + case GDK_Down: + direction = GTK_DIR_DOWN; + break; + case GDK_Left: + direction = GTK_DIR_LEFT; + break; + case GDK_Right: + direction = GTK_DIR_RIGHT; + break; + case GDK_Tab: + if (event->state & GDK_SHIFT_MASK) + direction = GTK_DIR_TAB_BACKWARD; + else + direction = GTK_DIR_TAB_FORWARD; + break; + default : + direction = GTK_DIR_UP; /* never reached, but makes compiler happy */ + } + + gtk_container_focus (GTK_CONTAINER (widget), direction); + + if (!GTK_CONTAINER (window)->focus_child) + gtk_window_set_focus (GTK_WINDOW (widget), NULL); + else + return_val = TRUE; + break; + } + } + + return return_val; +} + +static gint +gtk_window_key_release_event (GtkWidget *widget, + GdkEventKey *event) +{ + GtkWindow *window; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + if (window->focus_widget) + return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event); + + return return_val; +} + +static gint +gtk_window_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return FALSE; +} + +static gint +gtk_window_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return FALSE; +} + +static gint +gtk_window_focus_in_event (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkWindow *window; + GdkEventFocus fevent; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + /* It appears spurious focus in events can occur when + * the window is hidden. So we'll just check to see if + * the window is visible before actually handling the + * event + */ + if (GTK_WIDGET_VISIBLE (widget)) + { + window = GTK_WINDOW (widget); + if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget)) + { + fevent.type = GDK_FOCUS_CHANGE; + fevent.window = window->focus_widget->window; + fevent.in = TRUE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent); + } + } + + return FALSE; +} + +static gint +gtk_window_focus_out_event (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkWindow *window; + GdkEventFocus fevent; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget)) + { + fevent.type = GDK_FOCUS_CHANGE; + fevent.window = window->focus_widget->window; + fevent.in = FALSE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent); + } + + return FALSE; +} + +static void +gtk_window_style_set_event (GtkWidget *widget, + GdkEventClient *event) +{ + GdkAtom atom_default_colors; + GtkStyle *style_newdefault; + GdkAtom realtype; + gint retfmt, retlen; + GdkColor *data, *stylecolors; + int i = 0, j; + GdkColormap *widget_cmap; + + atom_default_colors = gdk_atom_intern("_GTK_DEFAULT_COLORS", FALSE); + + if(gdk_property_get (GDK_ROOT_PARENT(), + atom_default_colors, + GDK_NONE, + 0, + sizeof(GdkColor) * GTK_STYLE_NUM_STYLECOLORS(), + FALSE, + &realtype, + &retfmt, + &retlen, + (guchar *)&data) != TRUE + || retfmt != sizeof(gushort)) { + g_warning("gdk_property_get() failed in _GTK_STYLE_CHANGED\n"); + return; + } + /* We have the color data, now let's interpret it */ + style_newdefault = gtk_widget_get_default_style(); + gtk_style_ref(style_newdefault); + stylecolors = (GdkColor *) style_newdefault; + + widget_cmap = gtk_widget_get_colormap(widget); + for(i = 0; i < GTK_STYLE_NUM_STYLECOLORS(); i++) { + stylecolors[i] = data[i]; + gdk_color_alloc(widget_cmap, &stylecolors[i]); + } + + gtk_widget_set_default_style(style_newdefault); + gtk_style_unref(style_newdefault); + + /* Now we need to redraw everything */ + gtk_widget_draw(widget, NULL); + gtk_widget_draw_children(widget); +} + +static gint +gtk_window_client_event (GtkWidget *widget, + GdkEvent *event) +{ + GdkAtom atom_styleset; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + atom_styleset = gdk_atom_intern("_GTK_STYLE_CHANGED", FALSE); + + if(event->client.message_type == atom_styleset) { + gtk_window_style_set_event(widget, event); + } + return FALSE; +} + +static gint +gtk_window_need_resize (GtkContainer *container) +{ + GtkWindow *window; + gint return_val; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (container), FALSE); + + return_val = FALSE; + + window = GTK_WINDOW (container); + if (window->handling_resize) + return return_val; + + if (GTK_WIDGET_VISIBLE (container)) + { + window->need_resize = TRUE; + return_val = gtk_window_move_resize (GTK_WIDGET (window)); + window->need_resize = FALSE; + } + + return return_val; +} + +static gint +gtk_real_window_move_resize (GtkWindow *window, + gint *x, + gint *y, + gint width, + gint height) +{ + GtkWidget *widget; + GtkWidget *resize_container; + GSList *resize_widgets; + GSList *resize_containers; + GSList *tmp_list; + gint return_val; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + g_return_val_if_fail ((x != NULL) || (y != NULL), FALSE); + + return_val = FALSE; + + widget = GTK_WIDGET (window); + + if ((*x != -1) && (*y != -1)) + gdk_window_move (widget->window, *x, *y); + + if ((widget->requisition.width == 0) || + (widget->requisition.height == 0)) + { + widget->requisition.width = 200; + widget->requisition.height = 200; + } + + gdk_window_get_geometry (widget->window, NULL, NULL, &width, &height, NULL); + + resize_containers = NULL; + + if ((window->auto_shrink && + ((width != widget->requisition.width) || + (height != widget->requisition.height))) || + (width < widget->requisition.width) || + (height < widget->requisition.height)) + { + if (window->resize_count == 0) + { + window->resize_count += 1; + gdk_window_resize (widget->window, + widget->requisition.width, + widget->requisition.height); + } + } + else + { + /* The window hasn't changed size but one of its children + * queued a resize request. Which means that the allocation + * is not sufficient for the requisition of some child. + * We've already performed a size request at this point, + * so we simply need to run through the list of resize + * widgets and reallocate their sizes appropriately. We + * make the optimization of not performing reallocation + * for a widget who also has a parent in the resize widgets + * list. + */ + resize_widgets = gtk_object_get_data (GTK_OBJECT (window), "resize_widgets"); + gtk_object_set_data (GTK_OBJECT (window), "resize_widgets", NULL); + + tmp_list = resize_widgets; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + /* referencing needed? */ + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (widget)); + + widget = widget->parent; + + while (widget && + ((widget->allocation.width < widget->requisition.width) || + (widget->allocation.height < widget->requisition.height))) + widget = widget->parent; + + if (widget) + GTK_WIDGET_SET_FLAGS (widget, GTK_RESIZE_NEEDED); + } + + tmp_list = resize_widgets; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + resize_container = widget->parent; + while (resize_container && + !GTK_WIDGET_RESIZE_NEEDED (resize_container)) + resize_container = resize_container->parent; + + if (resize_container) + widget = resize_container->parent; + else + widget = NULL; + + while (widget) + { + if (GTK_WIDGET_RESIZE_NEEDED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (resize_container, GTK_RESIZE_NEEDED); + resize_container = widget; + } + widget = widget->parent; + } + + if (resize_container && + !g_slist_find (resize_containers, resize_container)) + resize_containers = g_slist_prepend (resize_containers, resize_container); + } + + g_slist_free (resize_widgets); + + tmp_list = resize_containers; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_widget_size_allocate (widget, &widget->allocation); + gtk_widget_queue_draw (widget); + } + + g_slist_free (resize_containers); + } + + return return_val; +} + +static gint +gtk_window_move_resize (GtkWidget *widget) +{ + GtkWindow *window; + gint x, y; + gint width, height; + gint screen_width; + gint screen_height; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + + return_val = FALSE; + + if (GTK_WIDGET_REALIZED (widget)) + { + window = GTK_WINDOW (widget); + + /* Remember old size, to know if we have to reset hints */ + width = widget->requisition.width; + height = widget->requisition.height; + gtk_widget_size_request (widget, &widget->requisition); + + if (GTK_WIDGET_MAPPED (widget) && + (width != widget->requisition.width || + height != widget->requisition.height)) + gtk_window_set_hints (widget, &widget->requisition); + + x = -1; + y = -1; + width = widget->requisition.width; + height = widget->requisition.height; + + if (window->use_uposition) + switch (window->position) + { + case GTK_WIN_POS_CENTER: + x = (gdk_screen_width () - width) / 2; + y = (gdk_screen_height () - height) / 2; + gtk_widget_set_uposition (widget, x, y); + break; + case GTK_WIN_POS_MOUSE: + gdk_window_get_pointer (NULL, &x, &y, NULL); + + x -= width / 2; + y -= height / 2; + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + if (x < 0) + x = 0; + else if (x > (screen_width - width)) + x = screen_width - width; + + if (y < 0) + y = 0; + else if (y > (screen_height - height)) + y = screen_height - height; + + gtk_widget_set_uposition (widget, x, y); + break; + } + + gtk_signal_emit (GTK_OBJECT (widget), window_signals[MOVE_RESIZE], + &x, &y, width, height, &return_val); + } + + return return_val; +} + +static void +gtk_window_set_hints (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWindow *window; + GtkWidgetAuxInfo *aux_info; + gint flags; + gint ux, uy; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + g_return_if_fail (requisition != NULL); + + if (GTK_WIDGET_REALIZED (widget)) + { + window = GTK_WINDOW (widget); + + flags = 0; + ux = 0; + uy = 0; + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), "aux_info"); + if (aux_info && (aux_info->x != -1) && (aux_info->y != -1)) + { + ux = aux_info->x; + uy = aux_info->y; + flags |= GDK_HINT_POS; + } + if (!window->allow_shrink) + flags |= GDK_HINT_MIN_SIZE; + if (!window->allow_grow) + flags |= GDK_HINT_MAX_SIZE; + + gdk_window_set_hints (widget->window, ux, uy, + requisition->width, requisition->height, + requisition->width, requisition->height, + flags); + + if (window->use_uposition && (flags & GDK_HINT_POS)) + { + window->use_uposition = FALSE; + gdk_window_move (widget->window, ux, uy); + } + } +} + +static gint +gtk_window_check_accelerator (GtkWindow *window, + gint key, + guint mods) +{ + GtkAcceleratorTable *table; + GList *tmp; + + if ((key >= 0x20) && (key <= 0xFF)) + { + tmp = window->accelerator_tables; + while (tmp) + { + table = tmp->data; + tmp = tmp->next; + + if (gtk_accelerator_table_check (table, key, mods)) + return TRUE; + } + + if (gtk_accelerator_table_check (NULL, key, mods)) + return TRUE; + } + + return FALSE; +} diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h new file mode 100644 index 0000000000..ff22527312 --- /dev/null +++ b/gtk/gtkwindow.h @@ -0,0 +1,105 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_WINDOW_H__ +#define __GTK_WINDOW_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkaccelerator.h> +#include <gtk/gtkbin.h> +#include <gtk/gtkenums.h> +#include <gtk/gtkwidget.h> + + +#define GTK_WINDOW(obj) GTK_CHECK_CAST (obj, gtk_window_get_type (), GtkWindow) +#define GTK_WINDOW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_window_get_type (), GtkWindowClass) +#define GTK_IS_WINDOW(obj) GTK_CHECK_TYPE (obj, gtk_window_get_type ()) + + +typedef struct _GtkWindow GtkWindow; +typedef struct _GtkWindowClass GtkWindowClass; + +struct _GtkWindow +{ + GtkBin bin; + + gchar *title; + gchar *wmclass_name; + gchar *wmclass_class; + GtkWindowType type; + GList *accelerator_tables; + + GtkWidget *focus_widget; + GtkWidget *default_widget; + + gshort resize_count; + guint need_resize : 1; + guint allow_shrink : 1; + guint allow_grow : 1; + guint auto_shrink : 1; + guint handling_resize : 1; + guint position : 2; + guint use_uposition : 1; +}; + +struct _GtkWindowClass +{ + GtkBinClass parent_class; + + gint (* move_resize) (GtkWindow *window, + gint *x, + gint *y, + gint width, + gint height); +}; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +guint gtk_window_get_type (void); +GtkWidget* gtk_window_new (GtkWindowType type); +void gtk_window_set_title (GtkWindow *window, + const gchar *title); +void gtk_window_set_wmclass (GtkWindow *window, + gchar *wmclass_name, + gchar *wmclass_class); +void gtk_window_set_focus (GtkWindow *window, + GtkWidget *focus); +void gtk_window_set_default (GtkWindow *window, + GtkWidget *defaultw); +void gtk_window_set_policy (GtkWindow *window, + gint allow_shrink, + gint allow_grow, + gint auto_shrink); +void gtk_window_add_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table); +void gtk_window_remove_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table); +void gtk_window_position (GtkWindow *window, + GtkWindowPosition position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_WINDOW_H__ */ diff --git a/gtk/line-arrow.xbm b/gtk/line-arrow.xbm new file mode 100644 index 0000000000..493ecf325d --- /dev/null +++ b/gtk/line-arrow.xbm @@ -0,0 +1,4 @@ +#define line_arrow_width 6 +#define line_arrow_height 9 +static unsigned char line_arrow_bits[] = { + 0x00, 0x00, 0x04, 0x0c, 0x18, 0x3f, 0x18, 0x0c, 0x04}; diff --git a/gtk/line-wrap.xbm b/gtk/line-wrap.xbm new file mode 100644 index 0000000000..82428037d9 --- /dev/null +++ b/gtk/line-wrap.xbm @@ -0,0 +1,4 @@ +#define line_wrap_width 6 +#define line_wrap_height 9 +static unsigned char line_wrap_bits[] = { + 0x1e, 0x3e, 0x30, 0x30, 0x39, 0x1f, 0x0f, 0x0f, 0x1f, }; diff --git a/gtk/marble.xpm b/gtk/marble.xpm new file mode 100644 index 0000000000..1ef2607610 --- /dev/null +++ b/gtk/marble.xpm @@ -0,0 +1,408 @@ +/* XPM */ +static char *granite07[] = { +/* width height num_colors chars_per_pixel */ +" 384 384 16 1", +/* colors */ +". c #000000", +"# c #111111", +"a c #222222", +"b c #333333", +"c c #444444", +"d c #555555", +"e c #666666", +"f c #777777", +"g c #888888", +"h c #999999", +"i c #aaaaaa", +"j c #bbbbbb", +"k c #cccccc", +"l c #dddddd", +"m c #eeeeee", +"n c #ffffff", +/* pixels */ +"aacfedbbcbbaaaaaaaaabaabaaaaabcbcbbbabbchfdcccbbabbbaaabaabcbaa#aa#######a#aaaabcddeefhec##dgbabbaaadabbcfbaa##########aaabbaaa#a#####a#aa###a#aaabbbbcbbbccdedaaaaa#aaaaa#a#abaaabbabbbeddbbaaaaaca##a#aaaba########aaaadcababbabdehd.##.a######.cgdcb###b##.##.##aaaaa####abcba######a##aac#a##a####aa#aa##babbbcfccbbbcdccccecbbbcbbbcdccddcbcdfeecbhhjihhgffc.aaa####.#######aaaaaaaabbaaaaa", +"aaacedccbbcbaaaaaa#bbaabbbaaaabcaabbbbbbafhfccbbbbbbabacbacbaaaaa##########a###abbcdeghhhcagb#ababaaccbacdfca#a####aa###aaaaabaaa#####aca#aabaababbcccccccbcdfdaaaa###aaaaaaaaaaabbbbbbccccccbbcbcaaa##aaaaabaaaa###abdaccceebaaaabehja####a######..#aeec#bb##########aa#####abba#########aaca########aa#aa###aaaabddbbbbbbbbbbccbbabbbbabbabbabcbcbcefhfeddccefhhijheecb#...a####aaaaaaaabaaaaa", +"aaabccccccdbabcbaaa#aaaaaaaaaaabbabbbbbccabefdccabcbbabacccbaaabaa######a######aaabceiiiihije#bbabbaaeaabcedcaabaa########aaaabaa##a###ab#aabcababbccccccdeeeecc#a##a##aaaaaaaaaabbbbbbbcccbbbdcbbcdaa#a#aabbaaaaa###acbaa#bccaa#abcfig.#######.#######acddgefdda#######a########a#######aaaaaa#a######aaaa#####aaacdcbabbaaabbbcaaaaaaaaabbbaaabbaabbbcbcbabbabcdeefghjkjgc#..####aaaaaaaaaaaa#", +"#aaaaaacbccbcabbbaaaaaabcaaaaabbbbbbabbbcbaabffccbccbccbbcbaaaabaaaa#aa#aa##a#aaaaabbikkjhijicabbbcc#faaacdebcbda#########aaaaaaaaa####aa##cacccabcccdccccdddfdcbaa##a##abbbabccbbcbbbccccaaa#abbaaba#a##abbbbbaaaaaaaaaaccaaca##aabcfic.###aa#######a####bddeeddb####.##.###aaa#########aaaa###aa####aaaa#######aabdbbbbcabbbaaaa#aaaaaaaaabaaabbbaabbbbdbbaaabccccccdcefhhkhda##aaaa#a#aaaaa##", +"#aaabaabcecbaa##bcaaaaaaaababbabaaabbabbaabb#chhfdccccbcbecaaabaaaaaaaaaa####aaaaaaabdgjkkijijdabbdcabfaabcecbbec###########a#aaaabaa#######abbaaaadddedddeeefeccaa###a#aabcccdcbcbbbbccbbbbaaaaa#aabbaaaabbbbbbaaaaaaabbbbbaaa####acegha##a#aabbb####a##adccdedbcc#######.###a###a#######aaa#a#aa##..#aa#########abdbaabbabbbaa###aaaaaaaaaaaaacbaaababbdbabbabcbbcbcbccbbdegjkgb#aa#aa#aaaaaaa", +"##aa#aabccccaaaaaaaa#aaaaaabbaabbbaaaaabbbcbbcfhhgfcccbbbbccbaabbaaaaaaabaa#aaaabaaaabbcehkljjdabacccbgbaaccdb#adea#########aa#abaaaaa#####ac#ba##accdedddefffeaba##a#aaaaacccccccbbbcccaabaaaaaaaaa#aaaaabcbbaaa#bbbbaaefccdbaaa#aaacdei##aa##aabbbaaa#a#cdcccccbcea.#########bbaaa######a###a#aaaa.#aaba####.###abcbaaabaabbbaa###aaaaaaaaaaaabbaaaaaaaaaaababcbbcbbaabbbdddeghheba##ab#abaa##", +"#####bbaaaaabaaaaa##aa#adccaabaaabbbbabbabbbabccbccfdbccbbbbbcaabcaabaaabbaaaaaaaaaaaabbbcglli#accbbbddgabcddbbaacea#a##########aaa#aaa##aaaa####aabcddeeefffgdbbaaaa###baabbbbbbcdabdcbcaaabaaaaaaa#aaaaaabcbbbbadfbbbaejhhebbccaaaaaccfi.aba##abaaaba####ecbbccba#fc.####.##.bba#a#######aaaaaaaaaaa##aaaa######abcdaa#aaaabaaa###aaaaabaaabbbaaba##aaababcbbcbbbbbcbaaabbccccddgggeb#aadca###", +"#####bcaaaaaabcbaaa#aaaabcccaaaaaaabaaabbbbbbbaacbabeeddddccbcbbcccbabaaaabaabaaaaaaaaabbbbglmdbcbaabebdgdbcecbbaabdbaa#########aabbaaaa#aa#a##a#aabbdceeedccdcbbaaaaa##aaabbcbbbabaaabbababbaaaa#aaaaaaaabcdccbbbabcbbbcfijfbcdcabb#abcbif#abb##aaabaaaa##fcccbbcaa#db#..##.##.aaa#########ab#aaaaaa#aabaaaaa#####abdbbaaaabbaaaa###b#a#aaaabaaaaaaaaaaaaaabbabbbbaabbbaaaabbbbbbbceffecccbaa##", +"#####abaaaaa#accbbbbaaabaaaaaaaaaaadcbaabbabbbabbdcaacgfddddcdddcadfcaaaabcbbabaaaaaabcabbbdjliacbababcbdfcdeeaaaaaabba########a##aa#aabaa##a######abddeggca#bcbaaaaaa####aaaaaabbbbbcbbbbbaaa##a#aaaaaaaabcbccbbaaaabaabfgfiecccccbbaaaccicbbbcbaaabaaabb#ceccccdca##aacdb######aaa###a###aabaaaaaa#aabca#abba#####abca##aaaaaaaaa##a##aaaaaaabaaaaaaabaaaacbcbacdbaaabaaaaaabaaaaabbcddccbaa##", +"####aa#aaaaaaabccbabbaaaaaaaaaaaaabfaaabbcbbbbbabdebaabdffddedefedccecccdcbbbbbccbccbbbbbbccekldaabaaabccbfaaaaaaaaaaaba########aaaaaaaaba##aaa###aabbccfgfaababbbaaaaa#aabbaabaaccaabcccbcbaa##aaaaaabaabbbccbbbaabbbbbbdddghdbbbcccb#abcdebcccbaabbbabbcbaecddddbaa##.#acdeca#######a#aaaaaaaaaaaaaaabba##abba####aacba##aaaaaaaaaaaaa##aba#abaaaaaaabaaaabbbbbbcbabbaabbaaaaabaaaaaaaaccbaa##", +".####aa#aabaa##bccbaabbbba#aaaaabbaefdaabbbbccbbbaddaaabadeeffhhhffdedddeecbbbbcccbbabcbabbcfjjlkeaaaaacdadcaa#aaaaaaa#ab######ba#aaabbabcaa#aa###babcddcedba##acbaaaaaa#ababbbacbbbcccdfffbaa#aaaacbaabcbabccbbcbbbbbbcbbccedbbbccdccbaabcgb#bccbbbababbbcccdededcb#a####...addcba##aabbbbbbbbaaaaabba#aaa##abba####abbaa###a#aa#aa##aaa#a##abaaaaaaaaabababbcdbcb#baaaaaaaaaaaaaaaaaa#aaaaa###", +"######a##aaaaaa#accbaaabbbaaa#aaababdcaaabbbbcccbbbdbabbbacdccgecadbbbcdccddeddcccccbaabcbbcgjhhjgeb#aacdcccaa#aa#aaa#a#aaa##aaaaa#aaabbaabb#aa###aabccddeccbbbaabcbbbcbbb#aacbbadbabcccddbaaa#aaaaabbbbabbbbcdbbbabbcddcbbbccaabbbccbbaaaadi##abbbbbbbaabbbacdeedbd######aa####bceda#aabbabaaaaaaaaba#aaaaa#aabaaa###acaaaa####aa##aaaaaaaa#aaaaaaaaaaababaaaaabcaaaaaaabbcbaaaaaaaaa###aaaa###", +"##########aabaa#accbbabbbbbba##aaaabbcbbbbbbbbcbaaabdbbbbbbddccbbbbaaaabbabbbbcefefdcbaadbcddje#debgfbabecdc####aa##a###a#aa#aa##a##aaabbcabbaa###aabbcceedbcbaaaabdcccbabaaabbbbabbccbbaaaaaa#aaaaaaaabbbbbcbccabcccccdcccbbbbabbababbba#abfe#aaaaaaaabccbbaaaedddc######adcaaaa##dfcaaaaaaaaaa#aaaaa##aabcaaabbaa#aaab###aa###aaaaaaaaaaaa##aaaaaaaaaabaaabaaabcabaaaaaaabcbaabaaa##a###aa####", +"#########aaaaaaabbcbbbbabcbaacbaa##aaabaaabccccccbaabecabbbcddbacdeba#aaaaabaaabbdfgedcbaccdcgica#aadghdbddd#aa#aaa#a###aaaabaa#####aaaaabbbbbba#aaabccceecbddbaa#bbccabcbbbbbacccdbbdabbaaaaaaa#aaaa#aabbbbcccdcbcbbccccccbcaababbdbabbba#bbgaabaaa#aaacccdcddbeedba#a##a#aba#aaaa##decbaaba#aaa###a#a###abba#bba###aaba####a####aaaaaaaaaaaa#aaabbbaaabbaabbaabbaaa#aa#a#abbaabbbaaa#aaaa#####", +"############aaaaaaacbbbbbbbaa#aaa#a##aaaaaaaacbbbbbbabdcabbbcdbaccdba#aaaaaababbcbbdddedccddefihaa#aaahiiiffd#aaaa#abaa##aaaaacaa##a#bcaaaabbbcaaaabccdddecabaaaaacbbbabbccccccbbdbdfdaabbaaa###a#aaaaaaaabbbbbbbaaabdcddccbbbbabbbccaabbbaabfdaaabaa#aa##aabbbbbddba##aa#a#aa##aaaaaabcdbbaaa##aa#####a#aaabbaaaaa##abb######aa###aaaaaaaaaaaaaaaaabaaaaaaaabbbbaaabaaa#aaaaaaabbbaaaaaaaaa####", +"###########aa#aa#aaaccabbaaaaaaabb#######a#aaabcbbbabbaeebbccbcbacdaaa##a#aabbbbccbbcbcdegifdfgifba##aaaagigha#aaaaabbaaaaaaaaabaaa##acaaaaabbbbbbabcdddefeba####abbaabccccbbbcbadcbcbaabba#aaaa#aaaaaababacccbaadbabbccedcccbbccbbabaaaaa##ade###abba#aa##abbba#cebb.#a####.#a#aaaaaaaaacfca#aaa###aa###abaabaaaaaaaabbaa#######aaaaa#aa#aaaaaaaaaaababdaaabbbbbababaaaaaa#aaaaaabbaaabaaaaa###", +"##########a#aaabaaaaccaaaaaaabaaaaaaba###a##abaaabbababaccbcbbcccaaba#a###aaabbccdccccccdeegggfigaabb#aaa#fffcba#abbaaaaaaaaaaa#abba##aaa##aabbbcbbbbcdeegfeb####aabaabacbbbcbccaabbabaaaaaaa##aa#aaaaababbabbcbcdbbcccbddcdcccabcbbababba###afba#aabba#acaaabbbbaddb##aa####.####aabbaaaabffcaaaaaa##a##bcabbaaaaaaabbbc#a#a#######aaaaa#####a##ababbbbbaaaabbcbaaaaaaaaaaa#aaaaaabaaababaaaaa#", +"#######a#####a#aaaaabcbaaaaaa#aabaaaaaa###abbabaaaaaccaaabdbccbccbaaca#####accddcccccccddeeefikjeabcca#a#abfifbaa#abbbbbaaaaaaaaa#bbba#bcaaaaaaaccbcccceffeccaa##aaabbbcabbacbddbbaabdbaaaaaaaaaaaaaaabbbaabbbbbbbbbcbbccccdcdcccabbbbbaaba###dcaaaabbaaabaabcbccaadba#aaa########aaaa##aaaacgdbaaaa####cfffda#a#aaaabbdbaa#aaa########aaaa#aa##aaabbabbbaaabbbaaaaaabaaaaaaaa#aaaaabaaaaaaaaa#a", +"a###########aaaaaaaabbaabaaa###abaaa#a##a###a#aaaaabacaaabccbbbcbbbcbb####a#bdfbbccccccdefecdgiiddaabbaaaabacfeaaaaaabcccbaaaaaaabaaacaa##aaaaaaabccddcfgfgbabaaa#aaabbcccbccbcddbbacabbbbbbbbaaacbaaaabcbabbbbbcbbcbccbccdccdccdcbaabbbaabaaade#aa#baaabaa##abbcbacdb#.#abbccc#.##aaa####aa#aeeaaaaaaabbabddfgfba#aabcd#aaaa########aa##a##aaaaaababbaabbbbbabccbababaaaaaaa##a#aaaabbaaaaaaaa#", +"#a###a######aaaaaaaacdaaaaaaaa#aaaaaaaaaa#####a###abbbbaaaaccbbbcbbbbaa#aaaaaeecabcccbccdedcdfgigeaaaacbaaabaacbaaaaaaabcbbbaaaaaaaaabccaaaaaaaaaacccceffffbabb#a####aaaabcccccddcdedbbbbaabcabbbccbccbcbcbbbbbbbbbcecbccccceccccdccbbaaaaaaabce#bbaaa###aaa##ababcacda#abb##a#######a#########bfdca#abcbaabaabcffddbabdc#aaaaa##########aa####aaaaaaabbabbbbbbbcbbbcbaaaaaaaa#aa#aaaaaabaa##b##", +"##a#########aabaaaabcdbabaaaaa##aaaaabaaba######a##ababbbbbabbbbcbcdddbbaa#abceecabccccccdddfedgjgdbaaabaaabbbaaba#aabaabaccaaaaaaaabbccbbbaaabaaabcddefgfebbbb#aa####aaaabbcccccbbfeccbbbaaababbbbbbbccba#abbbabbcdccdcbddcddcccdcddcbaaaaaabcfbadaa#######a#abbacbbcc###a#a########a######a##aabdcabccbbababaaaacdfededbbaa#aa##aa######ba#aa#aaabbabaababcbbcbcbbbabbaaaaaaaa##aaabaaacba#a##", +"##########a#abaaaaabbbcbbbcaa###a#aaaaa##aba#######aaaaaabbdccbaabccdddecaaaabccdbbacccddcdefdfgiifcba#bbaaabbaaaababbbbbbbabbaabaaaacbbbcbbaaaaaaaceeeefffbaaaa###a##aaaabbcbbbddcddddcbcbbaaabbbbababbabaaabababbbbcccdccddcddccccdecaaaa#abccfbbaaa#######aabbaacabe###a#aa#a#a##.aa#######a#aa#cfeecdcccccabbbabacggcabbaaabbaaaa####aabb#aaaabbababbbbbbcccbbbbbcccbbbaaaa#aaaaaababbaaaa##", +"######a####abcbaaaaabbccbcbaa###a##aaa##a###aa######aaaaaabdgebaaabbbccacbaaaaabbbaaabccddcdeeffgigbaaaaaabaabcaaababbbbaabbacbaaabbaaaababccbabbabbdffefhdcaaa###aaabba#aababcbdeeccceccccbababbbbabbabbaaaaaabbaabbcbcccccdcddddccccdcaaaababcdeaba#####.###aaabaab#b####a####a##aa#b########aaaaabedddcccccaaaabbcabeaaaabbccbaaa#abbaaabbbaaaabbbaaacbcbcbbdccbaabbacbbbbbaaaaaaaaabbaa#####", +"######aaa#abbcbaaaaabdccbbaaa#######aaa#####aaa##a#a##aaaababcbbaaaaabdebbbaaa##aaaaaaaabccddeefggieaaaaaaaacabaabbbabbbbaaaabbaaaaaaabbbabbccbaabbbdfgghebbbaa#####abba#aabbbcbccdcbbbcddcccbbbabbabbbabbabaaaaaaacbbabcbbccccddddccbcccaaaaaabbdcbc##########aaacbbaa####a####aa###a#aa###aaa###abbceddedcccbaaaacccdca##a#abbbabaaaabaaabbba#aabbbbbbccbbbbaaacccbbcbbaaabbbbbbabaaabaaaa####", +"#######aa#aaccabbabaabdecbb#a########aaaa####aaa#aba##a#aaaaaaabbdcaabdcbcaacb####abb#abaabccdeffghfdabaaaa#acbbbbcbabcabcbaaaabbbabaaaabbbbbcccbbbccdfedccbbb#########aaaababbacccbcbbbddbdcccccbbbbaaaabbaabbaaaaabaabbbbccdcceedccccacbaaaabbbbddb####aa######aabbaa####a####aa#aa###a#####aa#aabbddeccddccbbbabbbbceb###aa#aaaaaa##aa####aaaa#abbbbbccacccbaa#accbbbbbaaababbabaaaaaaaaa####", +"##a#####aaaaaabbbbabacdddccaa########aa#a#####aaa#aa#aaaaaaaaaaaabcabbcbbbbababa###baaaaaaabccdeeehifbabaaa###abbcbbcaccbcbbbaabbbbabaaabbbbbbbbcccccddbccbbbbba#######aaabbbaabbcccbdcbbdbbddcdcccbabaabaaaaaaaaaaaaaaaabbcccddecccbbacccbbbaabbbceca############aaaaa#############a#############aaaaabccddcbbbabbbbbbba#####a##a####aaa#######aaa#babaabbcbaaa##abbbaabbcbbbbaaaaaaaabbaaa####", +"#########abaaabbabbbbbddeccca##aa######a#aa####bbaaaaaaaaaaaaaaaaaabccbcccebacfdb#####aaaaaaabcdddcfgfccbaa##a##abcbbcbbdcccccabbabaababbbbbbbbbbcdccddbabbbbbba########aaababbbacdccccaabcbbcabddddbbaaabbabbbaaaaaaaaabbbddcddecbccbbbdcbabbbaabbcda#############abaaaa############a####bb##a####aaaaabcffdcccbbbbbbbb#######aaa###aaaa#######aabaaaabbcbaaaaaaaa#aaaaaabbccbbaaaaaabbbaaa####", +"#########aaabbabcbbbbbdddcbaaaaa###############aabaaaa#aaaaaaaaaaabbabbdefffccbba###aa##aaaaaabcdceecggdcbbaa##aa#aacbb#bcdddddabbbbbabbbabbbbbbbccfeedbbbbbbcbba#a#####a#acababbbdcbcbabbabaabaabeedcaaaaaaaabcbbaaaaaaabbcdfdddccbbbbcbccbabbbaaabcda########a#aaaaaaa#aa#####aaabaaaaaaacb##aaa#aaababbcdefddbbcbccbaa#####aaaaaaaab##a########aa#abbcccbaaaaaa###aaaaabaabccbbbaaaaaaaaa####", +"########aaaaaaabbbbbbcdedbbbbabaa##########aa###bbb###a##aaaaaaabbaabbbdfeedb##a#a##aa###aaabbbbccdefbfecbbbaaa####a#adb#acdecdfcbaabcbbbbcbbbbbbcdeffbcccabbcdbbba#a###a#aabaaaaaccccbaaaaabbbbaabdfedaaaababbbbbaaaaaaababbcedcccbbbbaccccbaaaccbbabeb######aaaaa#aaa###a######aaaaaaabacbca#aaaaaabbbbccdegfeccccccbcbaaa#####aaaa#aaaaa###a###aaaabbbcccb##a#aaa#aaaaaaaabbdeddcbabaaaaa####", +"#########a#aabbbbbbbbdddccbbba#aaaa##aa##a####a#bba#a#a#aaaabaabbbabbeedeeefdaaaa#####bb##aaabbabcddehgifffdcbaaaa#aa#aaaaaccdeddcabbbcbbbccbabbccdceeecdcaaaabbcccaaaaaaaaaaaaaabacdddbaabaabbbbcccccfdbaabbaabbcaaaaaaababbcccccbbbbbbbccbcca#acbbbbbda#####aaaa####ab##a######aaaaaaabaccbaaaaabbbbbbccceffcdeedcbbbbaaaa#aaaaaaaaa#aaabaaaaaa##aaaabbbcbbcbaa#####aaaaaabbbcccddcbbaaaaa####", +"##########a#aabbcbcbbcecccbbbabaaaaaa#####a#aaaabbaa##ba#acaaababbbbbbbcdcfgdbbbaa####aba##aaaabbbccdfefhfgedecaaa##abaaaaacbabebbbbbbbbcccbcbbbbddbedbddcaaaaaabdccaaba#aaaaaa#bbbbbaddccaaabcbbdcbbcbddabbbbbbbccaaaaaaaaabcddcbbbbbbbbbbbbbbaaaabbaabe#########a####bb#aa#####aa#aaaabccdbbbbabbcbbbccccdccbaaeffdbca#aaaa#aaaaaaa#aaaaabaaaa#aaaabaabbccbbcceb#bcaaaaaaaabbbbcdcbbbaaaaa####", +"#######aa#aaaaabbccbbcdccddcabaaaaaaaaa###aaa#aabcaaa#bba#aabaabbbbbbabcccdfedcaa##aaa######aaaabbbbcdddghhgfedcbaaaa#aaaaabcbbbccbbbbbbbcbccdcccccbeebccbbbaaaaaccccccba#aaaaaaabaaabbbddbbbbcccbcccbaceeacbbbcbccbaaabbabbbbceccbbbbbabbbbbbbab#aabbbbcc#.######a####.bcbcba####aaaa#bedccbbbbbbbaabccddedaaaaa##beeda#aaaaaaaaaaaaaaaaaaaaabba##babbabbbbcbbbccccbbaaaaabbabaabddcbbbaaaa####", +"##########aaaabbbbccccbcddddbaaaa##a#a#a###aaaa#baabbaaaaaaaabbbabcbaabccbddfebaaba#ba######aaaabbbbbcddfiiigggedbaaaaaaaaaabcbabccbbbbbbbcccddddccceecccccbbaaaabccddbbba#aaaaaaaaabcbbbcccdccbcbabcbabceecbabbbbbbaaaabaabbbcddbbbbbbbbaabbbcbbbbaaabcbdc########..####ccccba#abbaaaabddbabbbcabbbbcccceeca###aaa##aaa##a#aaaaaaaaaaaaaaaaaaaaa##aabcbbbbbbbccbbbbcddaaaaacbaaaabddbbaaaaaa###", +"############aaabbabcddccdbcdcbcbbbaaaaa##a##aaaa##abaaabaaaaaaabbaacaabddabcefc#aabaaa###a####aaabbbbbbddgihhfffgeaaaaaaaaaaaaabbbcbbbbbbbbbcddeeedceccdcccccaaaaabcbddbaa#a#ab#aaacbbbbbbddebbbbccbbbabbbedbaaaaaaaaaaaabbabbccecbbbbccbbbbaabbbbcc#aaabbcc######a#####.bccabbacbababaabdcabbbabbabbbcbdecabaa##aaaa####aaaaba##aaaaabaaababa##aa#aaabbbbbbbbcbbbbacbedbaaa#bbaaaabcbbbbaaaa#aa", +"#######a####aaaaabaabbcccbabbbbbbbcbaaa######a#aa######aaaa#aaa#acbbbabeeebabddbaaabaa####aa#a#aababbbbbcehhgeeffdca##aaaaaaaaaabbbbabbbbbbcdcdddfgfhcbbcbbbcbaaaaabcccdbba###baaaabcbbaabcdeecaaabbbbbbaabddecaaaaaaaabbbbbbbccfcbcbbbbbbbaaaaabbbcca#aabacc#######a####acdcbbbbbbaaaabbccaabbbbbbbabbceecabb#aa#aaaa#######aaa##aaaaaaabbaaaaaaaaaaaabbbaabccbbcbaaacgdaaaa#aababbbabbbbaaaaa#", +"###a#####a#aaaaaabcbacbbddcaaabbbbbbbaaaaaa##a#####a####aaaaa#aaabdbcbbedefcaaabaaaaabaaa#a##abaaaaababbbcfgggfeefea##aaaaaaaaaaabcbbbbbbbbcdcdddefgeabbbbaabccaabaaceddeeaaa##aaaaaabbbabbcdedbabbbaaaaaaaacfecaaaaabaabbbbbbcdfdbccbbbbbaaaaaabbbcdbaa#aabdb#########a#acdcccbaaab#aabccbbbbbbabbbceedccbcbbaaaa#baa#a###a#a##aa###aaaabaaaaaaaa##aaaabbaaabcbbbbbabbdfeaaaa#ababbcbbaabaaaaaa", +"#####a#####aaaaaabbbbbbbcddcbabccaaabbaaaaa#a##a##a######aaaaaabaaaaacbbbffeaaaababbabbbbbaa##bbaaaabbbbcccghghgeffbaaabbaaaaaabbabccbbbbbbcdddefggecccbabaaabbbacbabbdddecbaa####aabaababbcccdcabaa#aaa###abceedcaaaaabbbbccddefdccdccbcbbaaaaabbccdccdb#abbd###a#####a#a#cddcccaaaaaaaaabccbbbbdeefbba##aabaaa#aaaaaa#aa###aaa##a####aaaaaaaaaaaa##aaaabacbabbbbbcbbbbcfgbaaa#aa#abbab#aaaabba", +"##########abaaabbbbbcbcdcccdcbbbcbbbbbba#aaaaa#a############aa#aaaaaaababbdeaaaacbbbbbddcbaaa##abaaaabbbbcccghhhedecababcbaaaaaababcbbbbbccbddceggffecccbbbaaabca#aaaadddedcb#a##aaaabbbabbbbcccdd###aaaa#aa##bcefeddcddccefdddfdcccccccccbbaaaaaabccccdddaabbda########ab##bbbddcbbaa#aaaabcbbbcdddccaaaaa#abaaaaaaaaaa#aa#aaaabaa#####aaaaaaaa#######aabaacbabbbbbbcbbbbdfbbaaaa###baabaabaaba", +"###########aaaabbcbbbcccbddbcdccbbbbcabbaaaaaaaaa###a##aa###aaaabaaababbccbbdb#abccabddbbbba#aaaabdbbaabbbbcdehihbaabbbbcdcbbbbaababbedcbbaccdddeeefedabbabaaa#aaa#aa#beeeeffca###aaabbbcbbbbbbcced#a###a##aaa#abffgfedcccfhcbdebcbccdccccbbaaaaaabbcccccddbaabdcb#.#aa#aaa##abdddcbbbaaababbbbbcbdbabbbbbb##ababbbaaaaa#aa#aa##aaa######ababaaa#####a#aabcbbbabbbbbbcccbbbeabcbba###aaaaaaaaaab", +"b#########aaaaababbbbabbbbdebcccccbbbabaaaaaaaaaaaa########aa#abbaaabbabbdbcbbbaaadcbcbdbabba##aa##abcb#aaabcdcfhgdabbbccdcbcbbbbbbabcgdcbdbbdedeeehfgdbbbbbaaaa#aaa#abddddgeedcaaaaaabbbdccccccbceeaa###a###aaaacfghhgedccggefbccccccccccbbbbbbaabbcccccccdaabaaccb#aaa###a##adedccbcbaaabbbbcbbcddbaaabbbbaadbbaabbaaa##abaaa#aaaaaaaa#aaabaa########abbadccaaabbbcccccbbdcbcbbba###aaaaaaaabb", +"aa##########aaabbbbbbbaabbaccbceeebbaabbaabaaabbbbaaa###aaaba#aabaaaaababbccggcbaabccbbbccbca##aaaabdbbabbabbcdddghbabbccddcbbbcbbbbbccgfcbccceddddeddedddcbababaaaaaa#accdeffedbaaaaaaaacccccbbbccffb#a#####aaaaabfhgghhhhgghecbccbccccccccbbbbaaabbbbcbbbcdcbbabbcb#####abca#abccccccabbbbbbbbbdddbaaaaabab#cdba#aabaaaaaaaa#aaa#a#aa#####aaaa#######aabbbbccbbbabbdeddcbbeaabbcb###aaaaaaaaab", +"baaa######a#aaabaabdbbcbabbaccccedaaaaaaaaaaaaaaadbaa#aaaa##aaaaaaaaabbbcbcccdbaaaaabdcbacbcdcaaaaaaaabaaccbbccdddhgcabcccdecbcbbcbbabadedbbcdedcddeeccdddeeedcbbcbaabbbabbcddddec#aaaaaabbcccccbccdffc##a##a#aaaaaafheffhgeccefcbbcbcccccccbbbbaaabbbbccbbddedbabbcc.##a##abc###cdcccbcbbbabbbaddccababbbaaabaddba##aaaaaa#aaa#a#aaaaa##aa##aaaa#######abbbbccbcbbbbdefeeccecaaaaa####aabaaaaaa", +"bb#a########aabbbaaababcccdaacdbbaba#aaaaaa#aaa##acaa###aa#aaaaaaaaaaabcdcccaaaaaaaaadbcbbbbacc###aaaaaaaacbbccdcdfggbbbcccdecccddcbbbacdfdbcdebbbcccdcccccdcbefccbaaaaabcbbccabdfcaaaaaaabbdddccccccefe##a##aaaaaaaadfghhhdbbcccccbcbbccdccbbbcaaaabbbbdccddeeba#bbda######.acabbddccabcbbbbbbbddccaaaaaaaaaaabdca#a#aaa#aaaaa##a#aaaaa##aa##aaa#a##a##abbbbccbbdbbccefffeccd#a########abaaaaaa", +"aa##########aaaaabaabbaaccdcaacbbaab####aaaa#aaaaaa#a####abaaaaaaabcaaabddcacda#aaabacbbbbddddcbaaa##aaaaa#abbdcccdegfbbcdcdefccddccccbcbbfdccecabccbcbbbcdddcbffdcccb#aacbaabcbbeecaa#aaaabcedddccccddfeb#####aaaaaabbehhfcccbcccccbbccccccbcbcbbaaabbbcdcceddcbbabba########bcbbcdcbbbbbbbbaacccccaaaaaaaaaaaabcba####aba##aaaaaa#aaaaaa##a#aaaaaaa#aaabaabbcbbbbbbbdffffeeeaa########aabcaaaa", +"aba#a#aa####aaaaabbabbabbaccaaabaaaa#######a####aaaaa####aaa#bbaaaabaaacbddcbccaaaaaaaaaaacdeabcbba#a###a#aaabccccdeegfcbcdddeedcdccddccccfedddcbbccbbbbbbccddedecccdca#aaaaaaabacedcddcbabaabccccccccceccd####aaaaaabaacdghhfecccccbbccccccccbcbbbaabbbcccccddcddceaca########cdccdccbbbbbbbbbccbcdcaaaaaaaaaaaaaaba#####aaaaaaa###aaaaa##a####aaaa###aabbbbbbccbdbbbcdefffgaa#a#######aabaaaaa", +"aa#####aa###aaababbccccbbbbcbaaababa#######a#aabaaaaaa####aa#abbaaaabbaabbdcbbcdbbbbaaaaaabcddbcbba#####a#aaabcdccceefhgbbdcceeeeccccccddeefeeecccacccbcbabbccdefdbcebaaaabaababbbcdcdfffdabbbbbcccccccecade#aa#aabaaaabaackijkidbbbcbccccccccbcbbbbaabbccccccccddegfdaa#######ceedcbbcaacccccbcccccbaaaaaaaaaabaaaaaaaaa####aaa.baa######aaaa####baaa#aaaabbbbbccdcbbcddedfgfb##########abbaaa#", +"#a########aaaaaaccbbcdcccbbbba#aaaaaa#####aa#aaab#aaaa#.###aa#aabababcbabaccbccdedaaaa#aaaaabccacbaa#a######aacbcccdffhigeccccdeedddccbcddffdefcbabbbcdecbabbbbcddecddbbaaabbabbbcccddeeffabbabbbbcccccdecdedb#a#aaabbaaaaahifgikfcbcccccccccccbbaaabbcbbbccbbbbcccdhea#a#####aedfebccccbbcbcccccccbaaaaaabaa#aaaaaaaaaba#b###aaa#b#######a####aa##abbbabaaabbbbbcdecbbcdedefghc#########abcedcb", +"a############a#abcbbbcddccbbbcaaaaaa#a####a#a###ba#aa#######aaba#bbbbbccaabcccddeebaaaa##aaaabaaabaaaa#####a#aaaabcbdeggihfccccdddffdcbcccdfcbcbbbbbbccbbbbabaabcdfebcbbca##aabbbbcdcdfffeeaabbbccbbcccdeeddeed##aaabaaaaachgcccfijebbcccccccccbbaaaaabbbaabbaabbcbbcfecaaa#aaadcddbbdcccabbcccbbbabbaaaa#aaa###aaaaaaaaaaaaa##aaaaba######a######a#abbbbbbabbcbbbddcabcddddefgfa########aacedcc", +"#######aaa#####aaaccccddcdcccbbaaaaa####a####a#aaaa#aa#######abaaabbccacdaadccdddccba#aa#bbaaabaaabaaaaaa#aaaaaababbbdeffiiebcccdddeedcccdcfbcbbbbaabcbbbbbbaaaabcdeefeeddedbaaabcbdccefffffabbbbbbbbbcdcdddddefbaabbbbabaeidccddcejgbbccccccccbbbbaaabaaaaabaaabccccdffebaabbaaddcc#cdccabcccccbbbbbaaaaa#aaaa##aa#aaaaaaaaabaaaba#b##a####a#a#a##a#aabbabbaabbbbddecbbdcccddeega.##.#a##aab###", +"#########a#####ababccbbbdcccccabbb##aaaaaa#aaaaa##aaaaaa#..###aaaaaaccbbdcbbccdbccdaa##a#a#aaaaaa#ba###a#a#aaaaaaabbbcdeefhgeccedbbcdedeedgebbbbbbbbcdcbbbaabaaabacccddccccbdcaabbadddeefffgfbabbbbccccccccdddbggbaabbbbabhefcccddddihdccccccccbbbababaaa###aa#aabbbcdeeffa.##abcfedabccbcccabcbbbbbbabaaaaa###aaaaaaaabaaaaaaaaaaaaba#######aaab#####aaabaaaabbbaceffecbccddccdec#####.##aa#aa#", +"#aa########a####abbccbbccdcccbbbbba#a##aaaaabaa#aa####aaba#.##baaaabccdabdbabbbbbcccbaa####aaaaaaa#aaaa######aaaabbabccdfeehihfggfdbceedddeddfdccbbcbbbbbbbbbbaaabaccccbbccdddecababedefffffhgdaaabccbcccccdddbfhfbbbcbbackdeeccdddccfhgbccccbbbaabaaabba#####a#aabbbdeddeda.###aeddcbaaccccccccbbbbbabaaaaaaaaaa##aba##abbaaaaaaaaaab######aa##aa###aaabbbaaaaabbbeffffdcdcdeffda######.###aaa#", +"#aaa############aabcdcbcdcfedeecbbaba##aaaaabaa###b#a##aaaa####abaaacdcaacdaacbcaaaaaaaabc##aaaabaaaaaa######aaaaabbbdddeddfhhhhhhfcccffffdbaabcbdbabbbbbbbbbbaaaaabbcccbbbbcfdedbbadeddeefdefhffecbbcbcccccceddgibbbbbbdecccbbccccddddhidccccbbaacaaabba########aabccedddeda####cdcecbccccddddcbbbbbabbaaa#a#####a#######abaaaaaaa#aaaa#a##aaaa#a####aabaaaaaaaaabccddfgfddefge################", +"##aaaaa#aa######aaabdccbccdeefebbaccb###aaabcbaa########aa######aaba#bdbbbcabbbbbbaaba##aba#####ababaaa##a#a##aaaabbcddedddeeefhghfddccdhecbbbaaaababbbabbabcbaaaaaabbccbbbbbbeefdbbbddbddffdggihiebbbcbbcccccedeicbcbbcdccccccccddddddcfifccbbbbabbabbbaaa####aa#aabcedddefeb##.bdcdeccbcccdddcbabbbbaaaaaa#aa############abaa#aaaaa#aaaaaaaaaa#######aabaaaaaaaabbabbcefgecbcc############a#a#", +"##aaaa####aa##a##aaabcdcbbccdcdccbcaba##aaaabbbaa#aa#a####a######aabaaabaaaaaaaabbba#aa###a##a###abbbaa#aaaa#a##aabbcededddddeghggcdfedffddcbbbaaabbbbbccabbbbbcaaaaabccbbbbbbeccefdbcdbcbcefefhgghdbbcbcccccccdcefedbadccbbcccccddddddddeggcbbbaacaabbbaaa######aaaabdcdeedefbaa#deddcdcbbcdedccbbbcbaaaaaa##################aaaaa#aa##abaaaa#aaa#aa##aaaaaaaaaabaabbacdbacbaaba###############", +"##a#aaa####aa##a##aaabbbbbcdeccbbaaaaabbaaabbaabaa###aaaa#########aaab#aaaaaaaaabbaaaa#a#a#aa#a#aabaaaa###abb##aaaaabcdeeddefghhhebbbfebbdddccbbbbbaaabdcbcbcbacbaaabbabcbbcccddbbcefecdcbbbcddehgggcbbcbcccccccdddffbbdbbbbbccccddddddddddegcbbaabaaabbbaaa######aaabbbcdefdeca#ddedcdddbacadedccbbbbbabaaaa###############.####aaa##a###a##aaa#aaa#abaabaaaaaaaaaaaaabcdbaaaa#a########a##a###", +"a##a#aaaa#####aaaaaaabcccbbcdebbaaba#a#bbaaabbaaaa####aaa#####aa#abaaaaaaaabaaaaaabbbaaaaaa#aaaaaababaaa####aaaaaaaabcddddefedhhgbbbbcefbcdedcedabbbababbbcbbbbbbaaabbaabbbbbcbcddbbbcdcebbbbdcabehhebbbbcccccccceddhfddbbbbbccccddddddddddcdfdaaaaaababbaaaaaaaaaaabbbbccddcdfededffddddcbcabcddccbbcbbaaaaa#####################aa##a#a#######aa###aaaaaa###aaaaaaaaaabbccaabaaaa######a######", +"aaaabaa##aa####aaaaaabbccccbcccaabbba#a##aaaabbb######aaaaba##aaaaababb##aaaaaa#aabaaaa#aaa#aabaaaaaacbaa####aaaaaaabcdeddefefhheabbbbbdfgfgedcfaaabbbbbbaaaaaacabaa#baaabbabaabbdeeeccabdccbbbcaachifbbbcccccbcccddejkeabbbbccccddddddddddccceebabbaabaaaaaaa#aaaabbbcbbcccddefgedfedddcccbaabcdcccbcbcaabaaaa########.##.########aa###a########aaaaa#a###a###aaaaaaaaababccaabaa#########aa#a#", +"##aaaacb########aaaaabbbbcccbdcddbbcbc#aaaca##a#aba######abca#aaaa#aa###aa###aaaaaabbaaa#a###aaaaaaa##bcbba###a#aaaabbceedddehgfdaaabaccbfhiihffcaaaaccbaaaaaaacabaaabbaabcbbbbbbbcbdeffedfdb#acaabafjgbbcbcccbccccdefiicbbbbacccddddddddccccbbcfbbbbbabaaaaaaaaaabbbcbbbbccccdegfecfdbaabdabbbbcccdcccbbbbaaaa###################a#aa##a#a##a####a#aaaaa###########aaaaaabbbbbaabaa#######aa###", +"###aaacba#######abaabbdcbbcdcbbefcbabcbbaaaaa####aa#a#a#a#a##aaab###a#aa####abb#a#aacbaa####aaaaaaa#aaabdcbaaaaaaaaabaceefeeffffbaaabbabccehigfeeddefdbabaaaaabbbabaabaaaaabbbbbbabccbabdedda##aaabbachhbbcbccccbbcccdeghebbbaccddddddddddccccbacecbabaaaaaa#aaaaabbbccbbbbcccdcdgfdfebbbbbcccbcbcddccccccbbaaaaa################aabbaaaa####aa###a##aba#############aaaaabbbddbbaba##########.#", +"####aaaba#######aaaaabdfdbbcccbbdebbaaaab#aaa#a###aa###aaa###aba#####aaa#####aba#aaa#baaa#####aaaaa###aabcccaabbbbbcbbbdfffgeccebaaabbbbcbbeffedccfghhebaaaaaabbaaaaaaaabaabbabbbbbacbbbbcbdda####abbabghabbbccccbbccddddghdaabcddddeedddddcccbbabdfdaaaaa##aaaaaabccccccbbccddcbefdffdcbbbcdccbbccddcccccbbbaaaa################bbccbaabaa#aaaaaa#aabba##a#########a#aaaaabbccbcabaa###########", +"#####aaaba#######aaacccefcccbcdccbcbbaaaaa#abcba#########aaaaaaa######aaaa####aa##aaa#aaaaaaa##aaaaa##aaaccddcccdddddcceeffdccdccbaaaaabbbbcfggdddfffggfebaaaaaaaaaabaaabccbbbbbbbabccbbbbbcbdb###aabbbbghbacccccccccccdddfigdbcddddddeddddcccbbbabbfeabaa#####aaaabcccccbcbdddecegfffcccabbccccbbccdcccccbbbbaaaa############a#aaaababaaaaaaa#aaa##aaaa#aaa##########aaaaaabbcccbbdba#########.", +"#####aaaaa######aaabddefcccbabdccccbaaaaaa###aaa######aaabaabbba#######aaaa####a###aaaaaa#a##a#aaaaaaaaaabcddddcdeeedefgfefecdaabbaaaaabbbbbadfebcfdfgffeeecaaaaaaabaaacabdbaaabbbcdcbbbbbbbbccb#a###abbaegcabccccdcccccdddcfihfdccdddddddddcccbaaaaaddbaa######aaabccccbcbccdddhfcfgecccbbbbcbccbccbccbcccbbbbaaaa#a##########aaaaaabccbcba#aa#aa#aaaaa#aaaaa###########aaaabbaddedaa##a#.#####", +"####aaaaaa#######cffdabcbcdcbbadfbcbbaa###a#aaa#aaaaaaabaaaababaa#######a##a#########aaa##aa##aa#aaaaaaaaabdeddccddddddffeeeec#a#aaabbbaaabbbcggdcfeeeeegfdccbabccbbaaabbbcaaaaabbbcdbbbbccbbbdbaaa###abbccebabbccccbcccccddcdfhjhedddddddddccbbaaaaaabdda#######aaabbddccbbdddedccdgeeedccbbccdccbccbcbccccbbbaaaaa#########.##aaabbaabbbcbaaa###aaaaaaa#a#a#a########aaaaabbaccddeb###########", +"########aaa######acddbabcbbcccabcddcaabbaaa##aaaaaabbbcaaaabbaaaaaba########aaa#aa###aaa###aa##abaaaaaacbbbcdffeddeccdffffeddbaaaa#abbaaaabaabegebdfeddeffeddddcdddcabbacbcbccbaabbacccbcdbbbcdb#aa##aabbbbbffbbccccbccccccdddedfkkidddddddcccbbaaaaabbabdb#a#####abcccdbccccddfcccdfgeedccbbbcbccccbbabbcccbbbbbbaaa############a#a#aaaacacbaaa####aaa#aa###a##a######aaabaabbbbbbdfa##########", +"#################abbcbaacccccbccaacbcaaaaaaaaaaaaaaabccabbbbaaab##bb######a#aba##aa##aaaaa##a#a#acabbbacdcbcddffffdgeefefeddcb#a##aaaaabaaaaaaddfdcfdccccccdcbcbcccecbbabccdddddcbbbbccccccbbbceb#aa###aaaabbfgbacccbcccdcdddeedgjkihccddcccccbbaaaabaabaadca####aabbcccbcddccefdcdeeeedddcacbccccccbabaaabbbbbbbaaaa###########.#####aaaabacbba##aaaaaaa####a####a######abbabbcbcbcdb###a##.##.", +"###########aa#####bdbaaaaccddbbdcba#bbaa##aa#aaaabbbbbbaaabaaaaba##aa.####aaa##a#aaaaaabbbaa#####abaabbbbbccdddeefeffddefdccaa####aaaaaaaaaabaeefdedeccbabbbdddbbccccabbbbbbbbcdcccbcccccccccbaaaa#a####aaaabacgcabbcccdddefffedgijfehdcccccccbbbaa#aaaaaaabcbaaaaaabbccdcdddefgecddeefedccbbbabccbbbbaaaaaabbbbaaaaaa################aaabcbabbaa#aaaaa#aaa###a####a####aaabaabcbbbcbba###aa####", +"############a#####abaaaaaabddccbcdddbaaaa###aaaabaaabbbaaaabbabba###b######aa######a##aacbcbba##a##babbccccdddddeeefgfeedccdb####a#aaaaaaaaaaadefedecbabbbbbcddddbcddcaabaaaaaabbbbbaabbccdcccbbbcb#a##aa#aaabbbfdbbccddddeffffefggeedjhedcdcccbbaaaaaaaaaaabbcaaaaabbcdcccdeefgdcccdefeccbbbbbbbccbbbbaaaaaaabbbaaaaa#######aa######aaabbbcab#a#aaaaaaaa#a##a#####abaaa#abaabbbbbbdccc####aa#.#", +"###aaa###a#a#a####aabaaaaaabdbbbcecdcbaaaaaaaa#aaaaaaaaaaaaabccbb###a########a#a#aaaaa##aaaabca#a##aabbccccccdcccbbbbcbcabbbb#a#a#a#aaaabaaaabbeffddeabcbbbbcccccdccbbbaaaaa#abaaaaaaaaaababbbbbcbb#a##a##a#aaaabefcbdeeddeffffffeddfbchjieccccbbbaaaaaaaaaaaacfcabbbbcdddcdehggffeeddgfecbbccbbbccbcbbaaaaaaaaabaaa######a##aaa####aaaaaaabbaa##aaaaaaa#aaaa#####aabbaaaabbbbbbccccddbaaaa####.", +"####aaaaa#aaaa#aaaaaaabbaaabccbbbcddbbdcbaaaaaabaaaaaabbbbaaaaabaaa###############aaaaa##a#aaaaaaaaaaabbccccdcbbbaaaaaaaabaaa#######aaaaabbbabaacffffbbbbbbbbbbbbccccbaaaaaaaaaaaa##aaaaaaabbccca#######aa###aaaabcgfcdeeefgggggggeffcbbehkjebbcbbaa##aaaa#aaaadheabbbcdddcegfbccdfffgggedccccbbbbbabbbaaaaaaaaabaaaaaa######aaaaa#aa##aaaabaaaaaaaaaaaaa##aaa##aaa#acbaaabababbcccdecbaaaa###a#", +"#######a###abaaaaaaaaaaabbdccccbbbceefebcaaaaaa#aaaaaabbbcccaabaaa###aaa#######a###aaaba##aaaaaaa#aaaabccccccbbbaaaaaaaaabaa###a###a#aaaaacbababa#eeedbbbbcddbcbccbccccaaaaaaaa#a#aaaaaaaabbbbcba########aa####aabbbghdeeegggggghggfedbbbcdikgbbbbbaa#aaaaaaaaaabheaabccddegdccccdddccfffddbbabbbcbbbbbbbbbbbaaaaaaaa########a###aaaa#a#abaaaaaaaaaaabbabaaaaaaa#a##ccaaaaaaaaaabcccbacaaabaa###", +"##a#aa#####aaaaaaaaaa#aabbbabbcbbabcdeedcbbbaaaaaaabbbccdddccccbbccbdcbcca########aa####aa##a#aaa###aabbccdccbbbaaaaaabaaaaa#########aaaaabcaaabaa#dfcccbcccbcccccdccccdbbaaaaaa###aaaaaaabbbcb######aa###aaaa###abbcfheeffghhghhijifcbbbbbehjhcbbba##aaaa##aaa##afgdbbcefecdcdccddddddeedcbabbcbbabbcbbbaaaaaaaabaa######a#a#a###aaaa#aaabaaaaa#aaaaaaaaaaaaaaaa#a#bcaaaaabaaaaabbcccbcabbbaaa#", +"aaaaaaaaaa#aaaaaaaaaaaa#abaa#aaaaaaaaabcbbaabbbabbbbccddddddefdbcdccdecddcaa##aab######baaaa##ab###aaaabbbcccbbaaaaaaaaaaaaaa########aaaaaacdbaabaa#dcabccdddcccccdeeddddddbaaaaaa###aaaaabbbca#a#########a###a##aaabcegefgfhhggiiihddbbccbbfegihfb###aaaaa#aaaa##adgfefecbddccccddcedccefdcbabcdcaabbbbbbbaaaaaaaaaa#a####aaa#aa###aaaabaaaa#aaaaaaa#aaa##aaabaa##abcbaaa#aaaaaaabbbbdddbbbaaaa", +"aaaabbabaaaaabaaaaa#a#aaa#abaaaaabaaaaaaaaababbbbccdddeeefdfffedccbbbbcccccaaaaacb#abaab#aaba#aaa###a#aaaabccbaaaa##aaa#abaa###a##a#aa#aaaaacca#abaaadbabddddfededcbbcaaabcddcaaaaaa###aabbbcdca######a####aa##aaaaabbcdkgghhhhhgiigecabbbccffedgiida#aaaaaaa#aaaaaabfecbccccbbbabbbddddddccbaaacdcbbcbbbbbbbaaaaaaaaa##################baaaaaaaa######aa#aaaaa#a##abbbbaaaaabbaaaababbddcbbbbaa", +"aaaaabcccbbbaabaaaaa#aaaaa#aaaaaaaaaaaaabaaabaaabbbcdffefgffdcccdddcccccbaabaaacbab#aa##aaabb#a#a##aaaaaaabbbcaaa###aaaa#aaa#a###aaa#abaaaaaacccbaaaabcbaaccbbdccbbbababba#abccbaaaaaaaaaabdeabaa##########aa####aaaabbceghghhihiihhgcbbbbbbegdcdedhhdd#aaaaaaaaaaaaabdccccccaaabbbbcddddfeffdbbabcbbbbbbbbbaaaaaa###a#########aa#######acbaaa#####aaaa##aaaaaaaaa#a#aaaaaaaaaabbbbaabbccddbbbba", +"aaaababbbccbbcbaaaaaa#aaabba#aaaaabaaaaababbbbbaaaaaa#aabbcaaabbbbbbbbbcbaaaaaabaaaa####a##aaaa######aaaaaabbbbb#######a#aaa#a###a##a#aaa#aaacbbcbabbabcabbbcddbaaabbaaaa##aaaabbaaaaaaaabbcdbaaa###########a####aaaaabbbcfihghhhihhhdabbbbbbeeccccbdehfaa##aaaa#aaaaaabedccbaaaabcdcddcbfeffddeedccbbbbbbabbaaaaa#############aa########ababaa###aaaaa###aaaaaaaaa##abaaaaabbbbbbbbbbbbcdffabaa", +"aaaaabbacbbbabaaaa#aaa#aaaacba###aaabaaaaaababaaaaaaaaaa##aaaaaaaaababbccc###aabaaaa##a##aaaaa#aa##aa#abaaaacccb##a#a#a#aaaaa####aaaa###a#aa#ababdbbbabcbabbbbbbbbbcbbaaaaaaaaaaba#a###aaacbcdaaaa#########.#####aaaaaabbccfkjgfhhifdfdaaababbffcbbbbbacgda#aaaaaaaaaaaaaddcba#aabccccdbbdeefeddfdfecbbacaaaabbaa##############aaaaa#######a#aa###aaa####aaaaaabaaaaaaaba#aaababbbcccddddgihcabb", +"baaaaababccccbbaaa##aaaaaaa#cddb#####aabbbbaaaaaaaaaaa#####aaa##aa#aabadedca#abbaaaaaa####aaaa#a#aaaaa##aababcbca#aaaa#####aa###a#aa##aaaaa#a#aaacbaabbbcbabcccbbbbcbabba#aaaaaaaa#bbaaaaabbadb###################aaaaaabacbgkkihhggfedaaaaaaaceecbaaaaabffgeca#aaaaaa###acdca#aaacbbccbcbeeefffdabdfecabaaababbaa#a##########aaaaaa#######abaa##aaaa#####aaaaaaaaaaaaaabaaabaabbbbbcdegghffdabb", +"bbaaaaaabbcccccbbaaaaaaabaaaabccca###aabcceebaaaaaaaaaaa#a##a#####aa#aaaddbbaaabaaaaaaaaaaaaabb##abb#aaaaaaabcbba##aaa###aaa#########a#aaaaaaaaaaaaaabbbccbaabccbcbbbbbaaaaaaaaa##aaabaaaaccbed#################.##aaa#aaaaacekljihhhdbaaaaaaabdeedbaaaaaabceffdaaaaa#####abdd##abbbbccccbcedfeddbbbbdddbbaaababaaa#################aa#aa.###aa##ba##aa###aaaaaaabaaaaabaaaaababbabbbdfhjifeecba", +"bbbaaababaabbcccbaaaaaa#aaaaa#aaba##aaabcbbccbaaaaaaaaaaaaa#aa####aaaaaabccbaaa#aaaabaabaaaa#abdca#acaaaaabaabbaba#aaaaaaabba##aaaaaaaaaaaa##a#aabbbbbbbccbbbacbcbabbbbbaaa#aaa##aaaaaacbccccdbbba#a########a#.####aaaaabaaaaafklljhfcaaaaaaaa#dcgfcbbaaabccccdggcbaaaaa#aaaacdaabbbbbbbbcbddeeddccccbbcecbaaaaaaaa#a##############aaa##a####aa##b###aa#aaaaaaaaaaaaaa#aabaaaaaabaabbdggghhfbdeb", +"bbabbaaaaaabbcbccbabba#aaaa##a#aaa#a#aaabbabbbaaaaaabbabaaaa#a#####aaaaaadcba###aaaaaaaaaaaaaaabbaa#abaaaabbbcbaa#aaaaaaaaaaaa#aaaaaaaaaa#aaaaaaaabbbbbbbcbababbbcbbbbaaaa###a###aaaaaaaccddcddbaaba#aaaa####a#.#.#aaaaabbaaa##djlljc#aaaaaaaa#afdfebaaaabccccddegfdbaabbbbbbabddbbbbbbbbbadceedcdcccbbabdebaaaa#aaa#############aaaaaa#ab####a##ba#####aaaaaaaaaaaaaaaaaaaaaaaaaabcdfebbbabbbcc", +"ecabbaaaaababcdcccbbbcdbaaaabbaa#aaaa##aabcbbbaabaaabbaabaaa#aa###aaaaaabecbaa#a#a#aaaaaaaaaa#aaaaaaaaaaaabbcbaa###aaaaabaaaaaaa#a####aaa#aabaaaaaabbbbbbdcbbabbbcbbaaaaa####aaa#aa###aaabcccccbaabbba##a####aa#####aaaabaaaaa##ahlkfa#aaaaaaa##fbbecaaaabccbcdddceghecbbccccbbbccddbbabaa#ccedddddccbbaaacfbaa#a##a############a##aaaaaaaaa##a###ca#aa###aaaaaaaaabaaaacabbaaabbbbddea###aaaabc", +"abbcbbbbaaaabbccbbbbaaaa#a#aaaabcaaaaaa#aabbbbaabaaccbbabaaaaaaaaaaaabbabdcbaaaaa###aaaaaaaa#aaaaaabbbaabbbabaa#aaaaaa#aaacbbaaa##aa##aaaaabcbaaaaabacbccccabaabaacbcbaaa####aaaaa####aaaabdccdba#abbaaa#######a######aaaaaba#####dljfa#aaaaaaa#ddaadcbccbbbbccccdccehihfddccccccbbdfaaaabbbceefedddcbbbbaaaecaaaaa##a###a####a##a##aaaaaa####a###ba#aa###aaaaaaaaabbbbacbbbbbaaacccdd#####aaaab", +"babbbcccbbbaacdbccbbbaaaaa######aaaaaaaa##abbbbabaaabbaaaaaaaaaaaa##abbbdcccbaa#aa#####aa#aaaaaaaaaaabcbabbabaa##aaaaaab#accbaaaaa#aaaaaaabcddbaaaaabbbccccbaabbbbaabbbbaa###aaaaa#####a#abceeeaaa#aaaaba#######a#######aaaaaaa###.cgjgb#aaaaaaaafcaacdcdcbcbbcbbccdeefeeghfeccccbcddc#aabaaaeffeccccbbbbbaaacdcaaba##aa##a#aa#aaaa#aa###a####a####b#a##aaaaaaaaaaaaabbbbcababbbbcdddeb#a#####aa", +"bacbbcddcbbbbacddccbabbaaaaaa#a##aaaaaa####aabbaaaaaaabaaaaabaaaaaaaaabbcccbbabaaaaa#a#aaaaaaaaaaaaaaaabbccbbba##aaa#aaaaaabbbaaaa#aaa##abbaabbcbaabbcccccbbbbbabbbabbbbaa#############aaabbcedbaaaaaa#aaa######a########a#aaaa##a##adhjc#aaaaaaacdb##bddcbbbbaabbccefgecceffgfcbceccedabbaaacffdccbbbbbbbbbaabccbbaaa#aa####a###aaaaa#a##bb##a###ab##a###aaaaaaaaaaabaaabbbcbcbbbcefeb#####aa#a", +"aaccbcddcbbabcbcddcbbbcbaaaaaaaa#aaaabaa##a#aaaa##aaaaaaaaaaaaaa#aaaaaaaaabbccaaaaaaa#aaabbaaaaaaaaaa##aabccccbaa#aaaa#abaaaaaaaaaaaaaabbbbaabbaccbddedcbbbbbabbbcbcbbcaaaa############a#aacbcba##aaaaaa#aaa#a###########a###aaaaa####adid#aaaaa##eca##addcbbaaaabbcddefddefddgiedccccffbaaaaaefeccbbbbbbbbbaabacdbbba####aa#a##a##aaaaaaccbba###.aa#aa#ba#a#aa#aaaaabbabcbccbcbcccegc######ba#a", +"abcbbccdedcbbbabdddcbabbbbbaa##aa#aaabaa######aaaaaaaaaaaaaaa#aa#######aa#aabcbbaaaaaaaaabcaaa###abaaa#aaabcbcb#aa##aa#abbaaaaaaaabbcaaaaaabbgecbbbbccbbbbbabcabbcbbbbaaaaa##############aaabaaaa#aaba#######a###########ba#aaa#aaa###aabffcaaaaaabeb####cdcbaaaaaaabbccdeffeeegihfddddffcaaaabefeccaabbbbbbbaaaabdba#aa####aaaaa###aaaacccbbba#######aaaa#aa#a##aabbbbbbbccccccccddgf#aa##a#aaa", +"aabcdddddddbbbccabcdccbaaaaaa#####bbaaaa#######aaaaaaa###a#####a#########aaaacbbbaaaa#accdddba#a#aaaaaaaaabbbcbaaaaa#aaaabaaaaabba#bdaaaaabeecbbcbcbccbbbbabbbbbbbabbbbaa#aa####a########aaaaacaabaabaa#######aa########abbbbaa##aaaa###aaegfb#aa##dcaaaabddbaaa##a##aaabcdfgffgiggfffedefea#aabffccbaaabbaaabaaaaacbaaaaaaa####a##aaaaaabbabaaa##aa##aaaaa######aabcbaabbccccbbddedeeaaaaa#baaa", +"aabbdeedeedddaccbbbcbcccbaaaaaabbaccaaa#a#aa###aa#aaaa#########aa#a#####a##babbbbbcbbcfdccccbbaabaaaaabaabbbccbbaaaaaaaaaabaaaaaaaaacfcaaabcbbaaababbcaabbbabbbbbaaacbabaaa####a##.########a#abd##baaaaaa##.###aa#######abbadb#a#########aaeiib####bca#aabadcba########aabccdgghgfeddddeedegdaaabdedbbaaabbabbaaaaa#cbaaaaaaaa#a##a#aaa#abbbbaaa#aa##aaaaaaa#####aaabaabbbbccbbbcdecef######acaa", +"baabcccddedddbacccbccdcbbbbaa####aa##aaa###a###aaaa#a#####aaaa#a#aaa###aaaaabbbbbabcgjfdccbbbaaaaaaaaaaaabbacccba###aaaaaaab##aaaabbbdfdbaabdecbbbabaabbbbbbbbbbbbababbaaaaaa######.########a#acdb#aaaaaaa######aa######abbccb####aa######afiifa###bca#aaaabcbba#a######aaabcdeefcbcedccccceffaaaaacdbaaabbbaabbabaaabcbbaaaaaaaaa##a#a##abbaaaa#ba##aaa###a####aaaaaaaaaaccbbbcccdeff.######aaa", +"a#aabbbcdeddcccbcccccdcbbabaaaa##a###aa#a#a#####aa##a###a##aaa####aa#a#a#aaabbaabbbbbffdccbbbabbaaaabbbbbabcbbbaaa##aaaaaaaaa###aabcbbcdfdaacebbbbbaaabbbbbbbbbaaaaabbabaaaa###aa############abcdcaaaabbaaa######aa#####abbbdc#############adghf###cdaa##aaaabbaa##.##.##aaabcdecedbbcdecbbbccebaabacdaaaaabbbbbbbaaaaabdcbaaabaaaaa##aa#aaabaaa#bcaaaaaa###aa#a#a#aaaaaaaaababccdceec##########", +"###bbbbcdeddddcccccbccbccbbbaaa#####.#a##aa######a##aaaa###aaaaa##a###aaaaaabbbbbbbccddcdcbbbbbcdbbbadecccccbcb###a###aaaabaaaa###accbbccfhcacbbbabbabbbbbbbbaaabbbaabbbaa####aa#########.####aabcbaaaabbaaaa#####a#####aabacfb###############dhhc.ddb###a###bbca#.#....##aaabcdccecbbccedbbcccedbabbdcbaaaaaaaabaaabaaaacccaabaaaaaaaaaaa#abaaabbcaaaaaa###########aaaaaaababbbceeda.#####a###a", +"#baaabbcdeddddddddbbcccbcbbbbaaaa################aaababba####aaaaaa###aaaaaaabbaabbdecbccccccbbbccccbcbbbcbbddeeca###aaaabccaaaaaa##abbbbcdedbbabbaaaaabbbbbbbbaaaaaaabbaa#######aaa##########aabbbaaabbaabaaa########aaaaaabdfb####aa#########cghhceba###a##aabaa#.....###aaabcdceebbbbbddcbccbcdcabcedbbaaaaaaaabaaaaaa#cddbbbaaaaaaaaaaaaaaaaccbaaaaaba#a#a######a##a#aaaaaaccdeed####aa####a", +"aaabaabccceeddeedcabbbcbbcbbbbbbaaaaa#########a##aaaaabbcbaa#aa#aaaaa#aaaaaaaaaaabbcddcbbbbbbbbbbbbbabbbbbbaabbdgfba#aaaaabbaaa##aaaaaabbbcceedaaaaabbabbbabbbbbbaaaaaabba#######aba#########a##abbcaabcbaabbba########aabbaabddca#aaaaa#########adjhaaa#aa#####aaa#...####aaabbcccfdabbbbbddcccbbccacffccbaaaaaaaaababaaa##bccccbabaaaaaa#aaaaabdcaabbaaaaa#########a#a#aaa###bcddhga####aa####", +"##aabbbbcdffeddeebdcbbbbbcbbcbcbaaaaaa##.##aa######aabbbbaaaa#aaaaaaa##aaabb#aaaaacddfbcbabbccbccbbbaabbaaba#abadfdbbaaaabcaaaaaaaaabbbababbceedaaaabbabbbbbbbbbbaaaaaaaaa##.#####aa#########aaa#aacdabbbaaaaaaaa#######bbbbccdcddbaabbaaa####aa###bhgea#######.##aaa#####aaaababbbcebababbabdeccbbbceffeecbaaaaaaaaabaaaaaaa#bcccbbbbaaaaaaababbbbbaaaabaaa#######a##a#aa#aaaaabddhg###########", +"#a#aaabcdddffdddeeedbbbbbcbbbbcbbbaabaaa#a##a##aacaaaaaaaaaa#a##aaaaacdaaaabaaaa#accdeaaaaabbbbccbbbbaaaaabbbababcdddcccbbaaaa#aaaabbbaaaaaabdeeeaaaaaababbbbbbaaaaaaaaaaaa###a####ba####a####aaaaaabecaa######aaa#####a#ababccccbcbabaaaaaaa###a####dijdb########a#a###aa##a#abbbbddbaaaaabbabdddcfeffffeccbbaaaaa#aaaaaaaaaa#abccbcabaaaaaaaabbaaababaaaaa#aaaa###aaa#aaaaaaaaabchga#####aaa##", +"#a#a###abccdddefdeeecbbbbbbaabbbbbbbbba#########abaa#aaaaaaa##a#aaaaaccbaaabbabbcbbccfbcaaaababbbbbaaaaaaaaaaaabbbabbabaabaaa#aaaaaabbabaaa#abcdfea#aaaabbbbaaaaaaaaaaaaaaaa#######bba##########aaaabcedbb#######aa#####a##abdcbbccbaaaaaa#aaaaa#aa###bgjjga#######aba#aadba##aabbbccbaaaaabbaaabedffeffffdcbbaaaaaaaaaaaaaaaa#aaaccbbbaaaaaaaaaaaababbbaaaa#aaa#####aaaaaaaaaaabbbghc#####aaaaa", +"a##a#aa#aabccbdfgeefeccababbbaabaabbbaa#a##.######aaaaaaabba##aa##abbbcbcbbccacbbdedgheccbbabbaaaaaaaaabbaaaaaaaaaaaaaaaaaacbbba#ababbbbaaaaaaabdeeca#aabcbaaaaaaaa#aaabaaaaa####.##ba###########aaabbceeba########a#########cbbbabbbaaa#aa#aaaaaaaaa###djkjb#b#..#abbcaaabcba##aaabbcaaa#aaaaabaacfffffedffccbaaaaaaaaaaaaaaaaaaaabcbbaaaaaa##aaaaabaaabaa#aaaaaaa#a#a#a#aaaabbbbccgc######aaa#", +"##aaaaaa##aaccbaeihfgggcbabbbaaaaacbbceceeca########aaaaaabaaaaaaaabbbdcccdebbcbbabacedecbbbabaa#aaaaaabbbbaaaaaaaaaa#aaaaa#abbbbacbbbbbbaaaaaaaccddbbbbbbbaaaaaaaaa##aaa#a##a#####aa#############aaabbceeea########a########aaaaaaaabbaa###a###aaa######agjkhgfb.#aabddaaaaaaa###aabdb##b###aaaaa#cffffeeeeeccbaaaaa#aaaaaaaaaaaaaabcbaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabbbbbdfeba####aaa#", +"#a#aaaaa###aacca#cjjhhjebcbaa##a##acegebdcbdb#.#cbcaaaaaaaaaaaaaaaaaabbcdgiecbbaaabbbcbcdcbbbbbaaaa#aabaabcbaaaaa#aa#aa#aaa###aaaaaa####a###aaaabcddbcbbbaaaaaaa#aaaa#aaaaa##a#####baa#.#######a##aabbcdddffa##.####aa##.####aaaaaaaaaabaaa###########a####chhiihc..ceffbabaaabaaaaabccaacc###aaccbbegfffededdccbaa#a#aaaaaaaaaaaaaaaabcbbaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabcccefeaaa###aa#a", +"aaa#abaaaa##aaba##eiiikhccbddefeeffgecccdccdeffefddc#aaaba#aaabaabbaaaabcdhfbbbbaaacdecbbaabbbcbbbbaaaabbbbbbaaaaaa#######a###aaa#aaaaa######aaaaaccbcbaaaaaaa####aa##aaaaa#####a##############a##aaabcccccdfb##.#####a######aaa#aaaaaaaaaaa##########aaa##.#aejjifb#cffacbbbaaa#acbbcc##ddda##cddeefgfffeedddcabbaa#aaaaaaaaaaaaaaaaaaacbbaaaaaaabbabbbcaabaaaabbabbbbabbbbbbbbbbbdfc####a##aa#", +"#aaa#a#a##a####b###dgkkjgccfiifdfdeeccddddcdcccccbca#aa##aa#aaaaabbbaababeggdbaaaaadfcbbbbbbcccbabcbaaaaabcabbbcbaaaaaa##########a#a########aa##a#accbbaaa#########aa###aaaa###aaa####.#########b##aabcbbcddfb###############aaaa###abbaaba#aaa#########aa#####djjjifbcebccdcba#bbacbcb##addccdcdeeefgfffeecbccbbbaaaaaaaa#aaaaaaaaaaaaaabbaaaaaaabaabbbbbaabababbbbbbbbbccccbbbbcced####a###aa#", +"a##aaaaaaaaa#a#ba..#agkgfecfikgddcccdcccbcccbcbcbbdba##bccaaa#bbccccbaabbefffcaaaabdfbbbbbbbbccaaabaaaaaaabcbbbabbbbaaaa#######aaa############aa###abbaaa####a############a####a#######.#####a##aaa####aaaacfa#######..######aaaa###a#cdcbbbabcbaa#aab#########.chiiihfcddeghhgdccdabdaa#addcddceefeeffeeeedbbcccbbaaaaa#aaaaaaaaaaaaaaaaabbbbaaaaaaabaabbaaaababbbbbbbcccdccdcbbceea####aa###aa", +"a####aaaabaaabbab#.#aaeecdhfijfcccddcccbbbbccbbbccaaa###.a#abccccbcbcbbbbbff#a###abcebabbbbccbcaabbaaaaabccbbbbbbbbbbbaaa#aa####aa##############aaaa#ababaa##############a#a######a####################aabbcacaaab#####.#.##abbaa###aaabcacbcaaaaaaa#aa#########.bgihiifcdgijjjiidaaabe#a#bdcbccccddddddecdecbbbccbbaaaaa##aabbaaaaaaaaaaabbbbbabbbaaaabbbbbaaabbbbbbbccdddedddefeffa####a#####a", +"#######aaaaaaaaaa#.#abcdaahkkjgbbcccbbbbbcbbcbbbbaaaa#a######abddedccccbbacffcbb##acccacdcabbdccdbabaaaa#abbbbbaabbbbcba###a############.##.###########ababaa##################a##a###.################aaabcbcdbbbaa##.#.#.#aabaa###abcdcaabaa####aa#aabbb###a###.#bgjhacegijjjjjjhedfgea##cbbbccbbbcccccdcccbbbccaabaaaaaaaaaaaaaaaaaaaaaabcbabaaabaaabbbbbaababbbbbbccddddedffceedb######aa###", +"aaa#a####a##aaa##a.##acda#cejjfdbbbbbabcbaabbcbbaa#aaa##a#a###baecbdfedddefhhgefea#cedbafecbbcbecbbccbbbbabbbbbbbccabbcdcaa####################.#######aaaaca##########################.########a######aaaaccccbbca#a########aaaa####bedcaabaa##aaaabaaabc########..#figefhikjihhhhiijiihd##bbcdbcccbcccddebcbbbbcdbaaaaaaaaaaaaaaaa#aaaaaabbcbbbbbbbabbbbbbbabbbbbccddedeedffa###a#####aaaaaaa#", +"###aa############a#.##bccbbbbehhaabbbaaabbabbcbaba#aaa#######becdda#fgecddeehghegdabdecaabedbcaacbbddbbbbbbcbbbbbbdbaaccccba#########a################aaaaabcaba###############################a#####.###aaaabccbcb##a######aab##a###accbca#b#####aaaaaaaaa###.####...diihiiihfgeffeffhijid##ddcdccccccddddccbbaabddcaaaaaaabaaaaaaaaaaaaaaabbcbbabbababbbbbbbabbcbccdddedefc.##########aa#aaaa#", +"#aaaaa#aaa##a######.#abbccaaaabgfb#ababa#aaaacbaaaaabbbab####edeefeccgedcddehhfacebadecaaaabcccbbbbcbabbbbbcbbcbccccccabccdb#######abb###a##############aaaacbccba##########a######.########a###a#########aabcceccb###a#####aaaa##aaaaacbb##ac######aaaaa##aaa#######..diihffffffdeddddefiigaaeddddbbcdddccdccbaaabcedbbbaababaaaaaaaaaaaaaaaabdcbaabbababbbbbbbbbbbbcceeegc.#############aaaaaa", +"aabcbbaaaaaaaa########bbcdbaaaaaffa#aaaaa#aaabbaaaabcdeddabaefcdddefcgfddddeghcccffddbaaabbbbbccbccdbcbabbbbbbcbbbbbdcabbbddb########bca#a#######a##a###aaaaaaabdbaa#aaa####aca##...###aa####a##a########aaabbbdecc##aaa############aa#abba##a#########aa#aaaaa########.bgiedcccdccccccccdhigdeeeeedcdddccbcebaaaaaaceebbbbbbbababaaaaaaaaaaaabcccccfedcbbbbbbbbbbbbabcfffe############a###aaaaa", +"a#aaedbbbbaaa#a#######abddca#aaaadcaa##aa####aabababbbccccfggcbcccccfgeccccdddffedfecddcbbbbccbbccdcddbbbbbbcbbbaabbcc#abaacba########aa##..#######aa####aaaaa###bbaaa#aaaaa#cc###a.####aa##aaa#########aaabbbbadcdaaabba##########a#aa#bbaa##a#######a#aa#aaaaaa#######.ageccbbbbbbbbbbbcbehigffeedddddccbcccbbaaa#accdcbbbbbbaaaaaaaaaaaaaabbcbccdbaadfdcbbbbbbbcbcefccba#################aaa#", +"#aaacbaabbcbbbaa#######abcca##aaabbcba########abbaaabaabccdcbabbbccbcedccccccccccccedbbcdbbbccbcbbcbcbbbbbbbbbbabbbbcccbbaaaaaa##a####a#aa####.#####aa##a#aaaaa##abbcaaaabbbabcaaa#.#.###aa#a##a########aaabccabbddbaabaa####.##.aaaaaa##bba##############aaaa##a########.#bddbbbbbbbbbaaaaabfhhgfeedddccbccbdabaaabbbccddcbbbbbbaaaaaaaaaaabacbbcceb#a#babcbbbbbbcbce##.####################aa#", +"aaaaaa#aaaababba#######abcccb#a#aaacddb######aaaaa#aaaaabbbbbbbcbbbbcdcbcbccbccccddbababcccccccccbbbbaaabbbbccbdcbbbbabcbbaa######aa#aaa############aa#####aaaaa#acbabaa#baabbcb#a##.#####baaa#########aaaabcdcccccbaaaa##########abaaa###aa##############a####aaa########.##dcbbbbbbbaaaaaaaabghgffedccccccbbcabbaaabbcbdedbbbbbbaaaaaaaaaabaaabccdecbcabbbcbbbbbcbeea###aa####################", +"aaaaaaaaaaaaaa##########acceeba###bbbcda#######a####aaaaabbbabbabbbbbcccccccccbcbbcdcbaabbcbcccccbbbbbcabbbbddegebbbbbbbcaaaaa#########a######aba#####aa#####abaaaabcbb#aa##abaaba#####a##aaaaa######aaaaaaacccccbccaa##a#######aa#aabaa##aaa####aa########a#aaaaaa###########addcbbbaaaaaaaaaa#fieeeddcccbbbbbaaabaabbaaabdedcccbaaaabaaaaabbaabbbcdebaaccbbdddcbbcdc#aaaa###########.########b", +"aaaaa#aaa#aa#############abcdfdaaaabcdf###aaaa##a#####aaaaabbccabbaaaabbbcccccbcbabbccbbbbbbbbbbbccbbcccbbbcdcdedecabbbbaaaaaaa########abb##aa#aaabaa#aba###a#aa#aabcccbabb###aa#aaa######aa##aa######aaaaaaaccccdaba###########aaa#aaba#aaaa#aa##a########aca##aaa######a######cffaaaaaaaaaaaaa#ehfeeedcbbbbbbcbaabbbbbbbaadeeefedcbaabbabbccbabbdcbcaabdcccccceedffb##aa####################a#", +"aaaaa###aaaaaa#####.####aabccfgbaabbcfeda##aaabaaaaaa#aaaaaaaccbccbaaabcccbbccbbbbbbcbbbbbbbcbbbbbcabcccbababccdeccbabbbbaaaaa#aa########aaaaaaaabedaa##a#aaabaaaaabaccbaaaca###aaaaaa#####a###aa###a##aaa#aaaccbbabaa############aaaaaaaaaaaaa#########a##acdaabaaaa############acecaaaaaaaaaaaaafhffeddcbbabbcbbabbbbbbbbaabbdeddfeddbabbbdcabbabbababbbcbcbccddffcdaaaa##a###################", +"aa#a#####aa#aaaa#########abcdcfeaaacbdccfcbbbdddbbbbbaaaaa#aaaabcbaabbbcccbbbcbbcccccccccbbcbcccbbbbbcccbbabbacddedcaabbabaaaaa##aa########cb##aa#cfdaa##aaababbbbaaaabbbbaabaaa#abaaa#####a#bbaaaa##a##aaaaaabbccdaaaaa#####bb#####aa##aaaaaaaa############aabbbbaaaa##aa##########deaaa###aaaaabcgiggddccccccccabbbbbabbaba#aabcaacccccbbcdbaacbbabbbbabcbcdddd####abaa#a##a#a#aa############a", +"aaa#####aa#a#aaaaaaa######abccdfa#bbcddbcccdcdaaccdecbbbbbbbaabccbaaabbcccbbbccbccccddccccccddccbbbbbbcccbbbbbcccdddbabbbabaaaa########.####bba##a#aca###aaaaaaaaaaaaaabbbaabaabaaabba#######ababba.##aaaaaaaaabcdcb#aaaa#####a##########aaaaaa#a####aaaa##.##abbba#aab#aba#aa#a#####cgeaa####aa#aabfiigdccccbccccbbbbaabbbbaaaaaabccbbccccdabcbccaaaaabbbccdebdbaaaaaaaaa#a######aaaaa#########", +"#aa#a###aaa####aa##a#####aabbbbeb#abbceeba#a####aaaba##cdbbbcccdccbbbbbbccbbabcbbbcbcddccccccddddddccdcabbbcbccbbbddcbbbbbbbaaaa#########.####aaa####a#a#aaaaaaaaaaaaaabbbbaaabaaaaaaba####a#.a##ab##.a##a##aaaabbddb##aa#####aa######.##aaaaaa#aa####a#aaa###abbb###acaacaaaa##a#####bff###a##aaa#aacghhfccbcbcbbcbbbbbbbcaaaabababbdccccddbbccccaaaaaabbccee##aaaabbacaaaa######aaa#aaaaaaa###", +"#aaa##########aaaaa########bbbbbea#babcea#a######aaa####bccddcddedcccccccccbcbccbbbcbcddddcccbbbcccdefedcbaacbbcbbbbbbbbababaaaa############.###aa#a##aaa#aaaaaacbba##abbcbaaa#aaa#aa#########a#######a##aa#a#abbcbcc#a############aa####aaaaaaaaaa#######aa###aabaa##bbaaaa#a##aa######dea#####aaaaaa#behhdccbccacbbbbbbbcbbbaabbabbbcdcccdddbbbba#aaaaabbddb#######bcaaaaaa######aaaabbbaaaaaa", +"aa#aa##########aaa########aabbbbbedbaabddcb#aaaa#aaaa####cccaacdeeggecccccccbbabbbbbbbbccddcccbbbbcbcddeedcbaaabbabbbbcbbbabaaaa###########.#####aba#######aaaaaabbba#aabbbbaa###aa##a#####.#a#.#.####aa##aa#aaabccbca#aa#..########a######aaa##aaa#########aaa#aaaaaabcaaaa##a##a###a#a#bdb#aaaaaaaaaaabcfhfccccabbcbbbbcbcbbbaabaabbabcddcdcccbba##a#a#abddb########aaaaa#aaa####aaaaaaaabbaaa", +"aaa#aa##########aa#a#a#######abbabgebaabacca#ba#aaabaa#########a##bdeddeedddcbbbbbbbcbabacdddcccccbbbcdcdcdcabbbbbbababbbccbabaa###############aaabb####aa##aaaaabbbaaaa#abbbaa###aaaa###a###a##....###a##aa##aaabbbca##aa#.#######aaa##aa######aaa#########abaabaaaaaacbaaaaaa##a###a##a#afb##a##aabbbaaaaeggecebcbbbabbbcbbabaabbbbbbabbdddccccccabaaaaaaccc#####a#aaaa#a#####aaaaaaabbbaaabaa", +"aaaaa############aa#a########.#abbcffcabbceccaaaaaaaaa###a###aa#######aaeebccccccbbbbcbbccbdddccccccbbbccbbbbbbbcbbabbbbbccbbbbaaa########.#aaa#a##aba#aa##aaabbbabbbaaa###abaaa#########aa##a############aa###aabcc#aa#aaa#######.##aaba#aaaaaa##aaaaa######baaaaaaa#aaaaaaaaaa###aaaaaa###ebaaaaaaaaaaaaabbfhgedbbbbbcbbbbbbabbbbbbbabbbbddecbcbbbbbbcbbbceaa#####aabca#a#a#a##a#aaaaaabbbbbaa", +"aaaaaaa####aaaa#aa###########..#aabdddbbcccccaaaaaaaaaa##a##aaa###aa#####eddedddcddccbccbccccbbcbbcedbbcccccbbbbbbbbababbbcbbcbaaaaa############a#a#aa#aaaaabbaabaabaaa#aaa#abaaa#######aaaa#a###########.#aab##aacc#aa####a######..##aa#aaabbaaa##aaaaaaabbaabaccbaa###aaaaaaaaaa##aaaaa##a#ccbaaaaaa###aaaadgggfeababbcbcbcbbaabbbbaaabbbccddbcbbbbbcdccccca#a#a###aaaaaaaaaaaa#aaaaaaababccba", +"aaabaaa#a#######a#aaa####aa###.###bcdcbcbabddbaacbbababaa#a##aaaa#aa#aacdccbddddddbbbbbaa#aaa######bfggfdcccbabbbbabaaabcbccabbaaaa#########a#aaaaa#######aabaaabbabbaa####aaaabaaa##aa##aaa#b####.#########abb#aaee##a###.##.##.###..####abccccbaaaaaaaaabcdaabbccba##a#aa#aaaaa#a#aa#aaaaaaaabebaaaaa#a##aabbfghhgedaaabbbccababcccbbbaabccbcccbbcbbcdcdcaaa########aaaaaaaaaaa#aaaaaaababbccb", +"abaaaaaaaaaa######aaa########aa####bbccbbaabceaa#cbbbbbba#a##aaaa#aa###debacb#aacabaa##aa###########.#afhgeecbccbbbabaacbcccbbbbbbaa#a#########aa#aaaa####aaaaaabbbbbbbaa###aaabbba###a##aaa###.#######ba##aaadbaabeaa##aa#..###.##########abaaabdbaaababababbaabddbaa##aaaaaaaaaaa#aaaaaaaaaaa#aecaaaaa#aa#aaabdghhhfecccbcbbabbacccccbbbbbcbbbbbcbabbdcbcba########aaabaaaa##a###aaaaaaaaaabbb", +"baaabbaaaaaaaaaaaa###########aaa####acccbaaaabcbcabbbbbbba#####aaaba#acbcaa#aaaa#abaa############.#####.dhihgeefccbbbbaabccbbbbbbaaaa##########a#aa#aa####aaa#aabaabcbbaa####a#aaaa###a#aaa################abbeebbbdd##a#######..####.######aaaaabcbbbbbbbbbbb#abcccbaaa#aaa#aaaaaa###aaabaaaaaaa#bcbaaaaaaaaaaaabehhhfedaaabaaabbccccbabbbbccbbabccbbbdcbbaaa#######a#aabaaaaa#aabaaaaaaaaaaabb", +"bbaaaaaaaaaaaaaaaaaaa#########a#a####bbcbaaaaabeecbbaaabbaba###a#aaa##cedb#aaabaaaaa##a#########.##.###a#bfgedeffdccccbaaacdccccbbaa###########aaa######aaba###aabaabbbaaaa#####aa#a##abbaa####.##.####aaa#acbddddfega#a#######.######.##a#aaaa#aaaaaaaabccddebaba#bcba##aaaaaaaaab#aaaaabbbcaabaaaaccaaaaaaaabaabbehhfgebaaaaaaacdcccaabbcbbcbbbbbcdcbbcaaa#a######aa#abbaaaaaa#abbaaaaa#aaaaab", +"bbbaaaaabbbaaabaa#aaaa###.#######a####abb#aa#a#cfecaabbaaaba#######aaa#bddcdaaabaaaa#a#aa######.########ba.a####bfddcccbbacdccccccaa############aaa######adb###aaaaaaabaaaaaa###aaaa##abaaa#####..#####aaaaabbcdeedfgd#aa########.#######a##aa#aaaa#a###a#abeedecc##aaba#aaaaaaaa#bbaaaaabbbbaaaaaaaaaccbaabaaababbadgggfdb#aaaaaabcbbbbbbccccdcaabbcdcccbaaa#######aaaaaaaa##aa###aaaaaaaaaaaba", +"bbbbaa#aaaabaaaaaaaaaba#a######.#######abbbca##acdedcaabca#a#.###a######bddcfcaabaaa##a##a#####...##aa####a####a#abbccddcbbddedccccbaa####a######aaa#####acb###aaaaaaaaaaaaaa###########aaa####.####a##aaaaacdeceeeedc##aa########..#########aaaaa##a###aaaaaabcdedcb##aa#aaaaaaaaacbaaaaabbbbaaaaaaaaadfdaabaaaabbbbcdggfebaaaaaaacccbbbbbbccdcccbbbdcecba#####a####abbaaa#######a#aaabbaabaabb", +"bbaacbabaabaaaabbaaabbaabb#.####.#######abbcba#aabecdbaccaa#a#.##aa##a###acacecbaaaaaa##########..######..abaa#aa####aceeddceggeddccbaa##########a#aaaa##aaa##a##aaaaaaaaaaaaa#########aaa####a#aaa####aaaabbdffffgebca#ab#######.#..#aa######aa###aa####aaaa#baabbdcc##b##aaaaaaaaabaaaaaabbbbaaaaaaaabcegcabaababbbbabgfgfdaaaaaabbabbbabbbcdddbcbccccdbaaa#a##a###aaaaaaa#########abbbbccbaab", +"baaabbaaababaabbaaaaaaaaaaa##############abbaa##aadd##abbaaaa#.##aaa##a####aabcbaaa#aaa###a######..####.#..cdcbbbaa###abdcdedfghffddcbba###########aaaaaaaaaaaaaaaaaaaaaaa#aaaa########a#aaa#####aaa#a#aabbccddghhhfcca#aa##########...##########aa#aa###aaa##aaaa#a#bb####aaaaba#a#aaaaaaaabbcbbaaabaaabbefdabaabbbbbbbbfgggfdcaaaaabbbbbbbccdbdbcbcccbcbba##aaaaaa###aa#aaaa########bbabbbbaaa", +"aa#a#aaaaaaaaaaaaaaaaaabbabaa#######.#.####aaaaaaabdeb#aababaa####aaa#abba#####aaaaa###a##bdba##a######....acdbabbaaaa#####cddaeggffedcba##########aaaa###aaa#abaaaababaaaaaaaaa##a###abaaaa###.#bbaaaaabdcddeefhhifdda#bb#aa##aa######..########ab##a###a##a#aaaa#abaabaaa#aaaaaaaaaaaa#aaaababbbbaaaaaaabcffbbbabaabbbaacefggdba#aabbbbcbacddccecbbbcccbba##aaaaaaaaaaa#a##a#a#######aaaabaa#a", +"ba###aaaaa#cbaaaaa#abababa#a################aabbbbbbbea#aaabbaa#####a##adc##aaaaaaba##a####a########.#####...aca###########.####cffdcdecaaa#######aaabaa##aaaaaaa#aaabbbaaaaaabaaaba##babba######accbbbbbfccdeegdgfggeb#dc#####aaa#####...#######aaaa#aa##a#aaabaaa#bbaaaaa##aaaaaaaaaaaaaaabaabbbbbaaaaababbegdbbaaababbaabffffecb#aabbbbcbbcdddecbaabcbaaba#aaaaaaaaaaaaa###a########a#abbaabc", +"a#######a###aa#abaaaabbccba###.##############abcbcbbcbea#aaaaaaa#######.##ba#a#aa#a#a#a##a####.###########..###ba##############a#aeedbadfcdddcbb##aaaaaaa#aa#aaaa#aaccbbbaabbbbbabcbbcdccb######abcdbddeeefddddb#afdcfebdca#####aaa######.#####aaca####abaa#aa#abcb#accaaaa##aa#aabbaaaaaaaaaaaabbbaaaaaaabbbbbgdbaaabbbbaaaccffgfdcaabbccccccddddfcbaaaaaaaaa#aaabbaaaaaa#a#aab####aa##aaa#bcc#", +"aa###########aa#aaaaabbabbaaaa##..###########abdcccccbcdcaaaaaa#a##########aabb#abaa##########...#.########.######################.bfdaaccefddddbaaaaaaaaaaaaaa#aaababcccbbbbbccbbcddcabca####aaacdcabeggfdda.##.#cc#aefdbaaa###aaa###.##.####aaaaa#a###abd##a###ababbdc#aa#aaaaaaaabaaaaaaaaaaabbcbbaaaaaaabbbbgfbaaabbbbaabbbcefffddbabbcdccccedcabaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa#aaaaaaa", +"aaaa##########a######.#a#abbaa##########a####abdedcccccccba##########a######aaaa#abaaaaa#######..################aa#aa###############ddabedcgededbbbaabbabaaaaaaaaaaabbccccccbccdddba###abacbbcccba####aaaaaaaa##.###acfcaaa##aa#a############aa#####a#a##aea#aaa#aabbcda##aaa#aa#aaaaaaabaaaaaaababcbaaaaaaaabbbgfbabbbabaabcdcbdefffdbbcccccccdda#aaaaaaa##abaabbaaaaaaaabbbaaaa####a##aaaabaa", +"aaaaabaa#######a###a##.###abbaa###############acdeccbbccdga##########a######.#aabaaaaaaaaa#a############.###aa###aaaaa###############.cdbbdefhhhfdccccbbbaaabaaaabbbbbccccdddcdccdb#####bbcbcddba####aa####a#a#####.##aedaaaa###aaa#######..#########a###a#bbbbbaaabbbbaba#aaaaaaa#aa#aaaabbaaababbabccbaaaabaabbbggdabbbbcbbbddcbcbdffdcaccccacccd#aaaaaaaaaa#abbbaaaaaaaabbabbabaa#aa####aabaa", +"aaaa#aaa##########a###.##aaaaaaa####.##aa#####abccdcaabccffa##########a###aa####aabaaabaa#aaa####a######..###a#####aaa############aa###bdddeeddfgfeeeddcabaaabbbbbbbbbbcdddddeeeecaa####abbaaaa#######a#a########.###aaadaaaa#####aa########.#..##.##a######aaabbba#bbca##a###aaaaaaaaaaaabbaaaabbbaabddcaaaaaaaaabfgdaaabbbabdacdbcbdfffdbbdccbc#cbaa##aaaaaaa#aaaaaababaaaa#abbaaaaa#aaaaaaa#a", +"###a#aaaaaaa######accbaaab#####aaaa####a#######accccabacccfe##.############aa####aa###aaa#aa####.#########.##########a############abca##bfcfabbbcaafffffdbbbbbbbbbabbcccdeeedefcaaaaaa##aaaaaaaa################a#.###abbcaa#aa#aaaaa#######....########aa####a#abba#bbbbaaaaaaaaaaaaaaaaaaabcabbbbbbabeedaaaaaaaaacfgecaabbabbacdbabcffffccccdda##aaaaaaaaababaaaaaaabaaaaaaaaaabaabaa##abb####", +"a########aaa#######cddebba########aaaaaa#######abccccbabcdefea#.########aaaaabb##aaa#####aaa##.....#.##.##############a#####.#####aabcbaabfc######.afggggcbbbcbcccbbbccceeeeffhgccbaaa#aaabbaa#a######aaa########a#.##aacdba##ab#aabb##.#.####...########aa#####aaaaaaaabbaaaaaaaaaaaaaaaaaaccbabbbbbbabefdaaaaaaaaabeffabaaababdedabbcfffecccddaaaaaaaaababaaaa#aaaabbbaaaaaaaabbaaa#aa##ba###b", +"#####aa#####aaaabbaaaacdb.#a#########aaa########abcbbbbbcdeeeefc.######aaaabaacbaaaaa##########..#..#....##############a###########abbbba#bd#a######aabbcfedccdddccccdddeeeeefgiedeebaaaaaabaaaa#aaaaa#aaaa###########aabcca##aabaaabba#....#....##.###.#aaa#######a#abaabbaaaaaaaaaaaaaaaaaaddbbbabaabbbddaaaaaaaa##adfecbbbbacddedbbccdffdccddaaa#aaa#bbaabca##a#aaabbaaaaaaaaaaaabb#aaaa###a#", +"####aaba######aa#abbaaaba###aa#############.####aabcabcbbdegfebc.########abbbaaaaaaaaaa#########.....#.#.######.#######aa#####.#.##aaabbbbbc##a#######..##ehfeeeedddcedeffeeeeehf#abcecccbabbbbbaabaaaaaaaa########a###aacdba#aaaabaaaaa#..##..##.#..####aaa##a####aa#aaaabaaaaaaaaaaa#aaaaaabeeccbababbbbbaaaaaaaaaaaabcffbbbbcdccdcbbbcdfgfedcabaaaa##bbababa#####abbaaaaaaaaaaaaaaaa#aaaaaa##", +"#a###aabaaaa###ba###ab##ba###a#############..###aaabcaabbdedefgb####aaa###aaaaaaaaabaaaa###########...#.############################aabbbadcaaa#####.######bfhhgggffffffffeeeefhhcaa##acfffeedddbaabaaaabaa########a####abebaaaa#a#a#aa############.###..#aa##a###aba##aaaaba#aaaaaaaaaaaaaaaaccdcdcbbbbabbbaaaaaaaaaaaaacfeaabbbbccdabccbdfffed#aaaaabaaaaaa#aa###aaaaabaaaaaaaaaaaaaaaaaaaaa##", +"###aaa#aaaa#a##.a##a#aba#aa###########.#.#....####abcbbbbccdffegb...##aa###abaaaaaaaa#a#aa#######aaa###.####.#####################a##abbcfda#aaa###########.#acfhihhhijiiiihgfhhgcaaaa#..acccddccecccbaaabcb#######aa###abcdbaaaaa#aaa#aa##########.##########aa##aaa#aaaa########aaaaaabaaabbaaababaacbbabbbaaaaaabaaaaa#cefdabbbabbcbbbccdfggeb#aaaaaa###aaa#a###aabbaaaaaaaaa#aaaaaaaaaaaaaa#", +"#aaaaaaaaaa##aaaaaaaa#aaaaaa##.###aa###.###...####aabdbbabbcfeced.#########aaaba#aaaaaa##ca#######aaaa######.########.########a#####aaabdhgfeaaaa#############.#aaba#addfghiiiiheb###aaaa###.####bdbcdcdcbbca##a##a##a##aabbdbaa####aaaaaaa#############a#.##aaaaaaaaa##aaa##a#a#acbaabbabbbaaaaaaaabbbbbaabbbaaaabaaaaa#a#bfgebaaababbbbbbbcggfeaaaaaaaaaaaaaaaa####aabaaaba###aaaabaaaaaaaaaaa", +"a##ba#abaaaaaaaa####aa###bbaa##.#######b#####.#.###aacbbaabcdeccc##.########aabbba#a##aaa#bba######aaaaa#################.######aa##aabbfhhihdabaa##############aa######.##a#bgfb###aaaaaa########cbacccdfeecaa###aa##a#aaabcdbab##ababaaaaa##########aaa#####aaaaaaaa#a#aaba##aabfdaa#aaaaabbbabaaababdbbbbbbbbbbbbbaaaaaaa#dffcbaabbbbbbbbbcefgdba#abaaaaaaaaa#aa##abbbaaacba##a###aaaaaa##aaa", +"aaaaaaaaaaaaaaaaaa#####a##aaaa########ab##.####..###aadccbbacdcaa###.######aabaaabb#aaaa###############aa#####a#####.##############aabbbehhhfcaaaa#####.########aaaa##aaa##a#.#caa####aa##########cdbbbbbcedefdcbbaa##aaaababbdbaaaaaaaaa#aba#########aa######aaaaaa#a#aa##aaa##addbbaaaaa#aaaaabaaaaaaccccdcbbabbbcbaabaaaaa#cfgdbabbbbabbbbbcfgedda#aaaaaaaaaab#a##aabbbaaaba#aa###a#aaaaaa#aa", +"aaaaaabaaaaaaaa#accb#########babaa###aaa##.##a##.####abcbccabdeaaab#..######aaaaaaa#####################aaa####a#####.############aaaabdgihgcbaaa################aaaaaaaaa#aa###a######a##########dbaaaaaaaacbcefgfddcccddegdcbdbaabaaaaaaaaaaa######aaa####aaaaaaaaa#############aaaaaaaaaaaacaaaaaaaaabbbbdeccdccbbbbaabaaaaabefecbbbabbbbcbcegededcaabaaaabaaaaaa##aabbbaaaa#aa#aaa#bbaaaaa#a", +"a##a#aaaaaa###aa#bbcbaa##aaa#aaaca##abb########a#####aacbbccbdeaaaba#########aaa##a#a####.################ba#########.##..######.bbabaaehhhgbaaaa#################aab#aabaa#aa###a##########a.###.ab#aa#abababbbcbcdcaacecccdefdc##abaaaaa##aa########aaba#aaa#a#aaaaba#a#aa#a##.##abaaaaaaaaabbabbaaaaaaaaaaccbbbcdbbbbaaabbbabbdgfdbbbabcbcccdddeeedcaaaaaaaabaaaaa##aabbaaaaa##aa####aaaaaaa#", +"####aaaaaaa######abbcca##aaaaa##abbabba#a#####aaa######aabccedfaaaab#########aaa###.#######################b########.#ba#...##.#acbccccfgggebaaaa##a###############aababaaaa#a##a#a####a##a########c#aaaaaaaabbaaaaabccdebabbbdgeaaabbbaaaaa##a#######aaab##a##aaaaaabaaa###aaaa####ba#a##aaaaaabbaaaaabbaaaaacbbbcbbbcbbaaabbbbcbcfgecbcbbbccddccceddccaaaaaa#bbaaaaaaaaaaaa#aaa##a#aa#a#aa####", +"##a###aaaaa#######aaaaaaaaaaaaa#aabbcaaaaa#a###aa########aabeeea###aaa#######aabb#####a######.#######aa##.######aaaabedccbbb##bbbbaabbbbccdeaa##a##a########aaa#####aabbbba#a#aaa#a####a###########caba###ababbbaabbabcdcddcbabehcaaaaaaaaaa############ab##aaaaaaaaaaaaaa#baaaaa###bb#a##aaaabbbbbaaaaabbbaabbbbcccbabbbaaaabbccccbfffcccbccccbccccddeedaab#aaaabaaabaaabaaa###aaa###bb##a#####", +"aaaa##aaaaa#aa#######a#abbaaaab######aaaaa#aaaa#aa#######aabdefb#aaa#bc#######abcb#####a#################aa#a..###aabcdfffggfdcbbbbbaaaaaabdeaaa###########aaaa#####aabbbbbaaa#aaa#####aa#a##.#####aaaaaa##abaabcbbbaaabaabbbbcdefaaaabaaaaaa##a######aaa######aaaaa#aaaaaa##aaaa###aa#aaabbbabbaabbaaaaaaaabbbbbacccbaaaaaabbccdccdefegffdccecbccccdeeddcbaaaaaaabbbcbaaabaaaaaa#######aa######", +"#aaaa##aaaa#############abaaaaaba##aaaaaaaabaaaaaba#####a##abdgca#aaadeb########bba#####aa#aaaaaa###aaa#ab#aa#.###.#acfhfddgccbaa#aaaaaa#abcfaaaa#######aaabbaaa#####aaaaaaaaa#aaaaa#aaaa##########aaaa#aa##aaa#acccabaaba#a###acdbaaaaaaaaaaa###a##.##aaaa###a###aaaaaaaaa###aaaa#abb#aaaabbbbbbbabaaaaaaaaaacbbbccbbbbaabaaacccccdfdbdfgeefcddabccbcedddccbbaaaaaabbbababbaa#aaaa#a##ab##a####", +"##aaaa#############aa#####abaaabda##abaaaababbaaaaba####aa#abbdeaaaaaadf###############a#aaabbbbba#aa#aaaa#baba.#accbffffgddcbbaa#####aa##acfeabaaaaa###aabcdcbba######aaaaaaaaaaaaaaa#aaa##########dbaa########bbdcaab#abaaa##abceaaaa#a#aaaaaa#a###.######a#####aabaabb#aa#####a#bcbaaaaa#aaaabbbbbaaaaaaaaaaccccbccabacaaaabceeeeggdcdfffccccca#bbcbddeccccca#abbbbbbbaaabaaa#a#aaaaab#######", +"##aaaa####.##########baaa##aaaaabda#aaaabbaaccbaaaa#####aaaaabbcbbaaabdgfe###aaa#######a##aaabbabbb#a#a#aabdceeedcabcaeddcfhecdb#########aacdhcbccbbbbbbbbdehhedba##aaaabbbbbaaaaaabbaaaaaaa########cba#######a#abbda#aabcbaa##aabceaaa######aaa##aa########aaa##aaaaaa#aaa###.###aabaaa#aaa#aa##abbbaa#baaaaaaabbbbbbdbbabaaaacaddacbbbbddccccbbda#cbbcdcddeccccbaabbbbca#aabaaaaaaaaaaaaa#####", +"#aa###a####.##########aa#a##aaabaccaba#aabbaccbaaaaaaaaaaaaaabbccabaabeffeebbcb#.####.#aaabbaabbccccccccdddcec.#aaaaaaadccbbcccca.#######aabdhecdddeeeddeefecbbeedcaaaaabbbbbbabbbbcbbaaaaaaaaaba##aba####a####aacdccaa#ccbbaa##aabcdaa########a##aa########aaaa##aaaaa##aaa#########aaa##aa#aba#aabbbaaaaaa#aaaaaabaaaccbaaaaabccababbbb###bcbcbbecabbccdcddcdcccaaababbbbaaaaaaaa#aaaaaaaaa###", +"#aa#aa##########a######a#####aaaaabc#abaaaabbcbbaa#a##aa#baaabbbbbabbcfffgghebdcbbacacbbbbbbbcbccdccfdaaabdedcaaabaaaaacccbbbbbbcb########abcfgedeffeeeegfcbbcbadgdddaabbbbbbbbbbcccccbbaabababbbaacbaa#########abcccbabccbbbaa##aabcb#a#######aa######a#a##abbbbabaa###a#aa########.bbaaa#aaaaaa#aaabbbccbaaaaabbbbbbbaaaaaaaaabbbccccaaa###bcdbabcbbbabcdddcbddccbbaaaabcccabaaaa#aabaaaaaaba#", +"#aaaaa#######a####a###aa##.###aaaaabc#abaaabbcbba###aa####a#aaabbbaabcdcdeccdecccccba##aaabbaaaaaa##beaaabacfdeaabdecb#bdcbbbbbbaca#######abcdegeeeeffgfdabbccddeehhhfdbbbddeeccdcccdccbbbbbbcccbcca##a###a########aa#.aceccbbaa#aa#acb###.#####aa#####aba###abcdcbcbaaaaaaa#####a###bc#abaaaa#aaa#ababbbbccbaaaaabbcccbcbaaaaaabccdacccb#a###abddbbbbbbabbcebcbbdcccbbaabbabcabaaaaabcbaaaa#aaa", +"aaaaaaaaaaa####aa#####aaaaa.###a#aaaccaaabaabccaa##aa#######aaaaaaaaadc##abaaaaa###a#######a#########cb#aaaacdddb#bbdda#becbbbbbbac#######abceffhffffda##babcccdeeddbddeecdcdebdeeccdddeddcccdeba#b###aa##a#########a###bedbbbbaa#a##aca###.#####aa####aaa####bbcdddbaaaaaaaaa#######adbbabaaa##aaaaaaacbabbccbaabaabbccccaaabbcbdcbcecccaa#a#a#adcabbbbbcbbcbccaabccdcbbbbcacbaabbaabcbaaaabaab", +"bdbaaaabbaaaa#aa##a#aba#############abcaabababcba##aa#########aaaaaaabdb##aaaaaa###a##################b####aaccdeaabcbbaaeddbabbbabb#######bdfhghhgda###aabbcccecbbbdcccefdbbcbcb#eefgghggfeegdaa##a###aa#######aaa#####bedcabbaa#####acb##########a##aaaa####acbccccaaabaabbbba####a##dbba#aaaaa##aaaabdababbccbabaabbcddcbacbbccdacdbba#####aaaabcbbbbbbbccbbababbcddcbabbbabaaabcaaabaaacabaa", +"aacdbaa##.##a##aa#aa#aba###.#########abca##aabbbca#..###########aaa##aab######aaaa#########aaa#a###aa#######aaccdfbabbaaaeeddbbcbbbdbaa#abcdfhjigca######abccbadb###cfbcbbecabbba#begfhggddcggdbbaaa##############a#aa#.cddccbaaaa#####ab##########aaaaaba####accbbbbaaabaabbbabb#######aba###aaa#aa#aaabcaaaaabccbabbcccdedcbdbbacdcdccaa##a#aaaaabcbbbbbacccbaaaabaccccbaaaaaaaabbbbaaaaababba", +"aababbaa#####a##a##a###a####.##########aba###abbbbba####.#.#######a###aab######aa#a#########aaa#####aaaaa#####bbceebbbba#ceedccedcegdcbcddedbcbed#######aabccdbdda##adeeb##abbaaaaacbadeddfdghdcbbbaaa###########abbbcdbbdcbbca##aa#####bd###.#.###aaaaaaaba##abbbbbbbaaaaaaaabbaaa#######aa###aaa#aaaaaabcaabb##abcbbaabcedccdcbaaccccba####a#aaababcbaaaabbccbbaaababccbaa##aa##aaabaaaaaaabaa", +"aabaaaaa#a#####a###aa##########..######aaba####aaaabb#.###############aaab##.###a#a#######aaaaaaaaa#a#aa###a##aacdceddfgfcfffgdccdeeefggdbaabbbbdcaa###aaabbcddeb##a#adfeaaaaaaaaa#bbaaccbeedhecbabbaaa#########.adccbcdbdbbcbba#######a#cda########abbaaaba##abbacbbaabaaaaabaaaaaa########aba##aaaaaaaaabcaaa#a##abca#aaabdefecbaadbbbaa##aa#aaaaaabdcbaaaaabcbaa#aaaabbbaaaaaaaaaaaaaaaaaaaaa", +"aaabbaaa#########a##aaa###########.##.##aaaa#####aa#cba################abcb.####aaaaaa##aaaabbabaabbbaaa##aaaaaccgghggecdfihhg#a####a#a#abbccccacdcabbbbbacccdfeba#####aaaaaaa###a#ababbccadcgedccbaaa############ccbabccbcacabaa#####a#bacd###.####aaaaaaa###aaabbccaaaaaabbabbaaaa###.##..#bbb###aaaa#aaaaaaa########a#aabccceecbbdbbbbaa#aaaaaabbaadccbaabaabba#####aaaabaabaaa##aaba#aaa#aaa", +"aaaa#aa##############bba##########..#.############aaaaaa#####.##########abca..####abaaaaabbbcccbbccddbbabbbbbcdefebdfd##a#.bedaa#########aabbbcbcddddcbbbcdeffd#########aaaaaaaa#aa#baaabcbacegedbbaaa##########bcdbaabbcccbbbaaaaa#####abbcca####.##aaa####aaabbcccdbaaaaaaabaaaaaaaa####.###abba##aaaa#aa##a############aaaa##cfebdcabcb###a##aaaabbabacbaaaaaba#a####aaa#aaaaaaa####aaaaaaaaa", +"abbaaaa####a##########aa###################aaa####abaa#a################aabc#.#####aaaabbbcdddcdfffefgffeddfgdcdcb####aaaa###bb#######a##aabacdcddbdccacdefecc#a##a#####aaaaaaaaaa##aaaaabbbabfgdcbaa########aaacbbbbabbbbcdaba##a#####a#abccda####aaaaa#aaa#abaaaccbbbaaaababbaa##aaa#########bbba##abaa#####aa#a##aaa#a###aaa##defdcabbbaa##aa#aaaabbbaaccaaaaab######aaba#aaaaab####abaaaaaaa", +"aaabaaa#################abba###############aaaaa##aaaaa#a###############aacaca.#####aabbbbccddfda#adeca#####b###aa#aa#aaaa##aaba#a####aa#aabccdccedebaacccb####aaaa###a###abaaabaaaaa#aaaaaababdgdbb##########cabbdbbbaaaaaccaaaaaaa##aaa##acdc#.#aaaaa##a##aabaa#ccaaabaabbaaacbb##abaa######..abca##aaaa#####aa#aaaaaa######abaabdggcaaa#aaaaaaaaaaacba##bbaaaabba#aa#aaaaa##aaaba###aa#aaaaa#", +"#########.#################aaaa#.#.##aaa###aaa##aaa##a##aa###############abbbba#.##.#aabbbbcefc####...#####aa#####aa###aa####aa#######a#aaacbacbbdddbbccdfecbcc###aa####aa#aaaaaa###aaaaaaa##aaacfdaaa#####aaaabbabbbbaaabbabbaaa###aaaaaaa#abce..##ababc####aaaaabdaabbbbbbaaabbbaaa#a##.#######abaa#aaaba##aaaaa#a##aaa###aaa##ababehcaaaa##aaaaaaaadc####abaaaaaba###aaaaaaa###aaaaa#aaa#####", +"####a######################aab#....##aacaaa#aabbaaaaa#####a##############aabbbcb##.###abbcceca###################aaaaaa#a#aa##a#aaaaaabaabbbbbacaaabbabaafddcbcb###aaa#aab##aaaa######a#######a##cfeaaa#####abcbbbbaaaaaabbabba###aaaaa#aaaabaaee#.##ddaaa####aaaaacaaabdcbbbbaabaaba#aa##.#######aaaa#aaabaaaaaaa##aaa#a##a#aaaaaaabbcgebbba#aaaaabaabbaba###aaaaabbaaaaaaaa#aaa##aa#a##baa#a##", +"####a##aa##################aabda#.#####bcaa#abaabaaaaaa###################aaabcdb.####bbbdea##########.###########aaaaa##aaaaa##aaabbbbcbccbbaaaaaaaabbbaaaacdcbbbaaaaaaaabaa#aaa################abecaa####aadcabcaaaaaaabbaab#####aab#aaaaabaaade#..#ca.#a####abcbbb#abbccaaabbbabbbb#a############aa#aaaaaaaaaacaa##aaa##a#aaaaaacabccfebbbbaaaaabbbbaaba####ababacbaaabaaaa##a#aaaaaa##aaa###", +"#####aaaa###.#a######a#######aab##..####abbbbbbbbaaa#aaa####aaaaa##########aabddea.###abda#################a#########a#####aaa###aaabbcdcbdbbaaaaaaaaabbbaaaaacddcbaaaa###abaa######..############abeda###ababbbccbaa#aaaaaabaa##a###ab#aa#aaaaaacec##ab.########babbaaaabbababababbcda###############a#aa###aaabcbbaaaaa###aaaa#ababbcdcdecaabaaababbaaa#######aaabbbbaaaaaabaaaa######a#aaaaa#", +"a#######aa#a######aa#a#aaa###aaac#########abddccbbaaaaaaa####aa#aa########.abehghhc##abca##aaa##################################a#aabccb#aabaaaaaabbbaaaaaabaaabbbdba#aa###aaa##################aa#abefccaabbbcbabbaaaa#aaaaaaaa#aa###abaa##aaaabbcfdaba.#a######bacc##aaaabaababaabcbca##.#####a#####a#aaa#####aaaaab##aa##aaaa#aaaabccebbffbaaaaaabcaa###a#####bbbbbbbaaaaabaa#aa######aa#aa#a", +"#baa#aaaaa###a#a#aaaaaaa####b#aaba#########aacbdcccaaa##a###aaa#aa##########bbfikjicacc###aa#aaaa#############a###################aaabccca##aaaaaabbaaaaabbbbaa#aabcbbaa####a#################a#aabaabdfbdcccbbbbbbbbaaaaaaaabbaaaaa#a#aaa#aaaaaabbcfdbb#######a#aaac##a#ababaaaabbcdaaaa##########a#aaaa#a#aa##a#aaaaaa#aaaaaaaaaaabbccdcaaegcbaaaaacaa#####a####bbbbbbbaaaabba##a###aaaaaa####", +"####aa#aaaa##a#aaaaaaaaa##a#####aba##########aadcbbba####a####a#aa##########abcdfhiigc#a##aaaaaaaa#aa#####################a#######aadccccaba##aa#abaaaabbbcaabaaba#aaaaaa####a###a#a###.#####acbbcbaabcehfdccccbbbbbbbaaaaaaabaaaaaabaaaa###a#aaaabbcddca####.#####aa##aaacbabbbbaabcba#bc############aaa##aa##aaaaa#baaaaaa#aaaaaaaabccdeba#cgfbaaabca#a###aa#a###bcbbbbbbaabbba##b###aaaa#a###", +"###a#aaaaa#aa######aaaaaaaa######aaaa#######a##aaaa####.###aaaaa#a###########abacdhiiga##abbaaaaaaaa##############a########a##a##abbcabc#abbaaaaaaaaaaaaaacaaabaa###a###aa###a###aaa########bbbbcbbbbddceihebbcbbbbbabbaaaaaaaa#aaaaaab#a#####aaaabbcccfb#.########aa##abaaaaaaabbaaaabbcbc#####a######ba##aaa###aa###aa##abbaa#aaaabbbdcccbbabdhebcbaaaaa####a#####accbbbbcbaacba#aa###a#aaa###", +"#a####a#aaaaa#aaaaaaaaaaaaaa#######aba#######a####ab########aaaa##a#a##.#..#####aehhjihb#abacba#aaaaaa############a#a########aa#aabdcc####abaa##a##aaaaaa#ababa#a##aaaa#######a#aaaaaaaa##aacaabcccbcbabbcghgdbbabbbccba##aaaaaaaaaaaabaaa####aaaabcbcdccaa#########.##aaaaaaaaabababbabaa#######a#a##abbba#a######a###aa#aaaaaabbaabbcdbbbbabbadffbbaaaaaa#a##a####aabcbbbccabbabaaaba##baaaa##", +"##aa###a#aaa#a##aaabbaaaaaaaaa##aa###a#############bba#.###aa#aaaaaa#######.####adfehjif###aaaaaaaabbaaa#a########aaa###a######abbbbcca.###a###########a###aa###a#############aaabbbbbaaceb#aaabbbccbaaabbbdggdcbbabbbbaa###aaaaaaaaaaba#aa#a###aabbbbcdc#####aa#######aaaabbbaaabbbbbbba#aa#######a##aabbaa#######aa###aa#aaaaaabbbbbccaaccbbbccdfgedaaaaaaaaaaaa##aaaccbcccbbccba##aa##abaaa##", +"########a#aaaaa#aaaaaaaaaaaaa#aa#ba###########a####aaaaa#.##aaaaaaa##a#a########bbceeijfc####bbababaaaaaaa#########aa##a#aaaaabbadcccba####.############aaa#aa#############a##abbabbbaa##ceaaa#aaaabbbaaaaabbdgfbbbbbabba####aaaaaa#aaaaa#####a#aabbbccdccca#aaaa######aaaaababbaaabcabba##ba##a##a#aaaaaaaaa#######a#a##aaaaaaaabbbcccaabbddcaabbabdffdbbbaaa#aa####aabbccbbcbbddbaaa####acbaa#", +"#######aa#a#aabbaaaaabaaaaaaaaaa##aa#a#############abaaaa####abb###aaa#a########babcfhiiea###acbbabbaaaaaaaaa####aaba#aaaaa#aaabaccbcbaa###############aaaa###a##############aabaaaaaa####bbbabaaaabbbbaaaabbbcffbbbbbbbbaa##aa##a###aaaa####aa##aabccefcadda##aaaabb#aaaaaaaaaabbbbbbbba##abb######aaaabbba###############aa#aabbcccbabbaabdccccaabacfggccbaaaaaa##a#aabccbbcaabdbacba####bbaaa", +"aaa####aaaaaaaaaaaaababaaaaaaaaaaa#aa##############abbbbaaaaa##bbbaaaaaaa######ab#bccehiic###abcaabbbaaaa#aaaaaaaa#aaaaaaaaabcbccacba########.##########aa###############a#aaa#aa#a##a#####acbddcbaaabbbbbaaaabbefcbbbabaaaaaaaa######aaa###aa#####abcdghedcbbbbbcccdcbbaaaaaaaabbbbbbabaa#.acca#a###aaaaaaa########a##a###aaabbcdcaaaaaabbaccddaaaaacaadggfdbaaaaa#aaaaaabccbbaacbaababaaaabbaa", +"aaa#a#####aaaaaabaaaabbbaaa#aaaaaaa###aa#######.#a###abbbaabbbbaaaaaaaaaaaa####a##ababchie###aabbbaaaaaa#aaaaa#aaaaaaaaaaaabccccbccb####a#############aa######.###########aa###aa#aaaa#a###abcccdbbbbaaaabbaaaabbceebbaabbaaaaa#########aaa##aa#####acdfdefebcddcbbdffdcbaabbaabbbbbcdbbaaa##abca#####aaaa#a##a#aa####a#a##aabbdedaaaaaa#aaccbeda#aabbaaaacefgfdbaaaa#aaaaabcccbccabaaabbaaaacc#", +"##a##aa###aaabbbaaaaabcbaaa#aaaaaaa#a##########a#####aabbaaabaabaaaaaabcccca########aaacfhc##aaabccba#aaaaaabbaaa##abbababbcccbeecba#####a########a####a#a#####.##########b######a##a##aa###aababaaabbaaaaabaaaaaabdfcababbaaaa##############.#######bddcbdeffcbbba##dihdcbaaaaacaabbbdcaaabaa#aba#####aaa######aa##a###aa#abcdccdb#aa###aaaccdcbaaaaaaabbaaabehhebaaaaaaabaccbcbbbaaaaaaaaaaacb", +"a##aa#####aaaabbbaaaaaababaaa#abaaa#############.###aaaabcaabaaaabbbbacdedaaaa######a##bccdccaaaaaacdcaaababbbaababbbccbcbbcdcceedc####a##a###########a#aaa######..####.####.###aa######abbaaaabaaaaaaaaaaaaaaaaaaaacfeedbbaa############.######aaaa#abbaaaaccbabaaa###igdccbbbaaaaaaabcbabcbcb##a######a####a#aaaaa####aaaacb#abdcaaa#a###a#acddcbaabaaaaaaaaadfhhedaaabbabbcccbbaaaaaaaaaaaaaa", +"ba##a##a#aaaaa#aaabaaaaaaacaabcbaaaa#aa#########.#########aaaaaa##ababdefcab#aa########aabdfgbaaaaaacdcaaabaaaaabbbbabbcbbbcccddaaaa####aa#aa########a#aa#########..##.##..###.###aaba###aaaaa#abaaaaaaa#aa#aaaaaa#aaaegdcbbbaa###########.######aaa##aaaaab#abaaaaaa#.febaaabcccbcbbcbbaaadbcecbaa#####a#aaaaa###aaa#aaaaabaaaabccaaaaaa#aa###adbbbcbbaaaabaaaabbchifbabcccabbccaacbaaa##a#aaba", +"#ba########a###aaaaaaa#a#aaa#abaaaaabaa##a#aa###############aab####aaaaabccaaa##a#.#####abcdfb#aaaaaaaaabaabbbcbbbbbababbcdddfedcb#a##aaa#aaaaa###aaaa##aaa##.######.###.###########a#########aaaabbaaaaaaa###aaa##a###bfedcbbaaa############a####a######a#aaabcbbbaaa#gdaaa###bcddcecccca#addefgfddca###a##aaaaaaa##aabaacb####bbdcaaaaaa#aa###ccbbbccbaaaaaaaaabaadhieabaabbccdcbabbaa#####aaa", +"#aab####aa###aaaaaaaaaaaaaaaa#aaaaaaa#####aaa#a##.############aa#abaaaaaaabaaaaa########abccdfcaaaaaaabbbaa#abbcbbaacabbbbcddecdcc####aaa#aaaaa#aaaaaaa##aaaa###..######.#####a########aaa#a####aaaaa#aaaaa########aa####dedbbbaaa##############a###a#####ababccbaaaaa#gcaaaa####bdebbbbbca#bddcbaabccaa##a##aa#aaaaaaabbaca####abdbaaaaaaaaaa#a#ccbbbbbbbaaabbaabba#adhgcbaccccccdccba######aaa", +"a##aa#a###aaaaaaaaaaaaaaaaaaaaaaaaa#aa###aaaaa###.#############a##abababbaaaaaba######aaabbcddhcaaab##baaababaabaaabbabbbbcdddffeeb###aaabcaaaaaaaa###aaa#aa####.######a#######b#####aaacb#######ababaa#aaa##aa########a#aaeecbbbaa##################a##a##bbaabb#aaaa#cd#aaaaaaaace.aaa#bdccdcaaabcacbaba###aaaaaaaabaabccaa#aaabbd#aaaaaaaaaaa#bcccbbbcbbaaaaaaabbaabbhidbbcccbdeddaaa#aa#aa#a", +"aaaa#aaaa##aaaaaaaaaa#aaaaaaaaaaa######aa#aaa####..#########.###aaabbbcbbbaaaaaaba#####aabbcccegcbaaaaaaaacbaabbaaabaaaabcccdeeffddaaaaabcbbbcfffecdcba#abb#############aa#a##acbbcba#bbaa########aabba###a##########aa#aaa#eedccbaaa#####a#a###########aaa#aaa#bcaaaaaafaaaaaaaaacfa##a#aaaba#abaaccbcbbccbaaaaaaabbbbbbaaaa#a#abccc#aaaaabaaaaaadcbbbcbcabbbbaaaaabaaccfjgbccbcccccaa##aabaa#a", +"#a#aa#aabbaa#aaaaaa##abaaaaaaaaa##aaabaa##aa#a###.#.##############aabbbcacbaca#aaca#####aabbccdeedbaabbaaaabbabababaaaabbccdddffedffb###bbccefebccbdeda#aaabbaaa#######aaaaa###aabcca#adaaa#####aba#aaaa##aa################.cedcbbbbaaaaaaaaa##a######aa####aa#bbaaaaaadc#aaaaaabbee####abaaa#aa##abaaabbabdcccdcbbaccbcb##aaaaabbcdbaaaaababaaaacbccbbccbaaabbbbaabababadjiedccccbbbaaaa#aa#a#", +"aaaaa###aaaa##aaaaa####abaa#aaa#a###aaaa######aa#################a##abbbcccbbbaaabba##.#aabbbbddedd#aacb#aaaaaaaaaaaaabbbccdddggffghecbbaabbbddabaa#aaaabaaa#bbbaaaaa##a##aba###aaabb##bbaa####aaaa###########a########.#####aaeecbaabbaaaaaaaaaaaaaa###aaa##a##aa###aaabeabaaaaaabchca###a#aa#a###a##aa####bca#abdecbcdbaaba#aaabbdcaaaaaaaabbaaaaccbbbccdbabaaabbbabbbabacjkjgfdccbaaaabbaaa##", +"#a#aaaa###caa#####aaadb#aaa#aaaa#aaa##aaa###aaaa#a####a##a######a#a##aabbbbabba##aabaa##aaaabacdececaaaba#aaaabaaaa#aaaaccdeeefgeeefbcbbbcbbbcbaaaaaaabaaaaaa##abba##a#####aaa###aaaa##.#ba##.###aa############.##.#############dedcbaabbaaaaaaabaa###a###aa##aa#aaaaaaa#dbbbbbbbaacgg#b####a####a##aaabaaabbcaa#abacdcaaaabaaaaabbccaaaaaaaabbbbcbabcacccccbabbaabbbabcbbaaejklhfcbcbbaaaa#aaaa", +"####aaaaa##aaaaabaaaaabbaaa##aaaa###aabbaa###aa#aaaa###aa#######aa#a##bcccaaabbaa#acaa###aaaabbcdcdcbaabaaaaaabaa##aaaabbccdfffghffdaabbaabccddbabaaaaaaaaaaaaaaaaa##a#######a####aaa###.aba######a#################a############bfedbaabbbbbaaaaabaa##a#########abbbba##dcbabbbaaabcgdc#####aabaa###a#bbbbbbbbbbaaabbcbbabbbaaaabbbdebaabbbaabcbbbbacbabbabbbbabbbaababbbbbghillgcbbbbbaabbaaa#", +"###aaaaaaccdcaaaaaaba##aaaaa##aabaabaaab########aaaba####a###a##aaaaaabccbba##bbba#bca###aaaaabdcddcda#abaaabaaaaccaaabbbccefgfghffaaaabbaaabefbcbaaaaaaaaaaaabaaaa##aa#########a########aaa###a##############.##.#.############a#abdebabcdcbbcbaabba############acdea#abecbaabbbaabbdfc##aaaa#a#aaa##abbbcaba#adebaecabbaccdcbbabbcbdddbabbbabccccbbacbbbbbabccbbbbbaaaabcbcfijjkjfddcbabdebaaa", +"db#bdccbbcb##aabbbbaa###aaabbbbaccaaaabca####.#####baba##a#aaaaa#aba#accbbbbaaaaaaaacbaaaaaaaaacccdccc##abaabbaaabdbabbcccdffffhggbaaaaabdbaaaababbaaaaa#a#a#aaaaba#a#a################aabaaaaa###########.#####...#####.##.####aaaa#bedcccaaaaabbaaaaa##a#####aaaaddaabdebabbbbbabbbbgcaa#a#aaaa###aaabdaddabaadcfdfgdacbaabcbbbcccbdcdffdacdcedccbbbacbbbbcccccbbbbabacabbdgigbbgjjedcbbbccaaa", +"#bbbaaaaaabaaabbbea#aaa#abbbbabaaaaaaaaba#############b####aaaaaabaa###abbbbbaaaaaaaacbaaaaaaabbcccccdd##cbcbcaaaaaaabcdeffgggiigabbbbbaabcaaaaaaaaaaaaaa#aaa##aaaaaaa################aaba###baaaa#######.#####....#########.#a##aa##a#adfca###abbaaaaaaa#####a####bdbacfdaaaaaabbaacedfa#aa#########abefeddcccdebccfggfedaaccbacddecdccdeddccefddcccccccabaabbabaabbaabacbbhijgdbacfkjeedcba#a#", +"###aaaaa#abbaaaaaaa#a####bcaaaba###a#aaaa######a####aa######aaababaaaa##aabbaaaaaaaaabcaabbaaaaabcbccccbcbaaaaababbcccdefgfgghkgbaabbcbccbaaaaaabaaaaaaaa#aaaa#aaaaaaaaa####a########aaabba#aaaa#####a#.###.######.#####.####.##a#abaaa#aaddaaabbaaaaaaaa#########aabgggfbaaaaaabbbabbcfea#a#####aa##afghhfggghhgccddffhfffcccbccdfgeeeceec#aabcddcdddccebaaabaaabaaacbbbb#ejhjgbbceceikibbceba#", +"aaa##a#aabbabbaaaaaaab####bc#aaaa#aaaaaa#ab##aaaa##a#aa######aa#baaaaaaaaaaaaaaaa#aaaaacbaabaaaabbcccccdbaaaabbbbccddeeefeegjheb#a#aabaccdcaaaaaaabbabaa#aa##aaaaaaaaaaaa#######a###aaaabba#abaa####..###.###.####..#####.#######aa##ba#####bcbaaabbaaaaaa########abdfggebabaaaaaabbbbbchfaaa######abbfegggefgghgffeecefggfhheecdddeeefdcefcabaabccbaabcbcbaaaaaaabbabbbbbbfghggdbcbcbbgkjfbbecb", +"#aa#a###aababbbaaaaaaac###.acaaaba#aba####ac#aba###aaaaaaa#aa##a#a########aaaaa#aaaaabbbbbaabbaaabbbccccebaaaabbccddddedegggfhbaaa##aaabcccaaa#aaabbbbcbaaa#####aaaaaa#aaaaa#####a###aaaaaabbdaaa########...##.###..########.#####aa#aba###a#accbaaaaaaa#######aaaaabccdeeccbbaabaabbbbegfgeca#####adefffefgggfghggfeeccegihijigedbccfeceddfeaaabcacbbaaabbaaabaaaabbbbbcbchgghfgdabbaa#bgkjgcdd", +"d#a#a####aaaabbbabaaaaaa####abaabaaaaaaa###acdbaa#a###aaaaaaaa###########aa#a####aaa#abbbbbaabaaaaaabcbccdaaaaabccddeefefhgefgbaaaaaaabaabbaa##ababbaaabcca#aa#aaaaaa##aabaaa####a####aacba#bcb#aa#.####.#...##.##..################a########a#adbaaaabaa#aa##aaaaabbbcdeddddcbabebbcbbffeefdec##adeeefeffefghgghghhgfedfheabfghhfdcegecbbbbccaaaabcaaaaaabaaabaabbbbabbcdfffgffffabbbbbcabgkjec", +"cdaa##aa#aaababbbaabbaaaa####bbabcaaaaaaa##.acaaaaaaaa#aaaaa#ba###########aaa#a###aaaababbaabaaaaaaaabcccdgbbbccccddeffefgfeffbaa###a#aaaaaa#aaaaaaabbbccaaabaaaaa##a###aaabfd#####aaaabbaba#aa########.###.##.###############################bacedcbbbbabaaaaaaaaabcccccddedddbbdeecdefeededdeeffdegffeddefgfgggggcb##abbca###bbefeefeddcdcbeeaaaaab#a###babbbbbababcbccfgfeeefegcbaaabbca#afkh", +"gdcbaaaaaabbbaaabaaabbbbaaa###bbcbaa#aaaa#####a###aaaaaa#aaa#aaaaa##a#####a#aa#aa#a#aaaabbaaacaaabaaaabccdfgddddddccdfhhffddfbaaa####aaaaaaa##a#aaaaaabbdb#aaaaba#a#######aacegdbaa#aaabaabbb########.#.##.##..#...####.#######################babedededcbaaaaaaaaabccddeedefecfffeeffddddddeddeeeddeggfddeeffbaaaaaaaabdb#baa#a##cbdfeaaabbcdfbaaaaa####a##abbbbaabbbbdcgfgeeedeefabba#aaaaaabg", +"gjgccbaaaaabbbbbbbbaacbaaaaa###aaaaaaaaaaa####aaa#####aaa##aaa#a#a#######aaaaaa##aaaaaaaabba#acaacbaaa#acccfgdefefcdecfhhddbcaaa#a#####aaa#aa###aaaaaaabbeebaaaaaaa####.###aaacdcbaaaa#aaabba#############.#.#.#...###########..###############aacddeeededceeedccefggfgggfedggghfdfecdddccccddeeeeefddfffddddbabbbaaaaabefcdb#aa##aaabcaaaaa#bdgb#abaa#######ba#bbaabaaeegfgfeeeecfcaaa#aa#aaaa#", +"#bgifcbaaabbbcbbbbaabbbaba#a#aa##aaaaaaaa######aaaa##a#aabaaaaaaaaabaaaba##aaba###aaaaaaaaabbabbabaa#a#abcceffeecb#cddeeggcdb##a##aa##aa#########aaaaaaa#bedaaaaaa##########abaa#aaaaaa#aaabaa#####a####################..######.#a##.#########aabcccbcda##afgggffdbbbabdhheghifedddeecbccdcdefffeeffdfggfdbaaaaa#aababbacdddb#bb#aaa#a####ababbdebbbaaa####a#babbaaacddfgffeefeeddcbabbaaaa#aaa", +"a##ehiecbbbccdccbbbbaabbaaa#aaa##aabaaaaaaa####aaaa#####aaba#aabcbbbaabbba##abaaa######aa#abbacbaaaaaaaaabcccdfcaa##bbbbceabaa######aa##a##aa####aaaaaaaa#abaaaaaa###a######abbbaba##aaa#a####aaa###a############.########################a####aa#dcddcdb#a#dedeedcaa#baacgegiifedddddddcdddefeffggfgeedbba#aaaabbaabaaaaabceebbdaaaaa######aaaaabdddb#aaaaaabacbbbaabdfffgfgfeeeeddgcbaaaaa####", +"#b##adiifdbcefedccccbaabaaaa#aaaaaaaaaaaaaaaa##abaa######aabbaabbcbbaaaaaaa#abaaa#######aaaaabcca#aaa##aaaabbccc#########a###aa##a###aa########aaa##aaa#aaa#aa#aba##a#######aabbabcaa#ababbca##aa####a#####a.#########################a###a##acba.ddeecccba#cfeeedcaaaaabccbaigfeeeddddcbcdcddfeffggeedaabaaaabaaabbabaaaaa##cffedeaa#a#aaa#aaaaaa#abfebabaaaaaacadcaaffecffffgfffeeggaaabaa####", +"#caaa#.ahjgffefgggffecbbbabaaaaaaaa#aaaaaaaaababaa#aa#a#aaaabaaaacccaaaaaa#a#aaabaa######aaababaaaaaaaaa#aaaabccb####aaa##ab###aa#####a#a####.#aabaaaa########a##aba########acbbaaaaaaaaaabbbaaa################a###a####aa############aaccb#adcbbdddccbcdebdedccba#a#aabdcbaggeeddedcbbbccdeeffffhggfcbaaaabbbcaabaaaba####a#debceea#aaabaaaaaba#aaa#cfgcaa##aabcbcbdffedfeeeefefeedhcaaaa#a###", +"####aa##.behhgfeeeddefedbbbbaaabaaaaabaaaaaaaabaaaa#aaaa#a#abbaaabbcbbaaaaaaaaaaaba####aa#aaabaaaa##a#aa#a#aaabbcc.##ab##aabca##aaaa############aabaaaaa#a#a#####aaa#bb#.####bccbaa##aaaa###aaaaa######a#######bbabba####bb###a#a###a###bcccccdcdccddcbbabcdcddccba####bdddb#bdcecdedcbbbbbcceeeeehhcdaaaababcbcaaaaabaaa#####ab#aabb###bb##abcaa###a##adfeba###aabaaefefffedddeedefefhbaaa###.#", +"#####aaaa###chikjiigedcegcccbabbaaaaaabbaaaaabaa#aaa#a#a##aaaaaaaaabaa#aaaaaaabbbaa######aaaaabaaaaaa##aaba##aaabab.###aaaaaabaa#aa#a#############a###aaba########aa#cbb####abcbaaa##aaa#a######a#.####aa###bbccbbdccbaaabb###a#aaaaa###cbbbaccccbbcccaaaabbccccbbaaa#accdcb##bacgeeedccccbccdeeefggebdaaaaabbbbbbaaabaa#####a#a#aa#####aaaa##ca#####a####beeca#b#abadgefffedeedfdcffeff#a#a###.", +"..######a#aaadd#acdhihecdgecbcaa#aa####ba#aaa##aa##aaa###aaaaaaa##ababaaa#aaaaabbbaa######aaaaaaaabaaaa##baa##a#a#b######aaaaaaaaa#################a#aa#bcb#####aba##a######bbbcbaabcaa#################a#abcdbdefededcbcbaa##aaa#a###bcbababbccbbbbbcaaaaabcccbaabaaaabcdbba###bhhfhgeddccbccddfhhhfbbaaaaaabbbccaaaabaa####aa#a#####b####aa#aa#ab###a##aaabefd#a#abbfgfeeeeeedeeddefggbaaa####", +"##.######aaba#abaaaabeiiebceddcbaaaaa###aaba#########a##aaaaaaaa###aaaaaaaaabaabbbbaaa###aaaaabbbaaabbaaaaa###a###bb#####aa###########a######a#####aa#baaaba##abcedcbaa##a##bcccbaaaddccaa##############a##bbceffgfededdedcbaa#a#aaa#bcabaaabbbccbbbbbbaaaabbcbbbbaaaaabbcda#a##ehgfeeeeecddbcddfhhgcbbbbbbaaaabcbbbaaaaa###.#a#a#a####aaa###aa##a########aabbbedbacfegggfeeefeddccddgihdaaa####", +"##.###a####aaaa#bacbaa#chidccdfdbbabaaa#ababaaa###a###aa#aaaaaaaaaba#aaaabccccbcccccabb###aabaabbbcbaabaa########aaab.####aaa##################a####b##aaaabb#aacdddcbb#######bccaaaabdbba#####aa#a#########abccccccddcffhigcbaaa#aa#acaabaabbbbaaabbbbbaaaabbbbaaaaaabcccdda#a#higheddefedeecdffffeeaaabbbbaaabcbaabaaaa#########a####aaaa######a#######aaabdcbadgfdeddegfgfeedcccccehigaaa####", +"###########aa#####aacdb##ejgcbbfedcaaaaaacbabaa#####aaaa#aaaaaaaaaaa##abbbbbbaaabbcddddbccdcccbababaaaaaab#########aba..####aa###################aa########aa##aaaabbbba##a####ccaababdaa#aa#####aa##########aaaaabbccdfgjjihdcaa#aaaacbaabbababbaabbbabaabbbbbbbbbbbbbcccddebadhggfffeeffffeeeffdccddaaaabaaabbabbbbaaaa######..######aaaaaa#a###a#aaa###aaaccc#ceggedddcffffedcbabccdfgebaa###", +"#########aabaaa####a#aabbachjgbacdedcccbabaaaaaaa#####aa#######aaaaaa#aaaaaaabaaaabbccdccddcbbbabaaaaaabbaa########aabb.#######a##################aaa##########aa##abaaaaa######bbaaaaba#a#a#.##.#a#aa###aa###aaaaaabcddgijijjigeba#abdcbbcdcabbbbaabbabaaabbbbaaabbbbbcacddee#dfeeeffeccdghhfffebccccaaaaababbbbaaabba#a########.###a##aaaa##aa##aaaaa####aababbddceggfedcdffedcbaabcdeeffaaaa#", +"#######a#aaaaaa#a#####aaaabcdiibaaacecddcbaaaaaaaaaa##aaa########a#aa###aaaaaaaaaaaaabcccbbaaaaaaaaabaabbaaa######aaaaca.###.##a#a####a########aaaaaaa##...###a###a##a#aaaa#####bdaaaaaa########a########a##a##aaaaabbbbegfeedeghgeccddeeefgcbbaaaabbbbaaaabbbaababbbbcccbceeebegdddeffedbdeiihecbcbdbaabaaababcbbaaabaaa#a#.############aaaa##b#a##aaaaa##aabbbbccdceghgeddefedcaaaaccdedfaaaa#", +"########bcaaaaa##########aaaa#gidaaabedcccbbbaabdbaa####aba#a#############aaaa###aaaaaaacbbaaaaabbabbbbbcbbabaa######aabb..##.####aa#aaa######aaaaaaa####a#.####aa##ba#aaaba#####dbaaaaa######aaa#aa######aa###aaa#aaabccebabaabbdfhhhgfghggdbaaabbcaaabbaaabaaaaaaabccccccedchigdcdddcedccabghdbaaabcaaabaaaaabbbbcbbaa##a########a##.#aaaaaaaaa#aaaaaaaca#acbbbbbcccdefeddeecdcbaababcfdfeaa##", +"########baaaaba#aaaa#####a####aciib#aacdddbabbaabbb#aa#####aa#############aaaa##aaaabaaaabaa##aabababbbbccbbbcb#######aaaa#...##.#####aa########aaaaa######a############a#aaaab##abbaaaa#######cb############aa#aa#aaaaabaaa#######bfhigihhfbaabaaaaaabaaaabbaaaabaaaccbccdcchiihhdbcddcddccbbeeaaaabbbaaaababaabbbeeeaa#####.###.aaaa#aaaaaa#aaa#aaaaaa#bbadccbbbbccccbcddddcbcccbaaaaddddge###", +"########a##abbaaa#########a#aaabcfjhaaabcdecaabaaaaaaa#######a########a#aa#abaa#####aaabaabaa##ba#abbccbaccaaca########abcb..######################aa###ceb#######aaa#####a#aaa###acaa#aa#######b############a#a##aaaaaabaa########abacfhhfcbbaaaabaaabaaaaccaaaaaaaacbcbbcffgfgcegeddeddcdccbcd#aaababbbaaababcaabaaccba########a#abaa##aaaa##aaaaaaaaaababcbbbaccbbcbccdddcbbbcbbcbbadcdeehd##", +"########bb####aaba#########a####aabfjfbbcbcfdbabaaaaaaba######aa######aaaaaaaaa##a#####aaa######aaaabacbbaaabaa#########aadc...#######.##########aaaaaa#ddeb#a####aaaabeb######a###bbaaaa##b####aa#.##########a#a#a#aaaabaaa##b###.adbaabeecbaaaaaababaaaaabcabaaaabbbbbcdcfgeddgbbggeedddcccccc####aabaaaaabbaabaaa#acda############aaaaaa#aaabaaaaaaaaaabcbabbbabcbbbbcddccbcbbbabbbbccdfggf#a", +"aaaa####bc##a#aaaaaaa###.#####.####aciiecccbceebaabbabbb######a#a####a##aaaaaaa########aaa#######aaabcbbabbaaaaa#########acfc..####.#.###.###aa###a#a#aaabcaaaa###aaaa##########a##bdcaaaa#ba###baa##########aaa####aaa#bbababdcbaacbbbaaaabbaaa##aaaaaaa#aabbbaaabbbbbbcdcccddcdec#adfedddcccbe#####aaaaaaaaaabbbaaa#bdb##.#######.####aaaaa###aaaaa##aaabccbbbaababbbbbcdccccbcbbbcbbbdcefghc#", +"########a#####aa#bbaaaba######...####adhifegfddfdcabccbaa###aaaaaaa######aaaa##aa##a###b##########aa#aaaaaabaaa######a###abdfb..#######.##.#####aaa#a###baaa####aaa#########a####a#bddcbaaaa####aaaa####ad##aaaaaa#######abadddccccdcba##a#ababa###aaaaaaaaabaaabbbbbcbbcbbccdccbaba##afedddccbfa######a#aaaaaabbabaaaaab#####.##..#..a###aaaaa#aabbaaaaaabcccbbbabbbbbbbbddccbbcbbbcbbcfdeeffha", +"##############aababaaaa##########.##.#..chjjhjifffdeccdbaa#aaa###aa#####.##aa#######.#######a#########aaaaaaaaaac########acchc.....#..###########aa##aa#abaaa##aba##a######aaaa##a##bdcbaaaa#####a#aa###bd###aaaa#aa##a####adgdcbbcddbb###aaa#a#####aaa##aaa##abbaabbbbcbbbcccddeccc#a#bhggfedaec##########aa#aaababaaaaaa#####.##.##.####aaaaaaaaaaaaaaaabdcbbbababbabbbabddcbbbbbbccbbdifdefge", +"a###a##########abb#aaab#a#######...#####.##a#acgkigfeefdcaaa##aa#aaba####..######.#a###a#aa#aa##.#######aaaaaa##ba#####aaabbeha...###.###.#######a##aaa#aaa#a#aaaa###aa#a###aa###a###cdcaaa######a#####abb####aaaaa####a####deebbbccdbba##aaa#aa####aabaa#a#aabbbaaaaabcbcbbccbcedbba###cdffffeefba###########aaaaaabcaba#####.####.#######a#aaaaaaaaaaaaacdccabbababbabbaabcccbbbbbbbccdeeedefh", +"f#######aa##a##aaa#aa#bba#########..############afkjgfgfeeeba#aaa##a#######.####.#.#####abbbaa##########aaaa##a#a#######abbcdhe#...######.##a####aa#a###aa#a#aaaaa######aaa###########bdbbaaa####a######aa##.##aaab####aabdecdcbaabbbaba##aaa#########abaaa##abbbaaaaabbbcdbaccbcebaa####adghfedeeba#############aaaaabbcb##########.######aa#aaaaaaa###bcdccbbabbbacbaabbbbbbdcccbbbbbcccccddeh", +"hc#####aa######aa####aaaa#####a###.......##aa##a###gijhhhggeb##baaaa####...#####.#..a###acccaaa##########aa#####aaa####aacdddhf#..###.#..####aaaaaaaaaa###a#aa#aaaaa#####aabb##########cecaaa####a##############aabb##aabacddbcbbabbbaaaaaaaa##a#######baaaaa#abbaaa#abbbabcbbbcdgd####a##adcgfecdeb######a########aaaa#baaba########.######aaaaabbbbbbcbccbbbbbbbbbaaaaabbbbbbccbcbbbbcccccdeed", +"egb##baaaaa####a##aa#aaa#a#######.#..###.###########adfilkhfca#abaaa#####..##....#....###bbccaa##a##aa####aaaaa##a##a##abbcfhjfb#..#####.######aaaaaaa######aa##a#abbbba###aba#aa#######cecaaaa###a#.#######aa##aa#aa###aaabcbcbbcbbaaabb##aaaaa#######abaaaaaabbaaa#abbbbbabbabdfeaaaa##a#ca#eecccfcaaaaaaaaa#a#a######aaaaabca########a####aaaabababbbbbbbbbbbbbbbaaaaaaabababccccbcccdccbdffd", +"cfhd#acaaaa##a#######a#a##a###a##.....######.##########bddjkidca#########..###....######acaacbbb#a###ab##aaaaaaaaaaaaa#aabcfgejfa#.###a######a##aaaa#aaa#a###aa##a#abbcba#####aa####a###aeedbaaa##aa####...#aaaa#bcaccbaaaabcdccabcbbbaaca#aaaaa#########aaaaaaabaaaaabbbbbbbaaabbecbbcaaaaaa#adecccedcaaaaaaaaa##a###########abaa######a####aaaabdbbbbbbbaabbbbbabbaaaaaaaabbaabccbccbccdccdefg", +"fedfea#a####a##a#a#######a####a#.##..#.####...########aaaaaeikhea#####################aaacbabbdfdbbaa#aaabbcbbaabaaaaaaabcdfbbeica..#a########aabaaaaaba#a###aa#######aaa#####aaa#.aa###adffdbaaa##ca####.#########abbcdeeeefcdcbabbbbbaacbbaaaaaa##a##a##baa##aa###aaaabbabbaabaadfb#bbbbbaa###feccbeecbbabaabaaaaaaa#aa###a####a########a##aaaaabbbbbbcbabbaaaaaabbbaaaaaaabbbabccccccddddeeee", +"fggehdaaa######a##########aaaaa#.##.####..#..##.#######aabbaadjljgda.#################aaaccbccddcccccccccccccdcbbccbcbaabbcfdcbgf#...#aa######abcbaaaaabaaaaa############.##aa##a########dffedcbaa#cc##########a####bbbbcdffeedaaabbbbbcbabbaaaaaaa#######abaaaaaaaaaaaabbabbaa#a#bdcbbbaaaaa###cfeeehhecabbbbbbaaaaaa##aaa##a###a########aa#aaaa#bbcbbbabbbbaaaaabbbbbabaaaaaaaabbbbbcccddddeee", +"edehhg#aaa######a#a#####a##abbaa###.###################aaabbcaacjllkhbaa#######a######bbaefddddcbbbaaaababefeedddccffdccdfgeeeefec#...#ab#.####abccbbba#aaaaaa###########..###a##########bfdfdccaaacfb.######aababaaaccccbdffebbbbcbbaacccbabbabaaaa######aaaaaaaaab#aaabaaaabaaaabbeffcaaaa####aeeeefiihfcabbbbbbabaaaaaaaa##a######aaaa####abbabbabcbaaaaccbbbbbbbbcbcaaaaaaaaaaaacbbcdddddede", +"eefgghcaa#######a##aa######abbbcc#.############.###a#aaaaaaaaccbafjllkjecbaaaaaaaa##aabcccgefeecccbba#aaaa.acffffffcacdccbbbfffefda#.##########aabcedba##aa#a#####a#####..#####aa###.####bceecccbaabdfa##aabbbaabbbbdcbbccdcceebabbbaaabcdcbbbbbaaaa######a##aaaaaaacaaaaabbaba###acdeegcbbb#####aeffgfgijkgcbbbbbbbbabbaaaaa##a#aaa#abaaaa##aacdbabbccbaaa#bbbbaabaabccbaaaabbaaaaabbbccdeedddd", +"deeffdfd#####a######a#######aaaca#a############bdca###aca##aaaceddfijjnligdcbbcbaaaaabcddchgedddbccaaa#aaaaa##accfbbbaa####bdhfedhd#.###########bbcccdba###aaa#####a##a#.#####a####.####.#abedebdcbbcfe#####adcbcddbbdbaaacbcbccbbbaaa#bbcbbbbbbaba#a############aaaaaaaaaabaaaaaaabdfcccbbba#####aceffgiijihedccbbbbbabbaaaaaaaaaaaaaaaaa#####aabaaabbbaaaaaabbaabbbbbcabaaaaaaaaabbbbcccdddddd", +"ddddecbdca###a###a##baa#aa##abaaba#a###.#####.#aabaaa#aaa##aa#acdhilmklmlmkheegecbbbbccbcefgedcdcbbbbaaaaa#aba#a#cdabcbaaa#achihggfa############abdb#bcaa##aaa#########a###.######..########beddecbcdffc###.#acdfffdabcca#aabacbbbbbaa#abbbbbbbbbaa#############a#aaa#baaaaaba###aaadfd#babacababbbcegfhhiihgfdddcccbbbaabbaaaaaaaaaaba#aaa###a#aaaaaaaaaaaabbabbaabaaabcbbbaaaaaaababbccdddddcd", +"deddddcacaba###a####aaaaaa#aaaa#aaa###aa#########a##aa#aaa##aba#.cfehhjkjllmllihfedcccbbdefgdcccecbbbccbaaaaaaaaabdbbbcbaaaabhjjhggea#.####a##a#accaa#cdaa#aaa#.#############a##a##.###a####.cedccccefbbaa#####deffeaacdaaaa#aabbbbbaaaaaabbaaabbaba#####a.###a###a#a#aaaaaaa#a##aaacdecaaaabaa#aa#bdgfeeefhhfdccccddcbbaaababaaa##aaaaaaaaa###aaaaaaaaaaaaaaaabbaaababbbbabbbaaaaaabbbbcdcdccdd", +"dddcccdbbbcba#bb#aa###aa##a##a####a##.####aaa##a#aa##a#a#ba######.fffkjlhkkljmmmlieeddccefaeeeccdedbcdccbcbaaaaaabaccbccaaaabeijjigieba.#######aacbaa#accaaaaa##########a#a###aaa#############decabdeeeaba###..adeddcaabcbba##aabbbaaaaaaaaaaaaaaaaa#####a###########aa#abaaaa##a#abbcdeba#b#aa#####cefedcbbdeedcccdddcbbbaabbaaaaaaaaaaabaaa###aaaa#aaaaa###aaaaaaaaaabbbaabbcbaaaaaabcccccccdd", +"ddccbcccbcedaddaaaaaaaaaa#aa#a######...###########aaaaaaaaaa####..cfhjjkmlmklkklmnjfeedeefebdeddegheeedddccbbbaaabbccbcbbaabbbgjkjjhifda.#######aaaaa###abaaaa####aaa###########aa##########..adccaddcecbabbaa##dedddcbabcbca#aaaabbaaaaaaaaaaaaaaaaaa###############aabaa##a####aacbcddebaaa########cffecdcbceeefdddddcbbbaabbbaaaabaaaaaaaaaa###aaa#a#aaaaaaaaaaaaaaaabbbaaaacbbaaabbbbcdcdccb", +"cdcccccbbcdbaacbbbbbbaaa#aa#aaaa#####..#..##.#####a#aaa####aa######eigfcfgijjjlmmmmnlhfhiggdddeefgegfgffdeddcdcbaaccccbcbaaabbcfjkkkijgfb#######a#aa######a#############a###aaaaaba############abcc#ddcccbdecdcaddddddecbbbccaa###aabaaabaaaaaa#aaa#########.####a##a##a#aa#a######abccdgbb#ba#a######cffgfdefffehgdddeccccbaabbbaaabbabaaaaaaaaa###aa##aaaaaaaaaaaaaaaaaaaaaaaabbba#aabbacddccc", +"cddcccbbcccaabbabaacbaaaaa#aa#aa#.#...#...#..###a###a#########aa##adeaaa#abedefijlkmnnlkkjdddfdcebb#degfaefgfeddcbdcddbacbbbbbbdjjklkkihgc#aa#####aa################aaa##a#aaabaaaaa###########aabdbedcabdddeeddddedcccddccbbbca###aaaaabba#a#####a#a###aaa###.###a#######aaaaa###aabbbbcdaaabaa##a####aeghhhggghhhfedddcccccbbbbbbbbbbbbbbaaaaaa####aaba#aca#aaaaaaaaaaaaaaaaaaaaabaaaaabbbcddd", +"dddcccbbdedaabdaaaabbabbbbaaaaaa#.##.##.#.#####################aaaddbbaa#aa##a##aceejnllkkhfhfccfbbaaaabafabdeffgfcdddcabbbbabacgjkkllkhjhbaa#####aa############a##aaaa###aaa#aa#a#####.####a##aa#deedcabdeeeedeeddeedbccdcccdcb####aaabbbaaa#####a##a##a####################aa####aabbbcdea##a########aaabehiiiiiihfedfdccccccbacbbabbbcbbbbaaaaaaaa##ab##bbaaaaaaaaaabaaaaaaaabbbaaaaaabbbbbdd", +"ddccdbcbedcaabbbbaaaaaabbababbaa#################a##########a###a#ecbaababaaaa#####abkllllljgbaaccbababbabaaaa#cedfheedcabbbbbbbchkkkklkhggeba###aba####.####a####a##aa##aaaaaaa##aa####.####a####dfdcba#bdeeeeeefedddcbbcdbbadcba###abaaacaaa###a##a###aa#####.####a######.##a####abbbbccbbc#ab##a#aa#ca###cfggihhihffffedcccccbbabccccdccbbbaaaaaaa#aa#aa#aaababaaabbaaaaaaaaaaaaaa#aa#abbcccc", +"dedcccbcecaaacbababbbaabbbbbcbaaa#..###.#########a##############.cdabbbbbbbba###aabcddilmmljeaaabcbbbbbbbbbbbabaabcefgfecbbbbbbcdfjjkkkmkhfgecbaaabb########a######aaaaa####aaa###################befcbaabbadfeeeeffededcbbccabccccaa#aaa#abaa#######a########...###########.##..###abbbbcbbf#aa###abaa#a#####acfgffgfggefddcccccbbabcecbbbcbbaaaaaaaa##aa#aaaaababbbabbbbbcbbabaaaaa##aaaaabbcc", +"cddecccccdcaaaaaabbbbaaaabbbbaaaa########.####################..aaababaaacbba#abddbcdfeejmllf#aabbbaabbbbbbaaaaaaa#afffdedcbbbddffjfijjkkkhgfed####aba#######a####aaaa#aa#####a######a############adffddcaa#befefedeeddccccbcbaacbaabbaa###aba####a###############.###########.######aabcddcefbb###bbaaaaaabba#cffffghhgfffedccccccbcbbebbbbbbbaaaaaaaa####aaba#aaaabbbbbbcbaaaaabbcbaaaaaaaabcc", +"dddddfebdfeba##aaaaaaabbbbabaaaa####.#########################.abbaaaaaaaaabbaaabba##aceeilmme#aaaaaaaabbbbaaaaabbbbbefgeddcddddegiighiiggjggfdba##aaaa##############ba#b###aaaa#######a##a#aaa####dfgffgcaabefeeededccccdddcbbbbbaaacbab###aaaaaa########a#a########.#########..####aaabdcdecbdc#aa###aabbcccaacegggfgghggfeeeddddcccbccbbbbaaaaaaaaaaba#aaaabaaaaaaaaaaaaaaaaaaabbaaaaabbabbbc", +"bcdeeeeedeeda##aaaaaaaccbbaaaaaaa####..##.#########a##########aaaaaaaaaaaaababba#aa####abbdhkmgbbbaaaaabbabaaaaababbbaehfcdeeeegghkkjjigdeehfeccaaaabcba########a####aaa#####aa####a####aa###baba##adfgfffdeeffdcddddddbcccdccbbbbbbb##bdb###aadb#a##############.##.######.##########abcdcedecegdb#a#aaabbcddaa#adfghfghgffefeefeeddcccccbbcbaaaaaaaaaaa#aa###aaaaaa#aaaab##aaaabbbabaaaabaaabb", +"cbceeeefffffd#aaaaaaaaaddbaaaaaaaa#############.#############cbbaabaaaaaaabaaaaaaaaa###aaa#achlkigdaabbabbbbaabcaacaababccdbbdedcdfehkkjgeceheccda#aabbba###.######a#aaa#####aa######.#a#aa##aa#aa##adgggfeeggffdcccddcccbbcbccbbbaaa####ca##abcba#aa##########.#####a######.#.#######abbcbddbdfhgeaaa##abbcdcaaa##aaceghdfgffffffeeddddcccbbbaaaaaaaaaaaa##aa#aaaaaaaaaaab##a#baabbabbbaaaababb", +"ccddefgfefffd#a##aaaaaabccbabaabaaa##########...############acbaabaabaaaaaaa#aaa#aabaaaa#aaaabgkjiifbabbabbaaaabaaabbabaaaaaaabcc#####cgkmjgfhfcbcaaaabcbaa########a#aa###a###########.####a######aa##bghfefgeddeccbbbccccccbcdcaaa#a##a#aa#a#aaaacbaa##.############aa########.#######bbbccddddggfbaa###abbcbaaaa#aaabeeeeggghgggffeedcccbbbbbcbaaaaaaaaaa###aaaba#aaaabbaa#a#abbbbbbabdbbaaaab", +"bcceddefhgfcbaa#a#aaa###aaabbbaaaaa#######################aababaaaaa#aaaaaaaaaaa#aaaaaaaa#aa###cefllgabaaaaabbbaaaaabaaabbabaaa#ba######bfjljhghcac##aaacaa########a###############aa#.##a#############afgfgfedcccccbbccccccddcccaa##a####aa#aaaaaabaa#################a#a##.#########aaabccccddeegfbaa###abbaaa#aaaaaabdfceghhhhhhgfedddcbbbbbbbbaaaaaaaaaa###a##aaaaaaabbbaaacbbabbbbbcccdaaaa", +"bbcccdefhiea###a##aaa######aaaa#aacb##############a####aaabcbbabbaaaaabaaaaaaaaa##a#aaabaaaaaaaaabekljbaaabbaabaabaaaaaaaabbaaaa#a#aa#####aekkhhiba###aabbbb#####a.#########a#a#####a#######aa####.#aba##gggfeedccbbbbbbcbaabccbcbaa##a###aa##abaaa#aa###..###########.###a##.#######aaaabbbcdddcefgaaaaa##abaabaaaabbaabdeffghighhgfffeeccbababbbbbaaaaa#aaaa#a####aaaaaabbaabbbbbbbcccbcccdbaa", +"bcccccdefgeaaaaaaaaa#a#a#a##aaa#a#aba#######a#.###aa######bcaaaaaaaaaaabaaaaaaaa###aaaaaabbaa#aaabbchkkc#aaaaaaaaaaaaaaaaaaaaa#a#aaa#a#######dkklibca#aaabcdca#a#aa#################a######aaaa######aab#cghhgfddcbbbbaabaaaaabbca##a##abaaa##abaaba#a#aa############...##.###.#..####aaacbbcdccdcdedbaaa#a#acbaaa#aaaaaaabcffffghhhfggfeddbcbbbaaaabbaaaaaaaaaaa#aa#aa#aaabbbcccbbbbbbbbbbcdccb", +"bbbccccdfcec##aaaaaa####a####aa#aa#aca##a####baa#######a##bbbaaaaaaaabbbbbaaaa#aaaa##aaaaabbba#aaaaaadijgaabaabbaaaaaa###aaaaaaaaaaaaaa#######behlidcdbaaabbcecaa######a###aaa###########a####a#######aaacghihgfedcbaaaaaaaaaababbbaa###aaa####a#aba##a#a#####..######......#...#.#.####aaccbcccdcdehhdaa####bcba###aaaaaaabaaadfeeegihgecdedcbcbaaaabbaaabaaaaaaa##aaaa#aaabcbbbccbbbbbbbbbcbbb", +"babbcdddddde######aaa###########aaaabda##a####abaaa#####abbaaaaaaaaaaaaaaabbbaaa#aa##aaaaaaaaabaaaaaabcdkib#aaaabbaaaaaa####aaaaa#aaaaaa##a##a##acgjhfgefcbbacccbaa####a######aaaa########a#############bfffhjigedddbaaaaaabaabbbbccaa####aa###a##aa#################a##.....#..#########aabbbbcccddfheaaa####bba####abba#aaaa##bca.#bghfedecbccbbbaaaaaabaaaaaaaaa#a#aaaaabbbbbbbbbbbbbbbbbbaba", +"bbabbdcdddcec#####aaaa#a####a###abaaaaaa##bda##aaa######aaaaa#######aabbbaaaaaa##a##aa#a#aaaaaaaabaabacbdjjbaaaaaabaaaaaa##########a#aa##aaa##a#a##cfhhededabbdcbcca##########aaaaa############a######a##dffgjiiheedcbaa###bbaabbbddba#########aaa####################a###..###..##..###aaaabbbbcbcfffebaaaa#aabaa##a#aaaaaaa#####aa#.bdegfeccbbaabbaaaaaaaaaaaaaa#aaaaaaaababccbcbaabbbbbbcbbab", +"dbbbbcdcdcdcea###a####a#aab#aaaa##aaaaaaa##a####aaa###.##aa###########aaaabaa#aaaaaaaaaaaaa#aaaaaaabbaabbbhkfcaaaaabbaaaaa##########aaa###aaba######.ekjgddbabbaabccbba########aaa####.#######aa##aaa#####dgfgghgggedcbbaaa#aabbbcbedba#######aaa#a####################aa#.......##..####aabbbbcbcdefeebb#aaa#aaa##ab###aaa#######a###.##cgefdccbbabbbaaaaaaa#aaaa#a#aaaabbccbbcbbbaabbbbcbccbbb", +"bcabbcceffabbc########aaa#aaaaaaba#aaaaaaaa########.#####aa######aa####aabbbaaaaaaa##aaaaaa###aa#aa#aaaaabbfkjhdaaaabaaa#aa##aa#####aa#a#a#aaaa######aikjjhbaaabbaacbaaa###############.###################bfhggggggfedcabaaaaabbcdeccaa########aa##########aa######a#a##a##..#.#...#####aabbbbbcccecdgccb##a####a##a############aaa######agfedccccbbaaaababaaaaaaa####aabbaaaaabbababbbccccbbcb", +"ababbccdffdbbbba###aa#aaaaaaa#baaaaaaaaaaaa#########.####ab###########aaaaaaabcbbbaa###aaaa#ba###aaa###abbbbflljeaaaaaaaaa###########aa##aaaaa#######.afikkiba#abbaaba##########a############################ehffgggfeedcccbaabababcccbaa######aa##aa###.###aa####...#########...########abbbbcbbbcdecfgdaa#######################aa##a####bfeeddccbbbbbaaaaaabaaa#abaaaaaaaaabaaaabbbbbbccccccc", +"adbbbbcdddecbaba#a#######a#a##aaaaaaaaa#aa##########.###aac##########a##aa#aaaabcbbaaaa##aaa####aa#aaba#abbbbdillhcaaaaa####aa####aa#aaaa##aa#########.#chkli#aaaaabbaaa########a#aa###a###############.###aa#fggffgffedeecbbbaaabbbbcbaaa#####aa###a############################.######aababbcbbbccedcfccaaaaaaaa###############.####a#####bffeddccbbaaaaaaaabaaa###aabaaaaaaaaaaababbbbbbbcccc", +"ccbbccddeeeccaaca##a####aaaaaa##aaaaa#a#aaaa#########.###ab####.#a###aaa##aaa#aaaabbaaaaaaaaaaba#abaaaaaaaaaaachkklfbaaaa##########a##abaaa############..#bimiaaaaaabaaba##########aa#babaa##############.##a##aegfcbdeedfedbbbabbabbcbbbaa#####a#####aa######################.#########aabbbbbcbbacddddccaaa#aaaaaa###a#####################afgeecdccbaaaaaaa#abccbaaaaaaa#aaaaaaaaaaaabbbccbcc", +"ccedcdddeeeccbbbcba#a###aaa#a#a#aaa#####aa#a#############ab#####.#####aa#a#aabaaaabbbbabbba##aa###acb#aaaaaaaaacfihkida##a#a###.####aaaaaaaa##a###aa######.ahljc#abaaaaaaa###.####a######abaaa############.#####.bababeedegdcbccbcbabaaabba#a##aa####aba#aba#a###################.####a##ababbbcbbbcdddedea#aaa#a####aa#######.###.######a##a##fgfedddbbaaaa#bcdccbbba####aaaaaaaabbabbbbbbbcbbc", +"cddeddddeefddcbbcc#a#aa#aaaaaaa#aaaa####aaa######aa######ab#a########aa#a#aaaaaaaaaaabbaabba#aab###abb######aaabbcfheihc######a#####aa#aaaaaaa####aaaaaa###.aikjcaaaaaaaa#################aaccbaa#a################aaaaaaabdddcbccbaaaaaaaaaaa##b####abbcccb##.###a#############..###aaaaaabbbbbccbbccccddecaaa#aaaa###a########################effedccaabbaccbbaaaacc####a#aaaa#aabbbbbbbbbbbcc", +"dcdcdcdeddfecdcbcdaa#aaa##a###a###aa##############aaaa###aba#############aaaabaaabaaaabbabbaaa#aba####a##a###aaabccefadhhb##aaa#####aaaaa#aa#a##aaa#aaa#####.aflkcaaaabaa####################ddcbaaa#################a#aaa#bdddbbcbaaaabaaaaaaa#a####a#baa####a###a###aa#############aaaabccccbcccbbcdcdedefb##a###aa##aa###############a##aa####efddcbcecbccabbaa#aacc###a##aa#aaaabbababbbbccc", +"ccdddcbcfhfddcdcbbc#####a#aaa##a########a#a#aaa#####aaa##abaaa##.#######aabbaabbaaaaaaaababbaaa#aaaaa###a#a#a#aaabccdha#diga##aba#####ca##aa####aaaaa#a#######acildaababbaa###########a#######abccbaa#########.#########a###cdedbbdcbbabba#aaa###a####aaaa#aab###a##a#aa######aaa######aabbccccccccccddddeddfca#aa##aaa#aaa#####a####.###aa#a##a#cfeddedacaaabcaa###aacc###########aaaaaabbbbbcc", +"ccccddccdeffdcccdccb########aa##########a#aaabaa#####aa##ab#aa###########aaaaaaababaaaaaaaabaabcabba############aaabcffb.afjfa#aba####a#a########a#a########aa#abhjb#aaaba#a##########a#######aabcccbb####.#..###aba#########abddbcecbbcbba#aaa########aaaa#a#a###aaa########aaaaa#####aabccdcddccccccccddedcec###ba#a####a#a##########.######aa#adedcbbaabaaabbaa###aabca##aaa#a##aaaaaaabbbbbc", +"cccccdcedcddfebbdcbdb#######################abcbba#######bbaa######.######aaaaaabbabaaaa##aaabababaaaaa########aaaabbcfiea#bgjeaaa######aa#a#############a####a#acgigaaabb##########.##a#######aaa#adcba##########ba#a#a#####a#adfcddbcccbaa#aaa######aaaaaa##aa#aabbab#aa####aaaa#####aaabbccdddcdcbbbbcccddegd##baaaaa#########a################abbcccbbbbabbbba#####abca##aaa####aa#aaabbbbbb", +"bbbccddcdcddefdbcdadcaaa#####################aabbbba#a#aabba#aa##########aaaaaabbaaaaaaaaa#a#aaabbbbbaaaa###a#aaaaaaaabfifa##ejgbaaa########a##################acbcfigba#aa###########a#########a#aaabbbba#######.#a#a#######aaaaffddccbccba##aaa##########a######aabaaa#.####aa######aaabbbccdeeefggecdedcdfedcbaacbaaaa##a#a####a############a##aa#accdcbcbbbbbba#####aaca#aaaaaaa###a#aaabaab", +"bbbbcccccddddfecbccbdc#a############a###aaaa#aaa#aa##aabcccc###########aa#aaaaaabaaaaaaaaaa#aaa#aaabbbbbbaa###a#aabaaabbbhie#.bfhfbaaaa###aaaaaaaaa#######a####aaabdhifbaa########aabaa###a######aa#####bccaa#####.#####a########afgeddccdcba###aa########a#a#######aa######.##########aabcbcccdffghihgdcddcbacbbeabaaaaaa#a###################a##aaaa#bcddcdcbbbab##a##aaaba#aabcaa####a#aaaaba", +"bbbbbbcccccdefedbbcacdc####aa##a#.##a#.##abb######a##aabbccc###########aa#aaaabbbbaaabaaaaaaaaaaaaaaabbbccbaa##aaabaabba##diic##adhebaaaa#aaa#aa##aa##########aabaaagjjf#a######a#aaaaaaa#a#######aa#a###bdddaa#a###.#a###########adcdddddcba#aaaaa#a###a##a##ba#b###aa####.###aa#####a#abcdcbbcdghihhgdcaaaaaabcfdccaaaaa#aa###################a##a#a##acbcdcbbcba#a#####aaba##abaaaa###aaaaaaa", +"aaaaabbbbbcddeedccebaccb###a####a####a#..aba##########aaaaccb.############aaaabbaabbaabbaaaaaaaaaa#baaaccbbaaaa#aaaaaaaa####fjfb###egebaabcb##aaa##############aaa#achkjbaa######aaaaaba#a#aa###a###########abba###################abaceddcbaaaaaaaa#####a#####a####a##a######.###a##abaaccddedeeffdghfaaaaaaaabbdfcabbaaaaa###############.#########a###bccbedcbdaa######a#abaaaba########a#aaa", +"#a#aaaabbbbbbcdedcccbabbb##aa######.######ba#############abcc##############aaaaababaaaaabbaaaaaaaaaaaaabbcbbccba#aaaaaaaaaaa#beihb##afgdbbcba#aaaaa######a######aa#abcilheba#####aaaaabaaaaaa#########a####a##a#aaa###############a#aaadedbbaaaaaaaaa##aa##a#######a##aab######.##aaaababceefcddcb#.#gfaaa#aaaaabcfgcaaaaaba########.#####################aabddcbcabaa##a##aaabaaaa######a######", +"##a#aaaabbaabbccdcbcbbbacb###a###########.aba#######aa###aacf#######.#######aaaaaabcaaa#acaabbaaaaaaaaabababbbcdcbaabba#abaaaaabfje#a#aehdaaaaaaaaba#####ab#a####aabaabijiebaa##aaaaaabaaaba##aa#####a#a###########a###a###########aaaaaabbbaaaaaabaaa#aaaaa#####a##abaaaaaa########abbabcdgeba##.##.bdaaa#a#aaaacfgcaaaaaa########.a########.#######a#aa###abccbbbaaaa#aa#abbab#abaa####aa#####", +"#####aaabbaaaabcbccccbbbcca###a############a#########aa##aaacb###.#.########aaaaaaaaabcbaaabaaaaaaaabaaaaaaaaaabcaaaaabaaaaabaabaejhbaa#aggcaaaaaaaaa####abb#a###aa##aabhigddbababba#acbabaaa###aa####a#c#a#############a#a########aaaaaaaabbaaaaaaaaaa#aa##a#####aaaaaa###aaa######aabbabege##b#######aa#a##aaaaaceecbaaa############################aaaa##aaacbbbaaa##aaa#aaaaa##aa#####a#####", +"####aaaaaaaabbabbdcbcdccbbba#aa####a##a####a######..##aaaaabab###.###########aaaaaaabbbbbbaaaaa#aaaabcbaabaaabbaaaaaaabbaaabbabab#bghcaba#dhfaabaaaaaa#aa###aa##aaaaaaaabeegbccbaaabcbbbaababa######aa#aaaaa##aa#.######aaa#########b#aaaaaabaaaaaaaaaaa#a##aa#aaa#aaabbab##a####ab#aabbbbcfhaaca##############abbabddbbaa####################.###a##a#aaaaa#aabbbbbaaaaaa###aaaaaaaa#######a###", +"#####aaaaaabbbbbccdbccdcbcca##########a#####aa##a######a#aaaabc###############aaacaabbabbbbbaaaaaaabccbbaaaaaaababcaa#bbaaaaaaaa#ba#eiebabaafhb#aaa###a#a####aaabbaa#baabbbigcebaaabcbbcdbbbcca#a##a###acbbaa#ab##########aaaa########aababbbaaaaabaaaaa##a###a#aa###aaaca##a#aa.bc#abbdccbdga#####.###########abbbbcdebaa##a##a##########a####.###a#aa###aaa##aabbabbba#a#####aaaaaa########aa#", +"#####bbbabbbabbcddddcccbbbcca#a##aa###a#################aaaaabb#a####.########aaaacaaaaaacaaaaabcaaabbcdcbbbcbabbbabbaaaaaaaaa####aa#cijdbababhfa#aa###aa##a##a#aaaaa#aabbbflggfaabacbaabbbaacbba##aa#abccbbaa###aaa#####a#aaaba###a#aaaaabbacbaaaaaaaaaaaa###aaaaaaaaaacaaaa#bbab#abbcccccbdc#################aabdceedebaa#########################b#####aa#####bbbabbaa#a####a#aa##ba########a", +"aa##aaabbbbccbbcccddcdccabbdfa####a###########aa######a#a#aacc#######.#########aaabababbaaaabbaaaaaaaabbbbaaaaaaabaabbbaaabaaaaacba#a#beijbaaaaehfa###########aa#abaaaabbbbdhjghffedccaaabaabaabbaaaacbcbcccbaa#aaaaaaaa#aaaaaaaa####aaaabbaadebbaaaaaaaaaaa###aaabaa#a#aaaaabbbbbbbabcdcccefe####.##.#######.##a#aacccccaa#aa#####.###############aaa###.#a###a##bbbbbaa#a########aaaaa##a#####", +"###ab#ababbccbcbccdddccccbbbeda##aaa######aa###abaa####a###abdb#a###.######aaa#aaabbbaaaaaa#abbbaa#aaaaabdaabbcbabb#aaaaaaaabaaacbcba####ejdbbbacgjd##aa#aa#####aaabbaabaabbejiiiihhggfbaabbbaabcba#bcdcdddddcaabbbbcbaaaaabaaaaaaa##aaabbbbcdedbcbaaaaabbaa#aa#aabbaaaaaaabccbbbbbcdccddffebb####################aabccccca###########.#########a####aaa####a##aa#abbaaaaaa########aaa####a#####", +"#aaaaabbbabbcccccdedccccedccdebabaa#aa###########baa##.##aaa#aca#######.#####aaa#aaabaaaaaabaaaacbaaaaaaabaaaabcbaabaa##aaabaaaaabaaaa###.cjgcbbbadiib##aaaaa####aaabbaaaaabdhlijjiiihfefcbaabbbbbbababdedfddedccbccdccbccdccccbaa#aaaaababcccdddcccbaaabbaaba#aaaabbaabbaccdddcdefffedeeed..################.######abcbdfbab#a###########################a#a#####aaaaaaaa##aaaa######a##.#a####", +"###aaaaabcbabccccdcddcccccbbccebaaaa##############a#a####aaa##abb##############aabaaababaaabaaaabbaaaaaaaaaaaaaabbcbabbaabaaaaaaaaaaaa####.afhdbbaabfihb.#aa###aa###aaba#aaacclljjiijigddecbaabccbabbbdbadcbeffffeffgghhhighgfhgffcaaababdbbbbcfddddcbbbbbccabaaaaaaababddehggfegjiedaaaa#a####a##############.######bcdcddbaaa##a###################a#a#####aa####aaaa#aaa#a########a#######aaa", +"aa##aaaabaaabbbdddccdbcddcccccdd##a#aa##aa########a######aaba###ab##############abaaaaacbaaaabaaaaaaaaaaaaaabbaabbaccbaaaaaaaaaaaaaa#########bfgbaabbdije.######aa#abbaaaaaaabellkkkkllkiiigfdcdcbabbcbcdcbcgijkjhhhhijjic#dcbcbddghffeeeihiggfgddedcccbcdcdcbcbcbabadeeffghhhebegdddb#########a#a####################babbbcbbb##a##################aa##a####aa#a###aa#a#aaa##a#######aaaaa##aa#", +"a#aaaaabaaaaaabcdcceccefcadgeceebba###a#aaa########a#####aabaa#aabda########a####aaaaaaabbaaaabaaaaaabbaaaabbbbaaaaaabbcbaaaabaaaaaaa#aa######.eiebbbbcfihc#.###abaaa#aa##aaaabellkjlkjklmnnmlkgfccbbdddeefghjijkkllkhd#cfeabcbbcbbdgjjhgecccehieeededccceeedddddefcdffcedbacdec#bbaba#########aaaba#########.#######aaaacccdbbaa####################aa##a####aaaaa#aaaaa#a####aa######aa#aa##aa", +"a#aaaabaaaaaaaabcccdddggedbdfccecaaa###aaba#a#######aa#.##aabba#aabc###########aaaaabcbaaaabaabaabbbabaaaaaabbcccaaaabbbbbbaaabaaaaaa#aa#aba###.bigbbbccdilid.##aaaaaa####aabbbcekmljgdfiijikmlmnkgdeefeeegieeddgdcghgdbabcfdebcccceffggfcbbbbbcefgedddcceeefdedcbccefgb####babedcaa##aa#######aabcda##.#############aaaaabcdcdbaa#########a########a###a###aabbbbaa#aa#aaaaa##aa######aaa##aaa#", +"##aaaaabbaaaaaaabcdceeffedccfgedcaaa##aaaa###a#a#####aa..##abaaaabbd#########aaaaa#a#bbbbbbaaaaaaabbbbbaaaaaabccbbaaabaabbbbab#aaaaaaaaa#aaaaa###ahibbcdccgjkg####a#aa####aabbcddegkhddgihhghiibdilmljjjjiiihfaaa##aeeedcbbdghfdbbdfedfedccbbbbdbffhfededeefhhfc#####cea#####aaabdfda.a######.##abdfb##########.###a##aaaabadefecb#a##########aaa####a##aa####acbbbaa##aaaaaaaaaaa#####a######a#", +"a##aaaaaabaaaaaabacddeddfdccefffd#aaaaabbaa#a#####a#.aaa###aaaa#abbdb########aaaaba#aaaaababbaabbbbbbbbbaaaaaaa#abcbaaababbbbcb#aa#abaaa###########fhdcccdcehihb###aa######a#bccdefggiglkjjhiihba#cglkjhiihgebcaaaaaa#aacdbbdefhfdbbeedbccbbbabdcbgjifefedeggfgfa#aa#a.aa######aaaacffba####.###abdeca######a###########aabbegffgedaaa##########aa####a##aaa#####aaaab#aaa##aaa#aa######a#######", +"##aaaaa#aaaaaaaaabbcdddceddeeecdfbaaaaabbbaa#####ab#########aaaaaabbc########aababbaaaaaaaabbbaaaabcbbabbaaabaaaaaaabbbbaaabaabbbcaaaaaaa##########.bhfcccdddefigc#abaa#aaaaaacccdegeiihkihhjhbbaa#.#a##a#..##aaaaaaaaaaaacaabaacefedefbbedcbaccdbcfgiihhfdec.addb#ba###aa######aaaaadgeca#######aceaaa#################aaabdgeeghffb########a######aa####abaa#####a#aaaaaaa#aa###a#.######aaaa#", +"a##a####aa#aaaaaaabccbccdedefebbef#baaaaaabaa#####a#aaa####aaa##aaaada########aaabbbaaaaabbaaaaccbbcabbbbaaaabaaaaaaaabbbbabbbbaabcb#a##a#########a##bifdccdddefgjeaaabaaaa##accbbcddfhehijhdb#aaaaa#a####a#abaa#aa##aa#aaaaaabbbaabefigffefdbcccdcbaacbbdhhfeaacbabb##a##########aaaaadhgb#####aabecaa########a###########baegfefgfeca##a#######a##aaaaa#aaaaa####aa#aabbaa#aaa###a#.#####a#aaa", +"#aa#####a#a#aaaaaaacccbbccdcdedbcfcaaabbbaaaaa####a###a###abdb####aaeda######a#aa#aabbbabbaaaaacddbaaaaabaaaaaaabcbaabbbaabbbbbbababa####aa###aaa#####dihecccdedeejgaabcbaaaaabcbbbcdeheggeabaaa####aa########aa###aaaaaaaaaaaaaaccbaabdegedddddddccbbbba#abaabcbbaaaa##a##.#.#####a#a#abefb#####abdfaaa#####aaaa#a########aaadfeeffffc#######a######aa#aaaaaaa#aa##aa#aaabaaaaaa#######.###a#aa", +"aaaaaa#aaaaaabaaaaabbcbbabbbcceedffdbaabcaaaa##abaa##aa###acefa####abdaa###.####a##aabbbcbcbaaaaabba##aaabaaaabaabbbaabbbaabbbbabbcbba#a##aa###aaa#####bhjgccdddefdhheabbaaababcbbabcdehfcaaaaaaaaa#aaaa#######aa###a##aaaaaabcdaabbbbabbbefedeccddcbbbaababbbcccca#a####aa#############aaceda###aabfebaa####aaaaa##########aaadefedegca########aaa##aaa#aaaaaaa##aaa##aaaaaaa#bcba#########aa##", +"#aaa#aaa#aaaababcbbbbccbaaabbbbdgffgbaabbbaaaa#aaa####a##abbgea##aa##bca#########a#a#bcbabbbbaaaaaaaa##aabaababbbaabaabbbbbbbbbaaaabbaa##a#####aaa######adhidddddfhdfigbcba#aaaaaaaacbcfdabaaaaaa#aaaaaaa#######bb#####aaa##aabccaaabdcaaaeeefeddefcbbbbaaaabcbbbcdba#####a####..#######a##abdb#aabcefdaa####a#aaaaa#######aaaaaabacefc#########a###aaaaaa##aaaaaaaaaaaaabaaaa##aaaa###.#####aa#", +"#############aabaaaabcbbaaaabbcceeeeeaaabbaa##a###ab#####abddb#####a##cb#######aa#a##aabbbbbbbaaaaabaaa##bbabbbaaabaabbbacbcbbbcbbbbaaa###a######aa##a#baaagkecdeegfeehfcbba##aaaaaaaaccdcbaccbaaaa#aaa##aaa#########a##a###aaabcaaaadeddbbdcdeigfdbcccbaa##cbabcbcdaaa####aaa######.######aa#debaacfdcaa#####aaaabaa########a##aabccdd#############aaaaaaa###aaaaaaaaaaaaaa###aaaaaa#########aa", +"#############aabbbcbbccbaaaabbccddeedca#abaaa#aa###a##.##aaaa#######aaaca############aaaaaabaabaaaaaa##a#aaaaabbaaaaabbbabbbcbbccbccbaba##########a##aaabaabejfddddehddhgdbbba##aaaaabbbcccaabaaaaa#a#a##a#aaa###############aabcaaaaaegeddcecacdghfdccbaaa#cbabcbac#######bba#################bcdcbeebaaa###aaaa#aa#a###a####abaabdcdcba#a##a####aa###aaaaa##aaaa#aaaaaaaaaaa#aaa##aa#########a", +"aca##########a#aaabdbcccbaaaabbccddeedbaaaaaa#aa#########abca#######a#aca############aaaaaaaaaaaaaaaaaaaaaaaaabbabaabbbbbabbbcbbbbcabbbba##########aa###aabbbeidbbccehefhhcbbaaa#aaabbaaabbcaaa#abcaaaaaaaaaaaaa#####.########aaabaacbedfdbbbdccccfhebaabaaa##a#acaba######daa###.######a####aa##acfdfdaa####aaaaaaaa###aca#aaaabaabccdeaaa###aa#aaaa##a#aaaaaa#abaaaaaaaabaaa##############.aab", +"aa#bb#####.######aaabcccbbaaaabbbcddeebaaaa########.#####abca##########abaa####a#####aaaaaaaaaaaaaa#aaaaaaaaabcbbaaaaaaaabbbbbbbbbccabbaa#a#########a#####aaaachdbccdefehgiebbbaaaaabaaabccacbaaaacbaaaaaaa#aaaaaa#############a#baaaaceddbaabcbebbefdcaaaaa###ba#baa#####.aba##############a#a##aacfghdcaaaa#abaaaaaa######acbababbbdbaa###aaa#aaaa#a#aa#aa#aa##abaaaaaaabaaaaa##############ba", +"a#aa#a#####.###a#aaabbcccbbbaabbbccccge#aa#######.#######abbba#######aaabbaa####bba###aaaaaaaaaaaaa#######aaaaabbbbabaabbaabbbbcbbbcbabbbaaa#a##a##########aaaabeccccddfgefhgaccaa#abbabbbbabbbba#aa#aaaaaaaaaaaaa#######a#####aaaaaabacdccabbbcecaacdfecbbaaaa#aaabaaa#####aa########aaab####a###aabeggbaaaaaaaaaaaaa#a##a###aaaabcccccaa###aaaaaaa#aa#aaaaaaaa#abaaaabaaaaaaa#a###########a#aa", +"###aaaa###a######aaaacccbbbbbbbabccccehb#a########..#####abbca#######aaaacaa####cca###aaaaaaaaaaaaa#######aaaabaaaacdbaaabbbbbbbaabbbbcbccaa############a#aaaaabaccbdccegeccffbbaa######.#abaabbbaaaaaaaa#aaa#aaaaaaa#a##########aaaabbcc#abbabaabaddcbceebbba#aaaaaba######a############aba###a##aaaccggbaaaaaaabaaaaabaaaaa#a#bbabbccdb#aa###aa#aa#aaa#a#aaabaaaaab###abbabaaa###a#a########aa", +"###aa#a######.######aacccbbbbbabbbccccfheaaaa#############bbcaa#######aaabcaa#####aa####aaaaaabaaaaa#aaa##aaabaaaaaacdcbaabcbbcbbbabbaabbbbca#a######aaa##a##a#aaacabccdeggacge.#aa####a#baaaabbabaaaaababbaaaaaaaaaaaa#########aaaaaaabda#aaabbbacbcdbbcdeca#a#aaaaa#a#aa#aa#############aa#####a#aaabcfgcabaaaaabaaaa#aaa#####babbbcccc##aa#a#aa#aaaa###aa#aaaaaaaaaaa#aabbaaaa###a#a#####abba", +"###aa##aa##########a#acbcccbbbbbbbbbcceffebaa#############accbaaa######a#bdcaaa####aa##aaaaaaaaabaaaaaaaa#abbbaaaababcddccbcccccbaabaaabbbbbca####a######aaaaa##a##bbabcbdgefeed########a#a###ab#aabbbaaaaaaaaaaabaaabba#####a#.#a##aaaabca##abbbaccbbdcbcdedb#aaaaabaaa###aaa#########aa#aaaaaaaaaaaaabceecc##aaaaaa#a#aa########abbacccc##aaa#aa##aaaa###aabaaaaabaaaaaaabaaaa####aa#####a#a#a", +"b###aaaaa#######.##a##abbdcbaabbbbaabccdegea########a#####abcbba###aa####acccaa######a#####aaaacbbbabbccbbaaccaaaaabbbcccbcbccbbaaaababaaaaabc###a#aa#####a#aa#a#aabdaaacbbafhgbfa.#####aaaaaaaaa#aabaaaaaaaaaaaabbbaaba###a###########baba##aaaabacaabccbccdeeaaaa#aaab####.########.##aabbbaaaaaaaaaaabccaccba##abbaa###a##a###a#aabbccca#aaa#a#abaaaaaaaaacaaaa#aaaabbaaaaa#aaaa#a#######a##a", +"baabaa#######aaa#####aabbccbbaaabbaaabccdfeba#######aaa###abcabbaa##aaa####ddbaa######a###aaaaaaaaaabbcbbbbbccaaaaaabbbbbcccccbbbaaaaaaaaaa#abca##a#aaaaaa##aaaaaaabcaaaabaabgicce##.#a##aa#a#aaaaabaccbaabaaaaaaaaabbbaaa#aabb##########aa#aaaaaaaaaaabccccddfebaaaaabbaa################bbbbbbaaaaaaaabbbc##acbbaaaaaa####a#####aabbbcccb###aaaaaabbaaaa#a##aa####aba#bbaaaaaaabaaa#######a##a", +"baaaaa#######aa#######aabccbabaabbbaabbbcdgdb#a########a##abdbbaaaa##aaa##abdcbaa#############aaaabbbbbbbbbabccaaaaaaaacbbbcccbccccbbaaaaaaaabbca#aaa#a#aaaaaacbabaa#aaaaaccbbjgabc###bb######abaaabbcccbabbbaaaaaaaaaaaaa##aaaaaa#######aa###aabcbaaaabbbccdeeefebaccbbbbb#.####a####.###abaabbbbbcbaa#aaabca.##acccbaaaa########aaababbcba##abaaaaaaaaaaaaaaaa#aaa#baaababa#bbaaaaaaa#######aa", +"aa##aaa###############a#abcbabbaaaabaabbbcffcaa##aa##aaaa#abbbbaaaaaaa##a##abdbaa##############aaaaabbaacbabbbcaaaaaaaabbbaaabacbccbbbaaa#aaa#aabb#aaaaaaaaaaabbbbaaaa##aabbbadiabbc.##c#######aaaaaabbccbbabbaaababaaaaaaaaaa##aa#######a#####aabbaaaabcbbbcddcefhgceeaabba##############abbbbbbcbaa###.###aca####aacdba#a#a######aaaabbcbbaa##aaaaaaaaaaaa#aaaaaaaaaaaaaa#bababaaaabaaaaaaa#ab", +"cb####aa################abcbbbaaaaabbaabbbdgdb##a#aa#aaaaa#abaabaaa#bba####aaddba#######a#########a#abbaaccccccbaaaaabaabccbbabaabcbbbbaaa#aa###acda####aaaabaaabbcbbaaaaa#bcbcebbccd#.aba######aaa#a#acbaaabbbbbaaabbdbbca##ba###abc.#.####.##a#bbaaaaaaccccdecdefghgfccccb#.####.#...###aaaabbabddba###...##bb#####a#bcba##########aaabbccaa###aaaaaaaaaaaaa##a#aa#aaaaaaaa##ababbaabaaaaaaaab", +"ec##########a##aa#.#####abbcbbaaa#aa#ababccfffcaaa#aabaaaaaabbaaaaa#aba###aabbfdaa###.#############a#aaabbccbbccaabbaabbbbbbbbabaaabbbbbaaa#a###aacdba##aa#abbacbbcbbbaabaaabbceabccde.#c#aa######aaa#aaa#aaababbabaabbdefecd#aaaaaaec#.#########aaaaaa#aacdcbdbabdfegddffdba##.#.###.###aabbbbabbccbba###.#.##bc#######abbba########aaabbbddcaa##aaa##aaaaaaaaaa#aaa#aaaa#aaaaaababaabbaaaa##ab", +"bca######.#####aa#######abbbbac#a##aa##abcdcehfaaaabbbaa#abcbbbaaa#aaba#####acegdaa####.############aaaaabbbbccccbabababcbbbbbaabbcbbabaa##aaa###aacebba###bffcdbcbbcbbcaaaabbbhbabbcee.##aa##aaa#acaabbaaaaaaabccaaaaaabdefge##aaaacea###########a######abdfdabaaaaababaceeb###.#...#.##aaabbbabbbaabaaa###..##bea###a##a#aca#a#a#####aaababb####aaaa##aaaaaaaaaaaabaaaaa#aaaaaababaaaaaaa###ab", +".#a###########.b########aacaaaacaaaaaaa##acdffgbaaabaaa##aaehdbaaaa#aaaa#####acfgbaa#########.########aaaabbabcdecbaabbabbbbbbbaaababaaaa######a##aaddbaaaaab##a##abccccccbbaabfhaababgd.######aa#aaaaaaaaaaaaabacdddbaaaaaaddeda#aa#ba######..##a########abdcaaaaababcabbbcddb#a###..#.##aaabccbbaaaaa#########abed#########cb#a#a####a#aaaaacb###a#aaa##aaaaaaaaaaaabaa#aaaaabaaaababaaa######", +"#########aaa###a########abbaaaaaaa#a#aaaaaacdegeaabaaccbaa#acefcaa###aabba###aadfdbbaa####.#############ababaaabcccaaaaabbbbbbbabaaabbbbaaa#####aaaabdeaabbba########aabdedcbabbffaababhd########a#aaaaaaaaaaaaaaacedbabaaba#bfggcaaa#########..#.########aabcb#aaaaaabaababccddba#..##.####aaabbaaaaaa##...#####acecb########abba#aa#a#aaaaabbca##aa#aa#aabbaaaaaaaaaaaaaaaaaaabaaaaaabaaa#aa##", +"##########aa###a#####aaaaaaa##aaaacc#a###aabbcefbabbcfcddddbabgfa#a#aaaadbaa##abdedcaaaaaa#############a#aaaabbbbaacbbabbaabbaaababbaabababa##a##aaaaaccbbbb########.###abbacdcccgbabbbcida####aa#a#baaaaaaaa##aaabccaaaaaacbbabggb#a#####aa##..##aa######aabbcbaaaaaaaba#aabbcccca#.########aaaaaaaaa###...#######abdec########abb#aaaaaaaaaaabcbaaa#####aabbbb#aaaaaa#abba#aaaaaabaaaaaaaaabb#", +"###########aaaaba###aaaaaa####aaabdebca###aabbcfgfbacdccdeheaadgea###a##dcabaaaabdedcbaa##################aaaaabbbccbaabcbaabbbbabbabbbaaabaa#####aa#abddbcb##a########a##.##accdeedbcccejcbaa####aaaaaa#a#aaaa###aabbbbaa#bdbb#chfa####a########.###########babbaaaaaabaa#aaaaabbcdc#..######aa#aaaaaa###.#..#####a#abdeba#######bbbbaaa#aaaaaabcca#aaaa#aaaabbbaabaaaaaaaba#aa#bbaabbaaaa#####", +"######a##a###a#aaaaa#aabaaa##aaacddbbcaa##aaaabdifdadeeddfffaabdddbaaaaabd#aaaaaacfedcaa#################aa###aaaacccbbabbbbaaabbbbbbbbbaaaaa######a#aaacdddaaa#########a######aabbicceedghcbb##aa#aaaaaa#aaa#a####aaabbaa#adffbafgd####aa###################aaaaaaaaaaaaa#ababaaabbbcb#.####aaaa#a#a#a##..########a#aabbcdd#.###a##bbaaaaaaaaabbbbba######aaaacbb#abaaabaa#a#aaaabaabbbabaa####", +"######aaaaa####aaaaba#abaaa###a#bddccaaa######abcfgghhhfdfffcacbabdecca#bca#aba##aeffeba##############.########aaaaccbbbabcbbbaaaababbbbbbbaaaa######aaaabeeaa#aaa######a###a#aaaabfgdbbddhhccb###aaaaaabaaa###aa##aaaaaaaa#bffgd#cda##a#a######a#a###########aaaa#aaaaabb#abaaaa#aaaabbca####aa#aaaa####.#############aaabcdc#####a#abba###aaabababc#aaa##aaabcaaaaabaaaaaaacaaaabaabbbbbaaa###", +"a######aaaa##a#aabbaaaaacba##a##acccddbaa#a##aaaaacccdefefefdacaaaacgebcdb#a##aacbbegfdba#aba##############aa###aaabcdbccbbabcbbbbbbbaabbabaaa###a###aaaabcdb#baa#a###########aaabddgcdcbbcfidbcb#aaaaabaaa#a#a#abaa###a#aa##dfffeaa#####a#####aa##b.######.###aaaaaaaaaacbacaabaaaa#aaaacccaa####################a########abceca###aa#abaa#aaabaaaacda#aa###aacaaaaaabaaa#aaabaaaacbbbbacaaaaaa", +"aa##a###aaaa#a##aaaaabbbbbbba####bbbacbaaaa##aaaaaabccbdedcefaccaaa#accccaa##aaabcddfgefeeffea################aaaaaabbcbcbbcbabbbaabbaacaaaa#a#######a#aaaacfcaaa##a############aacdee#a####eifccc#aaa#ccaa###aaa#ba###a###a#befffd######aaab###aa############aaaaaaaaaabbcbcdbbaa###abbaaabccdca...#######aa#a####a######aaaabcdc######aaaaaaaaaaabbcdbaaa##aababaa##aabaaaaaabaa#abbbbaaba#aaa", +"#aaaaa##a#.###a#aaaaaceccbbbab##aaaaaaaaaba#aaaa#aaabccbcdddgfdaaaa######aa##a#aaaeggihgeefeddeca###############aaaaababcbbbbaabaaaaabacbaaa##a#####ba#aaabadgeaa#a##a####a##a##aabbeeaa#####bhibaca##aadbaaaaaca###########aadfddfda###abaabb#aaba#####a######baa#aaaa#abdc#bccbaaaa###ba#aaabdfeec#########aa#aaaa####aa#aaaaabde###a###aaaaba#aaaabbccbaaaaaaaaaa#a#aaabaaabbaaaababbbbaabaaa", +"##aa####a#####aaaaabcccbbbcbbaa##aaaaaaaaabb#baa##aaabbcccdefgiecbaaa##aabba###a#affghihfccdddddeca################aaabaaaabaaaaaaaaa#aaaabaa########aaaabaabcgcaaaadda#aa#######aacdde#######aegbbdbaa#adbbaabcaa#aa#########acfeeecaaaaaaaabbaaaba###########aaaaaaaaabddfbaaababaaaaaaa##aba#acefgca###aa#####abb######aaaaaaabcfa##a###aaaabdaaaabbbbdb###aa#aaaaaaaaaabcbbbbbbabaabbbbbbaa#", +"####aaaa#a#####aaabccccbaabcbcca##aaababbabbabaaaaaabcccbacddefffdccabccdedaaaabdeeffgggeccddccdcdca#a##############aaacaaaabaabaaaaaaaaaaaaaaaa###aa###aaaaacdgcaaabaaa#######a##abdchaa######.cfcbcb#a.bffcbbbab###aaaa###a###ceedddabcbaaaabbabbaaaa##..#####aa##aaaa#acecbbcbaaaaabaaaa##aba#aecbccdcabaaa##abbaa#a##aaaa##aaaabdd##aa##aaa#aaababbbbbdb#a##aabaaaaaaaaaaaaabbbbbbcbbbbcbbaa", +"aaabaaaa####aaaacccbbcbbbaaaabdaaaaabcaabcbbbbbaa##abcddcbcdefedffedbdccdeec#aafffdddeffcccbcdcccccccaa#############aaaab##aacaaaaaaaaaaaaaaaaaaa###aba#aaababdefaaaaaaa##a###aaaaabccgcaa#######bgcdeca##bhgbabaac##a#aaa##a###befddfdddbddbaacabbbbaa####.#######a#aaaaaacbaabbbaa##ababa##aa##acaaaabbcb#aa#a#aaa##aa#####a#a#aaaabeca#aaaaaaaaabaabbbbbdb#aaa#abaaaaaaaaaaaaaaaaaabcbaababaa", +"aaaaaa#aa#####abbbcbbabcccbbaaabbccccdbabccbbbbbaaabbcddcbceeeddeggddfbcdeec###dffedddeddcccedccccbbcdb#################aa#aaabaaaa#baabaaa#aaa######aaaaaaaabbcdfaaaaaaa#a####a#aaaabge##########bhcbccaabdeeaaaa###a###aaaaaabceedefeeedeeccabbabcbbaaaaa##.#.#######aaaabbb#aaaaaaaaaabaa##a##aaa#acbcabca###aa####aa#########a##aaaedb#abaaaaaaabbabababccb#aaaaba#aaaaaaaaaaaaaaaaabbbbbaaa", +"aaabaaaaaa###aaabbbbbaaaacbbbbbcccddefdaabbbbccbbbbabbccbcdddddeeeffefcedffedbabeeecddcbcccbdbbbabbbabba#aaaaa##a######aa#a##aaaaa#a##aaaaaaaaa###aa##aa###aaabbdedaaaaab#a####aaaaabbgha#a########becaccdfgddda#aa#aaaabaaa#a#addeecdcdfeeeddcacbbbcbbaaaaaa###########aabacbaaaaabaaba#baba#aa##bbbdbacaabcb##aaaaaaaaaa#########a#aaabddbaaaaababbbbbaaabcccbabaaaabaaaaaaaaaabaaabaaaabbbbaa", +"abbabbaaaaaaaaaaaabbabaaaaabbcbbcdedfggccbaaabbbbccccbccddeddccdddcddecddeffddecddccacbaacbbbbaabaabaaaaaaaaaaaaaba####a###ba#ba#aa#####aa#aaaaa############aabbcdebbbaaaa########ababdhf#a#########afecfffebceaa###aaa#aaaaa##abeeddddeegffdcfdbbabcccbaaaaba###########aaaabaaaabbaaabbbaabbaaaaacdcaacaaaabca##aaa#aa#aa#aa#######aaaaacee#bbaababbbbbbbbbccdcaaaabbaaaabbbaaaaaaaaaabaaaaaab", +"babbaaabaaa#aaa#aaaaaaaaaaaabbbbcdbadccdbbbaabbbbbcbbccdeeedeabcccccccccdeedfddcccdbcbaaaaaaabbbaaaaaaaaaccaaa#aa##aaaabbaab#a####aa####aa##aaa###############abcdedbcba#####aaaa#aabbdhie.#####a#####fgffececeda###aaa#aaaaaa#cddecddcddefeegefeccbccccbaa##aaa#.#####.##aaaabaa#aaaaa#aab#bcccbbccbbaab#aaaabcbbaa#aaaa#a#a######aaa##aaabdfdbbbbabbbbbbbbbbccccaaaaaaaaaaabbbbbaaaaaaaaaaba#b", +"bbaaabbaaaaaaaaaaabaabbbaaaabbabcedcbbabccaaaaabbbaabbceffcccbbcbbbbbbbbddcdddbbbabbbbaa####aaabaaaaa##aacfeaa######a##aaabbbaaa##aa#a#####bcca#a##aab##aaa#aaaacccgdbbb#######aaaaabbbdhhb###########aeifddbbceda#aaa##aaabaabefffcdddccdeeeedeffefeddccbaa##aaa###.###..aa##aba##aaa#aaabaaabccddcccaabaababaabcca###aa#aaaaa####aa#####aaacffbbbbbbbbbbbbbbbbcdcaaaabbaaaaaabbaacbaaaaaabbbab", +"babbbabbaaaaaaaaaaaaabbbaaaaabbbceddcbaaabbbbbaaaaaaabcdffdcabbccbbaaaabbbbbbbbaaaaaabaaa#a##aaaaaaa####aadd######a########abbaaaa##a#####a#aa########aaaaaa#aabbbbdgcaaa###aa##aaaaabadfgb######aa###aadidcdbaceca#aaaaaa#abcdeeeccdeddccddeadeefffffffecbaba#######.###.##aa#abaaaaaaaaabcaaabaabcbd#abaabbbbaaabdba#a#a##a###aaaa#########aacefdbbbbbbbbbbbbcbcccaaaabaaabbaabaaccaaabbaabbaa", +"baababbbbabaaaa#a##aaabbbaaaaabccehdbaaaaaaabbaaaa##aabdgieccccbcbaaaaabaaaaaaaaaabaaaaaaaaabaaaaa###a###aaa################aaaaaacba######a#a##########aaaa#abbbbbcdhb##a####aaaaaaaacbfe.##aaaaa#####aadhcbbaaefbdb##aaccddfgedbddccccbbcdedceceggfeefefdcbaaaa#####.###.###aaaaaaaaa##aba#aaaaababdb#aa#aaabaa###bcbaa#######aa#############abdffcabbbabbcbbcbcbcdcbbaaabbbbbbbaacabaaaaaaaaa", +"bbbbabbbbbbbaaaaabdcabdcaaaaaabbcdffcbaabaaabbbaaaaa##bcgjfbbbcdddcbbbbbbbbbaaabaabbbaaaaaaaaaaaba#########a#a###############aaaaaabaa#######a######aa#a##aaaabcbabbcceda#aaaaaaaaaaabbbec.a#aaaaaaa####aadhcabbbeecbaaadefggfeddcddcccccbccdccdddeghggeeeddcbaaaaa############abbaabaa#aaaaaaaaba#ba#aaaa#abaaaaa##aabbb###aa#a#a##a##########abbcffdcabbcbbbcccbbccccbaaaaaabbbbaabbabaaaaabba", +"bbbbbbbbbbbbbbaaabfdcccbcbaaaaacdceebaa####aaabbbbaa##bdghfcbaaacdddccccccccccbbababbbaaaaaaabbbaa#a##aa#a#b##a#aa###a#######abaa###aaaa##a################aaaaabbbcbbcffaaa#cbaaaaaaaacec.#####aadea##a#aabgdababdfda#adfggeddccccbbbaccbbcbcddddgghigffffbabbaaaa##########ab#aaaaaaaaaaaaa####aaaabaaaaaaaaaa####a##aaca##a######a#########acbbbbcdefdabbaabccbbbbccccbcbaaabbbaaaababaaaabcc", +"bcbbbbbbbbbcbbbbbcecccbaccedaaabddcaaa#######aabcbbbaabdfhfdcaa###acdcabdfeeedcccccbbcbbaaaaaaacbaa###aaaa#aaa#####a#aa##aa###ba###aaaaaaaba############aa#aaaaaaaaaabbbfgaa#adbaaa#aaaaehaa###aa#adea#a#aaabgbabacefdb#dfffedccbbaaaaaaccbbcdecdggihihhfdffcbbaaaa###aa###..#aa####baaabaaaaaa#####aaaaaaaa#aba#a###abaa#cbaa##.##aa####aa##aa#baaaacccefdbbabbcccbbbdccdbaabbbbbbbaaabbaaaaabc", +"cabaabbbbbbcbcccccddb##abaccbabbdbcaa#a##a####aabdcdbbcdddghcbaaa####bcacigggecbbbcbcbbabcaaaaaabaaa#a##abb#########a##aaaaaaaaaa###aaaaaaa########aa##aaaa#####aaaaa#acegfaaa#aac##aaaachfc###aa###aabb###a#bbabccddefdceffedbcaaaaa#aaabbbbcdegihhhhgggdcffecabaaaa##a##.###abca#aaa##aaaaaaaa######a###b###baa####aaaaaaaaabca###############aaaabbbbbbdfebbabcccbcdcbbdcbbaababbabaabaaaabbb", +"febaaaabbbbcdcccccb#####abbabbcccbbaaa####aa#a#abdeccbddeeehgcaa#a#aa#addhifdddbbccbcccbbbbaaaaaababaaa#aaba####a##a#a##aaaa#aaaaa#a##baaaaaaa#####b###aaaaaa##a##aaaabcefihefc##aaaaaabbdha####aaaa#ab######aaaabbccdefegffdcccaa#a##aaaaaabbehhhhffffcddbdcdbbba#ac######..###bb###a#abaaaaaabba#####aaa######a#aa#####a#####bbca###########a##aaabbbaaaabdfdbaccbccbcbbccdcbbbbaaaabaaaaaaabb", +"dedbbbbbbccbcdccddb#####bbbaacccacbaaaa###aaaaaaacfdcbcdegghigbaa#aaaaaadfhgedcccccbbbbbbbbbbbbbbbbaaaaaabbba########aa#aaaa#abaaa####aaaaaa############aaaaaaa###aaaabcfghgihfbcb#abaaabbge####aaaaab######a#aaaaaaccdeeddfdbcbaaa##a##aabaafhgggfedccccdccbaaabaaaaaa#########a#####a##aabaabcaa#aaa#a#####.####a###########a#aaaba##a####a#aba#aaaabbaaaaabdeecccbbcbbccccdcbabaaabbbaaaabbba", +"bccdcbbbcccccbcdfda#####acbabcbaabaaa#a###aa#aabbbefedcdffiihhcaaaaaaaabacfffefedcbbbbbaaaabbbbbbbbcaaaaaabaaa####a###a##aaaaaaaaba#####aabaa###########a#a####a###baabccghfhiieaa##aaaaabdga##a#a#aaaa######aabbaaabbbcddegdcbbaa##aaaaaaabbfedfddecbbbbbbaabbabbaaaaaaaaaa####aa####a#a#aaaabcbaaaaaaaa##############.######a#a#aabbba#a####a#aaaabaaabaaabbabcfedcbbbcbccccccbabbabaaaaabbccb", +"bbccccbbcccccdddeca####aabbccca##aaaa##a#####abbbbeeffeeccfjjifbaabaaabbbcdecdeffdbcbbbaabbbccccbbdcbaaaaa###########a#a#aaaaaba#a######aaabcaaabaa###aa#aaa######acedbcdfihfhifba####aaaadhc###aaa###########a#bbaaabbccccfecaaacca##aaaaaccffdfccedbbab#a#aaaabbaaabababaa###########aaa###bbaa#aaa#abaa##########.########aa####a#aabba#a###a###aaaaabaabaaabbbcdfedbcccbcccccabbbbbbabbbbbbc", +"bcdcbbcccccddddddba####abbbbdca#a###a###aa####aaabcededcbbgiijjhcabbaaaaaccddddcceedddddddeeefedbbcbcccbbbbaaa#a###aaaaa###aaaacaaa##a###a##acca############acaaaaa#abbccdghccggfcaba#aaaacggdaaa###############abbbaabbdeefedbaaaadda##aabbchedeefedbaaab#####aabbaabacbabaaaa########aa#a###aa####aaabba##a##.#############a#a####aaa##abdba#########aabbaabbabbaabdeddcbbbcccccbbbbaabbbccbba", +"bbddccbccdccdcebcbb#####abccbcd######aa##a######abcddcdddeggiihhhdaaaabcccceedccbbcbbccbccdeeeggfeddccdeccbbaaaaaaa#a##aaa###aaaba#a##aa######a#####a######aaaaaaabaaababcehb#adcbdbba#aaabdceaa#################abbbbbacgeeecca###bedcaa#adfhccdffbbbba###a####aaaaabbbbaaaba###aaaa##########aa#.##aaaaa#aa#b######a#######aaaa##aaaa###abcdb######a#aabcbaabaabbaaabcdedbbbcddcbbbbcabbbccbbb", +"bcdfdddcccdddcecbb####a#aabccabaa#####aaaaa#####abbccdedeedcijfggfabaabbbbccddccbbbabaaaaaaaaabbbgihihffedccbbbbbbbba#a#aa####aaaaaaa##aa#######a###aaaa########abaabbbbaccega#cdaaabaaaaabbfea#a#################abbbbbaeedddcbaaabacceccefihdccedcbaa##########aaaaaaabbbaaaa#####aaa##a############aa####aaaa######a#####aa##a##aaa###aaa#a#abc#aa###aabcaaaabbbbbbbbbbcddcbccddcbbbbabcccdcc", +"ccbcffhfdddddccadbaa#####aabbaaba##########a##aaabbaacdddfeehjifgha#aabcbacddccbbbbbabbaaa#aabcccefgdddeffeecdedbbbbcba###aa####a##aaaaa##a###aa###aba#aa######a#aaabbba#abbfcbcccccbaaa#abbfjg#aa###########aaabbaaabbcbdedcdbbaaabbbcceghhiiedcedbbaa######a###aaaa#abaaaaaaaa##aaa##a##############aa####aaaaa#####ab#####aa##a###aa#aa#a#####aaaa##aaaaabbbbabbbbbbbbbbbbdddccddccbcbbbcccdd", +"eecbdggfdddedcacda####a###abbaaca######aa##aaa#aabcababcdeeedgigdfgbbcbbbbbcccbbbbbaaaaaaaaaccddddefdecccbbcbbddcbccddedcaaa#a#aa##########a########adbaa#########aabbbcbcabbdcdcbbbcbaa##abbfiaaa##############baaabbbbccedcccbaa#abbbbbefgihfdcccbaaaa###a######aaba#abaaaaaabaa#aaaaaa######...#a#.#####aa#aaaa########a##aaa###a###aa#aa#aaaa#aabbabaaaaabcbbbbbbbbbbbbbbbccdeddcccbdccccdde", +"eedfhhfcba#abb##a#####a#aabcaaccbc#####a#aa#aa###ccbbbabcdfffhgifehfebbbabbcccbbbbbbbbaaaa#ccdcddfghfeccccbbbbabcddegcbccdcaaaaaa###a###a######a#a##accba#########aaaabbccbbcbcehb###cbba##bdehe###############aa##aabbbccdcbccba##aacccbcceffedcbbaaa#####a######aaba##aaaa#ababcbbbbcbaa########.#.##a####a####aa######aaa###aa####a###a##a#aaa####aaadbbaaacccbbbbbbccbcbcccbcceeeeededcdbccd", +"dgghigdb##a#a########baaa#abbcbdbbb#####aa#aaaaaaabaababcdegiihdggffdcbaabbbbabbbbbabaaaaa#ccdccdegedccbbbbbbcbbbbaadbabaacdb###aa###############aaaab#aa##a#######aaaaababbbabbfieaaaa#aaa#chke.#########..#aaaaaaaaababbccbbcbaa#aabbcbabcdeedcba###a#####a#a##.###baabbaaaaaaaabbaaba#########....#.#######ab#a#######a######a#########a##aabba###aaabbbbbbacdcbbbbcbcccccbdddeededegeddddcdc", +"dhghhfa##a######a######aabaacccedaaa#######aaaaaaaababbbccdghgfedgfgcabaaaaaaabababaabaaaaabdcceeeecdbbbababbbbccbbbbbabdbabcba#a############aa##aaaaab#aa###########aababcbbaabeggh######aaagj##############aa#####abbaabbbbbabbbabcabbaaaabcddccba#######.###########ccaaa###aa##aaaa###a###..##....#.aa##a############aaa#####a#####a###aaa#aaaa#aaacaabbbbbbeccccbbccddccdegghhgfeegd#bddccc", +"ffhhhe###########a#####b#bcadddcbaaaa#####abcca#aaaaaaaaabdhihgddfgfgcaaaaaaabbbabbbaabaaaabedcefecbbbbbbabbbaaabbacdca#aaa#bbdb#aaa#########aa####aa#a###a#####.###aaaaadbbaabaddcggbaaaa#bbdia#a##########aaa###aaabaaaabbbbbbaacefebaa#aaaabcccbaaaa###########.#.##ad#####.##aaa#aa#aa#####...#...###ab#ba######a###a##ab#####a###aaa##aa#aaaaaaaabbbbbbbbbbceddeeccbccccddfhijjhggghb#bba##", +"#afhgcaa###########a#a##aabcddca###aa######abbbabaaaaabaaaeiiihgbbgeddaaaaaaaaabbaabbbaaaaabdcccddddccabbbbacaaaaabbbaaabaa##acdd###a######..a#a#####a#aa##a########a##aaecb#abbbcccfgaaaaaaaeia#a#a##############aabbaaaababbababdgeca####aaaaabcbbba#####a####.#######da##############aaaa#######.##.#.#ba########.#a#aa##abba##aa#aa#aa###aaaaaaaaaabbbbbcbccccefgeeccbccbbbbdfiihgggeb#aaaa#", +"##bhgd###############ab#ababcdd###aaaa####aaaaaaaaababaaaadhhigebabfddcaaaaaaaaaaaabaaaaaaabcbbbcbbcecbbbabbbaaaabbaaaaaba###abadea#########.#a##########aa#a###a###a####aabbabbaadccghbbbaaabfi#a##a###aa####a##a#aaabaaaaaaaabbacfdba##a#aaa#aaaabbb######a######.##a#######aa#a##a#a####aa#####a#.#a####aa#########aaaaa##aaa###aa#aaaaa#aaaaabaaaabcbbbbccccceeceeeefedddcbbceeffhgfebaa####", +"##.dhdb#########ab###bdababaddc######a###.#a######aabacaaaadghfdbbabecdba###aaa#aaaaccabaaacababbbbbbbcbcbbcbaaaaababaaaba####abbcfbaa#aaa###.###ab#####aaaa##a######aa#ba#aabbbabdcabefbcaababhe#a##aa##aa###a#####aabba#aaaaabbbefcba###aaaa#aaaaaaaa#########a#.##############aa#bb#aaa##a####.###########aaaaa#######aaaa###a####a##aabaabaaaaaaaaaabbbcccddebbbbdedefdcccccbceeghgfdaaba#aa", +"aa#aeea##########c####ba###aca#####aba#############abcabaa#acdefccbacdbdc##aaaaa###aabdbaaabbcccbbbbbbbccbabcabaabbabbaaaaa###addbcdba#a################a####aaaa#aaaaaaaa#aaacbabdcbbbehca#abbeh#aa######aa######aa#aacfbaaaaaabbdgdbaa###aaaa#aaaa########.###aa#a.###########aaa#bbaaaaaa####a#.##.#######aba#####a#############a#aaaaabbba#bbbbaaaaabbcddddddbaabcedccbaadfdcceeggdbaaaaaaa#", +"aa##ada#a########aaaa###a###a######abaa#########aa#abbbaaaabbcddeeebcdbabb#aaaaaa####aaaabcccbccbaabbbabccbaaaaaaaabbaaaaaaa##aabcccfeb##############a####ab#aaa##aaabbaacababaaaabcdbccffc##abeh.##aa###a#########aaaaacbabaaaccddfgdbaaa##aaaaaaa#######.##.#######.#########aaabaab########a#a##.#########aaa#####aa##a#aa###bdaaba#aa#aabaaaabbbabbbbcddefecbcbaabbdcbaabcecccefgcaaaaaaaaa#", +"aaa#aaaa#aaaaa#####aaaaaa###########a#####a##ab#a##aacabaaabcccbdhedfdbbabc#aaaaaaaba##aaaeheaaaaaaabbbacddbbaaabbbaaaaaaabc#aa#a###cfgb#a#########aa###aaaccaaaaaaaacbabcdaacbaaabcddcccgfcaabeg.#a#aa#a###aaaa####aaaaabaaaaaaceefhfdbaa###aaaaaa########.####.###.####.####aa#abcbaaa####aaa#############aaaaaaaa#aaaa#ba#babffb#acb#aaaabaaabbccabbcccfgdaa##bcbbaaacbcbacebbbcddbbaaa#a####", +"accccedaa#aa#aaa##a#aabda#################a#a#a##aaaabbbabbcccdcccfcfecbaaceca#aacdbcccba#ahgabaaaaababbbccccbaabbbbbbbaaabcb###aca#aabcc##a##########a###a#abaaa#aaabbddddbbbcbaaaaabcdddhecccg######ba#a##.#a###aaceca#cbaaaaacdefhgfcaaa#aaaabba#########..#####...#.#######aaabccbaaa####aa########.####abb##aa#aaa#a#ba#abbefba##bbbaaaaaabbccc#ccddeffcaaaa#baaaaabebbbbcbbbbcbbbbbaa##a##", +"#abeeebaaa###aa###aa###aaa###################aa###a#aabbbbcddddccefegfcca#adhbaacccaaabcbcdecaaa##aaacabdabdcbaabbabbaaababbcb#aabb#aa##dea##aa#######aaa##a##aabaaaacacdfebbbbbbabccccfeddfgfed...#a##aa###########acdbabbb#aa#acddegfecbaaaaaaabaa#########...#####.#########a#abbbabba##aa#####.##....#####a##aaaaaaaa#baaaceeebaaaaeedbbbabbbccb#cedddcccbaaaaaaabaa#bebbbbbbbbbbbbbaaaa####", +"##aadba#aa##a#######abbda################a#######aaaa#ababccdeeddffhhgccbaabefdbbaaa#aabcbbabca#aaaababbbbcccbaaacaabaaabaaaabbaaaab#aaaaefaaaaaaa#.###a#a#a######bbbaabccabbdcbabbcbcdbbaaaefeiiffa####a#######a##aaaaabbcba#baabdddefffdcaaaaaaaaaa##########...##############aabbbbbdabaaa###.....########aaaaaaaaaaaaabcccbdfebaaaaaacfdccbcddc##baabcbabaaaaaaaaabaaaedbcbcccccbbccbaaaaaaa", +"a##aba#a####.######a##bgb#######a########aa#######aaa##aabbcceedddeghiebaaabccebaaaaaaaabaabaaabbaaabbaaabbbbbaaabbaaaaaaaaabbccbbcba#####cfebbabbbacaaaaaa#aaaa###acbbbbbbbbcbaabbbccbaaab#.aceffdfghfa#a####aa#aa##acbacbbbaaaaabcedcddedbaaabaaaaaa#######..#.################aabccccdbbb####.#..#..#.#..########aa#aaa#aaabdddbcababbbdeddedeeb####aaaaaa#ba#aababcbbbaeccbcbcbcbbbbaaaa###a", +"ba#a#####a#############cb#########aa##a###a####ab#aabaaaabbbbedcdccehihcbbbbbbccaaa#a#aaaaabbaaaabbbcbbaaabbbccaaabbaaaaaaaaaabbbbacda####aaedbaaabddba#aaab###aa####aaddcceebabbbcbcdca#aaba#aaabaabfmka##aabaaaaaa#abbabbbbaaa#acccdddccedbbbbaaaaaaaa##a####.#.###############aabddcbbcaaa####.#......aa###aa####aaaa#aa##aacccccbbbabbcdedddea####a##aa#a#bccbccbcbbaaaadddccbbbbbbaa#aa####", +"ab##aaaa######a##########aa###b##aaaaa##a#a#####ababbbaababbbccccdcdgjifbbabbcccca#aaaaaaaaacaaaaabcccbaaa#bbbcaaaaaaaaaaaaaaaaccbaabbaa#a#a#bcbbaa##a###aaba######aaaaaaddfhgccddddacacaaaaa#aaaaaaabhnk.aabbb##aa####aa#acaabb#aabccddeecccbbbabaa##aa###aa#######.######a###aaaabdddcdedda#########...#####aaaaaaaaa##a###aabcbbccbbbbcddeeefc##a####aaaaaacdccbbaababaaabccdccccbbbbaa#a####", +"#####a#aaaaa###aaa######ba###aa#bba#aa#abca##bb#abaabbbbbbaabbbbdccceihgecbcdccbcd#ababa##aaabaaaaaabccbaabbddbbaa#aaaaaaaaaaaaaccbaaa#a######aabdcb##aaa##a#a#####aaaa##aabffebccddcb#aa#######aaaaaadlnd#aabbabaaaaa##aaaa####aaaabccdeedbb#aa##a###############.##..#.#####aaaaabccdeecdaa#####.########.###aaa#aa###aaaa#aaabcbccccbbccddeef##aaaaa####aaaccbaabaaaaaaaaba#bcddcbbbbbb#aaa#a", +"abaa###aaaaa##a#a##a#############a#a#ababda#aaaaaaaabbaabbbbcbbbddbddgifhedbcccbbcc##aabbaa#aaaaaaabaabbbccccdebaa##aa#aaaaaaaaaabedaaaa##########becaaaaa#a#########aaa##abceffdccb##aa########a#abbabilk#a#a######ab#aa#aa#####aaabbcddedbaa#a######a#####################a#aaaaaabdddfgfc##########...a#a###aaa#a#aa##a###aaaabbbbbcbbbcceghfaaaaaaaabbabccbbbaaaaaaaa#abba#aacedcccbaaaaa#aa", +"bbaa##aa#aaaa#aaaaaaaaa#aaa##########abaaaa#baaaaabbbbbabbbbccccddbddggghhfdbbcaabbbbbaabbaaaa#aaabbaaabbb#bbbaaa#####a#aaaaaaaaaabb##aa##########aabdcbabaaaa####aa###aa#abbcdhhcaba#baaa#######aaaaabhlmc#a#####aaaaa#a##abba#aabaaabcdgfbb################################aabbaabbccdhigca#########.########aaa########aa#a##aaabbbbccbccdgfha#caaa.##fedbbcbaaaaaaaaa#aaa###aaadecccbbaaaaaa", +"#aa###aaa#a#aaabbbbbcbaa##a#######aaabaababaa#aaaaabbbbbaaababccdecdfhhiihgfdbccbbcbabaaaaaadca##abbaaaaaaa#bb##aaa####aa#aaa#aaaabbda.##########aaaabddcbbaa#a##aa#aaa##aaabbdecca#a#aa#a########aaaaaeili##a######abaa###aaaaaacfeaabddcdbaa##############################aaabbbbbbcdfgjieba####.#####aa#aa############aaaaa###aaabcbbcbbcefggcbbfeedbedbcbabbaaaaaaaaaaaaaaa#aaa#cdcddcbbaaaa", +"aa#a###aa#a##a#aaaabbccaa#aaa########bacbaaaaaaaaaaaabcbbbbbbcedcdccfhfhkhggfdbbccbbabaabaabdda###aaa#aaaaaaacb#########aaaaaa#aaaabec##########aaaaaaabddcbaaaaaaaaaaaa##aabacbaaaba#####a##a######aaabgklbaaa#####aaaaaaaaaaabbbfdaacddeddcbaaa#########aaab##########a##aaaabbcbbbbeffhjifdcb#####.##acbb#aaaa###########aaaa#aaacbcbbcbcegfaccgghgffdcbbaabbbaaa#aaaaaaaaaba#aaaabeecccbaaaa", +"aaaa########aaaabbabbbbcbbbaaaa#####.##aaaaaaaaaaaaabbbbaaaaadedcdccegijkifddebccbbccaabaaa##aa######aaaaaaba#aa#########aaaaaaaaa#bccda#######aaaaabbaaabddcba#aaaaaaaaaaaaabcdaaaaa##abaaa#a#a#a##aaaafhlg.aa#a#a###ba##b#acaabcdfaaaccdccedba##########adcbca#########a#aaabbcddccbdefggiigecb########aaaa#abba###########aaaaaa#bdbccbccef#abdeddeeddccba#bbbbbaaaaaaaaaaabcaaaaaa#eedccbbba", +"aa#aaaaa###aaaaaaaaabbbbbbbbaaaa#######aabaaaaaaaaaabbaaaaabbbfeccccdfiljigcdeccccbccbccbbaaaa#######a#aa##aaa#####..#..#aaabaaaaaaabacb######aaaaaaabbaaaacddcbaaa##cbabaaaaabcbaaaaa###a##a####a##aababchl#.###a#####aaaaaa#aabbdeaaacbbbbdfdccbabb####a#ddbbbba##########abbbccdcccddefghhfcaaa######aab#abaaddaa########ab###aaaacccccdefd#dbgebcccdcaabbbaaaaaaababbbaaabacaaaaaba#eeddcbba", +"aa#aaaaba#a#a##aaababbccbabbbbba########aa#a#aaaaaaaababbaaaaadcccaddfhkjigdcdecccbbcdcecbaaaa######aca####aa#####a#####.#aaaaa#aabababb######aaaaaabbabaaaaabcdcbaaaaaaaaaabbbcaaaa#a####aa####a#aaaaaababjh.####a#####aaa##aaaabdabaaaabbabdeeeddddcb#.##debaaabaaaba####aaabbccdcccddeffgfgcaa##aa###aaaaaccaddca########a#a###aaaccbbceffbaacgeaabbbbabaaaaaaaaaaabaaaabbcaaabaaaabbbccdedcb", +"ba#a#aaaaa####aaaaaaaaaaccbcbbaa#######aaaa###aa##aaaaaaaabbbabbcbbefffhjihfcbfcbcbbbcfhgcaaa#####a#deaa##aaaa###############a##a###aaaaa###aaaabbaaaababbbbbbbbedcbaa#abbbbbcccaa##a######aa##aaa##abaa#aabja##.#######a#a###aaabecaaaaaaacccbcaaaabbdddefedcbaa###aaaa#aaaabbbcccccccddfggghdba####aababababcbbddba###a###a#aaa##aabbcccegfbaabcaaaaaaabbaaaaabbaabaacaabbbabbadbaaaaabba#aefc", +"ba#a#aa#######aaaaaaabaabbebdbbb######aa####a###a####aaaabbaabcabcccddffjhfdbaefcdbbbbdjkjebaa#####bccb##baba#####aa######a###a#a####aaaaa##a##aabaaaaaaabbbbbbabefdbbcbbbcbbbcbaa####aa#######aaaaadaaaaabbdg###a#a####a#aa#aabccccaaaaaabcdbccaaaaabbdeeedcdcba###aa#aabaaabbbcbcccddddeffffdbaa####abccbb#bbccdbccaa###a#aaaa#a#aabbdcdfgdaaaccaaaaaa#aaaaababbaaabbbbbabbbbbcbcbaaaabaa###be", +"fcb#############aa#aaaaaaadegdacbaa###aa####aaa#a####aaaabbaaabaabddccehieabaabecccbbbbbikkgca####acbb###baba#####aa####aaaaaaaa######aa###aaaaaaabaaaaaaaacbbbbbbeffedccbcddddbaaa##aaaa###a##aaa#adba#aaabbie.#.#aa##aaaaaaacecaaaba###a##aabdb#a#aaccccccccbbba###aaa###aaabbbbcccdddedegcddcbbaaaabbabbabbaabbaaddbaa#####aa##aaabbddefgcabagbaaaaaaaaaaaabbaaacabaaaaabbbbabbaaaaaaaaaaaa#a", +"bdeba#########aaaaa###aaaaacfebbbbaa###aa#####aa########aaababaacbdeccehhbaaaaaddcbbbbbcgijhea####acb########a##aa#a##a#aaaaabaaaa####aaab###aaaaaaaaaababbccbbbbacbedffedcdeeaaaab#aaa#aa##a##aa#a###aa#aabackc.#.##aaaaaabdefb#a#aaaaa#a####abc####abcbbeecbbaaabb#aaaaaaaabbbbcbcdededdefdcaccbca##aaaa###aaaaabaaeccaaa###aaa#aaabcccdffbbacfc#a#a#aaaaaaabbaaaaeabcbbabbbbcbbabb#aaaaaaa#aa", +"##aba######aaaaaaaa##a#aaa#fdaabbccb###################a#aaaabbabccccdehibabbbbcfdcbbbabgihc#a####abbaa##a###aa##a#aaaa##aaa##aaaaba###daaa###abcaaabaaabbbbbccbcbcdcdddggfedbcbaaaaa##a#####aaaa#aa#####abbbbdjb.a##aaaaabeecabba##aabda######aa####aaabbdcdcbaa#bcbbaaaaaaaabbbcccddedefffdcbccbab####a#####a#aaabaabeeba######aaacbcddegebbacccba##a#aaaaaaaaaaaaccbbbbbabaaa#aaabbaaaaaaaaaa", +"aa##baa####aaabaaaaa#####aacaababbccbaa##################aaaaaaaabbccbegifaaaabbcecbbbbaadgb#####aeeabc#.######aa##aaaaa#aaaaa###abaa##edaaaa##aabbaaaabbbbbbbccbbdccccdddehhdabbaaaaaa##a###aaaabb######cebcbcgj#aa##abdfggcbbbaaaabdfea####aaaaa##aa###aaa#aaaa#aaabbaaaaaaaabbccddeeddeffeeeefcabaa#aa#####aa#aabbbacccbaaaaaaaabcccdegfbbbceaacb#####aaaaaaaaaaaacccabaaaaa#a#abbccaabbaaaa#", +"#aaa#daaaaaaaabbbaaaa####abbaabaabcbbbbb##aa################aaaaabbbddehecacbaaaabecbbbbabaa#####adcca#########a#a##daaaaacaaaaaa###aa#aca#aa##aaaabbbaabccbbbbcddaccdeddecfhgcabaaa#ab#a####a####aaa#aaaabbbcbcijdchihgighedbcbbcdfdabbbbccaaaaaa###caa#aaaa#a#a##aaaaaaaaaaaaabcccdddddeeedeeeffbaaaaaa##aa###aaabbbabcdeabaaaabbbbcdegibabbfaabca####a#acca#aaaaaaababbbaaaa##aaababbaaabaaaa", +"#####adcbbbaabbbaaaa#a#a#####aaaabbaaabcbaa#################aa#aaaaabddgeadbcaaaaabccbbbbba#####a#a##aaaaa###aa#aa#bccaabaac#aaa#####a#..#####aaaaaabcbaaabbbbcdccdcddedceefgfccbaaaaaa#aa###aa##accaaaaaaaabbbbdjkfdfgjjhgfeeeeeedcaabaabaaaaa#####ab#a#aaaa###a####aaaaaaaaaaabbccddccccdccdeeegfbcbcaaa#aaba#aaabdcbbbababbbaabbcccdghg#aadbaabbaa###a##acdaaa#a#aa#baaaaaaaaa#a#aaaccbaabaaa", +"a##a#aaedbbcbabaaaa##a##aa####aaaababbaabacaaa###a#######a####aaaaaaaccehbbbbcbaaaaacdbbbcb#a#a#a#.####aaa##a#aaaaaaabaaaaab##aaaaaaaa#####aaa##aa##abbaaabbbccbccbcdcdcddeffcaabaaaabba#aa####a##bcbaaaabababbbbejib#abccdcbbccba##a##aaaa##a######a##aaaaa#a###a#####aaaaaaaaabbccccccccccccdeegfcdabbaaaaaaa#aaaabccbbbaccbabbbcddefedea#cd##a#aaab#aaa##bcb###aaa##abaaaa#####aaaaabbcbaabbb", +"aa##aa#bhgccbbccbbaaaaa########aaaaabcbaaaabbaaaa###aa#####a#a#aaaabbbbcega##acbabababecccdabaa##########aaaaaaaaaaaaaabaaa####aaaaaaaa##.##abaaa#aaaaabbbbbbbbcdbbccddcdcegeaaaab#aaaaaaaaa####aabbabbcbbbcaaabbcegiaaaaaa##abbcbca##.###aaaaa####aaa##abbaa#aaaaa####aaaabbaaabbbbccccbcccdddedfddcaaaaaaaaaaaaabbccdbbbcecbbccdefged#a###fa######aaaaaaaabaa#######aab#aaaa#aa#aaaaaabcccabaa", +"aa##aadafhhfeccbbbaa#aaa##a####a#aaaaaaaaaaaaaaaaabaaaabaa#aa###aaaaaabbcfd#a#acbaaaaabeecdcc#############abbaaaaaaaababbba###aaaaaaa#a#####aa#aaaaaa#aaaabbbabcccehgeecdegebaaaaaaaaa#aaa#aa###aaaaababccbbaa#aabceggaaaaaa#aaaabcb####a###aaba######a#a#####aaaaba#####aabbaaaabcbbbbcbbacceeddeebabdbabbaaaaaababcdccdccdcbbccefecb#####cc#########aaaaaaaaaa##ba#aaaaabbbbaaa#aaaaaabcccdgdb", +"##aaacdggggghgdbbbbbaaaaa#aa###a###aa##aaaaaaaaaaaaabcbbaaaaaa#aaaaaaabbbdfd#aaacdaaaaaadgefc#######a#a###abb##a#aaabaaaaaa#######aaa#a########aaaaa##aabbbbbbbbccefhfeeegfbbba#aaaaaaaaaaaa####aa##abbcdacbaa##aabcehfaaaa###aaababa##.##a#aaaca#a#aaaaaa#aaaa#aabcc#####aaaabbbbbadcabbbbbbceedefcaabcecaaabaaababccdcdddccbbcceda#####baeaa#aaa#####ab##aaaaa##aaa##abbbbbbbbaaaaaaaaabbbagig", +"f#aaaehhfffeffhfbccbbaaaaaaa####a#aaaaa###aaa#a#abaabccabcbabbbbabbaabbbbcehdaaaaaaaaaab#dgeaa##a###########aa####aaaaaaa######a####aaaa###a###aaaaa###aabbbbbacccdedddfgebcbaaaaabbbaabaaba#########abcbdabaaa#aabcdeibaaa######aaaca######aabbb####aaaaaaaaaaa##bbdb####aabbbbaaaacdcaabbbbcceddeccccaba#aaabaaaabccddddddceddeec#aca#aabebaaa#######aaaba#######aaaaabbbabbbbbaaaaaaaaaba#dii", +"hd#aaejiedefeeddedccbaaaaaa########aaa#######a#a#aaaabbaacbbababccbbabbbbbceidbaaaaaaaacbcgeca#############aaaaaaaaaaaba######.a############a##aaaaaaaaaaaacbbbccccedbcfcbbbbaaabbbbaaaaaaababaaa#baaaabababbabaaaaabdfhaaaaa#aa##b#bbaa#####abb##a##aaaabbba#aaaaaacda#####abbbbaa####a#abaabccbdecdbbaaaaaaaaaaaabccceeedcdfgffeba#aa#aa#bcaaa##########aa##a####aaaaa#aaabbbbaaaaabbbcbbbeefh", +"ggecdhjkiefeeddcdefdababaaa########aa##a########abaabaabcdabbcdccbcbabbbbccchiecaa#abbbaaaadeca#####a#######aabaaaaaabba###a##.#############a##aaaaaaaaaaabbbccdddbbeccdbbcbbbabbbbbbcbbaaaabccaaaabaabcabbabaaaabaabcefeabaaaaa####aaccb####aaa###a###aabbab#a#aaa##aaa#####acbba#a######aaaabbbbfefdaaaacaaaaaaaabbbcefffeefbed########a##dbaaa#######a#############a########aaaaaaaaaccfgfhdf", +"efddegijmkfeeeddccdgdbcccbaaa####a#aaa#####a####a###aabbcbabacccdccbbbbbcbbdfijhbaaaaabb###cedbaa###aaa#####aabbccbaaaaa###accb###a##########aaaaaaaaaaaabcbbccddddcddaaaabbbabbbbbbcbaabbbbbaaaabbaaaaabbbbaaa#ccaabbddheabaaaaa####abca#####ba##a####abcaaaaaaaaaa#aaaa#####bbaaa##aaaa##aaabbaaadfdbaabcbaaaaaaabbacehhhhcaaaa#####a#ab##ccaa########aa#############ba#a#aaaa#aaabdaaeffghgff", +"eddcbcdefijgeedcccbbdeccccbaaaaaaaaaa#a#########aaa##a#abcaacccccccbcbbccccdefikibaaaaaaaabbdddca#a#a#aa####aaabbbaaaa##a##aaaba##aa##a######aaaaaaaaaaabbbbbccccddddaabbaabcdbbbccbacbabcbbccbaa#aaaa###baaaaa#a#aaabcdfjb#aaaaaa####abaa.####a##aa####bcbbaaaaaaaa#####aa##abaaa#a##aaaaaaaaaaaaabecbaababaaaaabbbcbcehhcaaa##aaa#######b#.cbabaa#####aa##a#####a#########aa#a#aaabdefffggfefe", +"ddcaaabdefhihecdbbbbacdecccbbaaaaaaaa############aa##aa#ababbcbcbbbababccdceeegijgaaaaaba###bfcdc##aaaaa######aaaaaaaaa#aaaaaacba#aaa#a#ba#aa#aaaaaaaababcbbbbbcedabbaabbaaabbbabbdccbbbaabbbbbaaa#aaaaa##aaaaaa#####abcehka##aaa#####aaaa###..a#aba#####abcaaaaaaa#a##a##a###ba########aaaa####aa#deaaa#aaaaaaabbbbbccefcbaba##abaaaa.#a#ba##dc#a#a####abaabb#a##aa##a###a###aaaaabaceecddhhedd", +"cccbabbcdfffhheccbbbbbcdfccbbbbaaaaaa###############a##aaaabacbbbbaaaacccddcdefhjjhbaaaabaa##dfbbc###aa#aa######aabaabaabbbbbabdb#aa#a###bba#a##aaaabbabbbbbcbbcedbaaaaaaaaabbbbbcbccbcebbbbaaaaaaaaaa#####aaa####aa#aabdegj.############a##a##a#aba####a##baaaaaa#a###aa#aa########a##a#aaaa####a#eeaa###aaaaaaaaabbcdgfdbaa####aabbcb#aabc###cda#aa##aababcbb#a#aa###a##aab#aaaaababdecbcdheed", +"cbbaccbcddeffeedcbbbbbbccffdbbcbabbaaa#aa########a###ca#abaabbbabaaaaabcccddcdgiikjgbaaaaba##afcacba###aa########abbbbaabbbbbbbcbbbb#aa#a###aa##aaaaababbbbcbccdca#a##aaaaabaaabcccbbcbcbaabba##aaaaaba#####aa####aabbbddcdjd.#########.#..#######aba######aaaaaba########aa#######aaa#aba#aaa###aacaaaa##aabaaaaaaabbcefcbbaaaaa##aaacabaaaa###bca#####aaaaacaa#a###a##a#aaa#a#aabbbbcddcccegdd", +"cbbabbbbccddeedddcbbbbbbbbdfheccccbaaaa###########aa#bd##baaaabaaaaaababcddcccggijjjbaaabbaa##bcbabba##aa#######aaaaaaabbbbbbbbbcccaaaa##a##aaa##aaaabbbdbcbbcdfbaaa#aaabbbbbbbbbcccbccdedaaa#aaaabbaaaa#a#aa####a#abcccdccfi###########....#######aa##aaaaaaaaaaa##########a###a##aa#aa#aaa#####aaa#aaaa##abbbaaaaabcdefbbaaaaabaa####aa####a#a#dba#####bb##b###########aaaaa#aaabbaabbbccddede", +"baabbbbbccccdeedcccbbccbcbbcdiheccbbbaaaaa#aab##aa###aa###aaaacbaaaaaababccccdfhjjjl#abbbaaba#abeaabb######a#####bbaa#aaaabbbcbbabbaa###aa####a###aaaabacdcccdceaaaaaaaaaababbbbbbbcbbbcbdba###aabbbaaa#aa##########aabbabccgb.###.#########.########a#aaaa#abaa#########a##aa#####bcaabaaba###aaaaaaaa#####aaaaaabbbdhidabaaaaaaaa###########a###ebbb###aaa####a###aa#aabcaabbaaababaaabbbbbdcb", +"abcbbbbbbbccbbcddbcbbbbbbbbbcfeghfccbbabaaaaabaaaa####a#b##aaaabbaa#aaaaabccbceefhegdedaaaaaaa#abdaaba#aa##a#####aaaabaaaaaaabbbaacc###aa#aa####a#aaaaaaabcccddfbba#aaaaaabbbbabbccccccbcbdaa#####ac#####a##########aa#aabcbdh..#########.#####.####aaa#aaa###abb###########accaa###a##aaabbbba#a##a#abba####aaaaaccegcbbaaaaaaa#aa###.##a########aeaaaa###a#a######aaa##aaaaaaaabbaabbaacaacced", +"cadbbbbbbcbccbbacbbbbbbbbabccdeehgffccbcbaaabaaaaaa###a####aaa#aaaaaaaaaaabccbdeeffeehgcaabaaa##adb#aca##aaa#####aaabaaaaaaaaaabaacdb##aaaaaaa#abbaaabbbabbdecffbaaaaaaaaaaaaaabbaccbcbcccdcaa#############aabb######aaaaabbbehd..###d#.#.######.####adbaaaa##abba########aaaaaaaaaaaaa#aaaaaaa#a#aa#abaaa####aaacdeheaaaaaaaaa##aa#aa#####a####a#.cdaa######a##a###########aa##aabb#aabaaabbadf", +"cabdabbbabcccdccbccbbbbbbaabdcdefdcfgccbbbbaabcbaaa###aa##aca####aaa##aabbbccccddffhihhfbaba#c###bdaaagaaa#a######aabaabaaaaaaaa#a#aa####aaaa#aabbaaaabbbbbcddfeca###aaaaabbaabbabbcbccbbbccdada###aa######aaba####a###abaabcafjlf..defe##...#########bbaaa###aab#a#######aaabcb#aaaaaca##aaaa####a##aab###a##aabdfiida###aaaaa##ca#aa#####a####a###ecaaa########a##a#####a####a###aaaaaaaaaabab", +"ccbbbbabbaaabccdcbbbbbbaaaabcdbbbeeadgeccbbbbabbbaaa##aa#abedbaa####a####bbbcbccddehhhfdaa###da#a#ddaabhaa###########a#abaabbaa######a####aaaaaaaaaabbbbbbcbdeefcb###aaaaaaaaaabbbbccccbbaabbcaaa############aacbaabaaaaaaabccbdejkbd..bgccdcba########aa######aaa#a#######aaaccaba#bcaaba#a##aaa#####abba#aa#aabdgkjkihgdb#.cedcbb#.###dc########b##ebaaaa#########################aaa#aaaaaaba", +"abeecbbaababbbabbdbabbbbbaaabcccbdcb#ehedccbbaabbbaaa#abaaaedba###########acbbbcceeeggdaaa#bacaa#aadabbdf#######.#######aaaaaa######bca###aaaaaaaaaabbbbbbbccfffbaaaa#aaaaa#aaaabbccabbcccbbbbaaaaa#######a#aa#acaaaaaaaaaaaabccceglh.#....#baacca..####ab########aaa####a##ababbbba#ceaaaaaa###a######aa##acbbbbchgcddfgjihddigefegfffba#affeecbbaaabda#aa######a#a################aaaa#aaaaaab", +"babfdcbcbabaabababbbaaaaaaaabcccdbaaaacifddcbbbbbbbabaabaacecabaaaaa######aaabbcdeeedifba#adcbaaba#bcabbfe#aa####aaa###a#abaaaa######aaaac#aaaaaaaabbbdbbbbcceebbba##aaaaaaa#aaabbbbbbcccdcabaaaaab##a#aaaaaaa######abaaaaa#abbbbddei#####a####.#ee######aa######aaaba######abaaaa#a##bc##aa#a####a###a#aaaabcbbbceecbbcbdeffgfdccccdefeefgffedcefeb##cdbcba########a###########a###aaaabaaaaaaa" +}; +SIMPLE = T BITPIX = 8 NAXIS = 2 NAXIS1 = 384 NAXIS2 = 384 HISTORY Written by XV 3.10a END 3"3wUD3D3"3""3"3"333""""""""3DDDU3""""DªwUUD3333333"3""3""DfD"3""""""""33DUfffUªw3""UD3""3"3D"33wf"""""""3""""""""D""""""""333U3333DDff333"""""""""""333333DDDUD"3"""""3"""""""""3""""""3333UUfª" diff --git a/gtk/parent b/gtk/parent new file mode 100644 index 0000000000..94fee61231 --- /dev/null +++ b/gtk/parent @@ -0,0 +1,10 @@ + gdk_window_show (widget->window); + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + gdk_window_hide (widget->window); + if (GTK_WIDGET_VISIBLE (widget->parent)) + if (GTK_WIDGET_REALIZED (widget->parent) && + if (GTK_WIDGET_MAPPED (widget->parent) && diff --git a/gtk/runelisp b/gtk/runelisp new file mode 100644 index 0000000000..115080cf08 --- /dev/null +++ b/gtk/runelisp @@ -0,0 +1,6 @@ +#! /bin/sh +if test $# -lt 1; then + echo >&2 "usage: $0 file.el" + exit 1 +fi +exec emacs --no-init-file --no-site-file --batch --load $* diff --git a/gtk/simple.c b/gtk/simple.c new file mode 100644 index 0000000000..47893772f7 --- /dev/null +++ b/gtk/simple.c @@ -0,0 +1,39 @@ +#include <gtk/gtk.h> +#include <gdk/gdkprivate.h> + + +void +hello () +{ + g_print ("hello world\n"); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *button; + + gdk_progclass = g_strdup ("XTerm"); + gtk_init (&argc, &argv); + + window = gtk_widget_new (gtk_window_get_type (), + "GtkObject::user_data", NULL, + "GtkWindow::type", GTK_WINDOW_TOPLEVEL, + "GtkWindow::title", "hello world", + "GtkWindow::allow_grow", FALSE, + "GtkWindow::allow_shrink", FALSE, + "GtkContainer::border_width", 10, + NULL); + button = gtk_widget_new (gtk_button_get_type (), + "GtkButton::label", "hello world", + "GtkObject::signal::clicked", hello, NULL, + "GtkWidget::parent", window, + "GtkWidget::visible", TRUE, + NULL); + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/gtk/test.xpm b/gtk/test.xpm new file mode 100644 index 0000000000..9b0d2efdb2 --- /dev/null +++ b/gtk/test.xpm @@ -0,0 +1,92 @@ +/* XPM */ +static char *openfile[] = { +/* width height num_colors chars_per_pixel */ +" 20 19 66 2", +/* colors */ +".. c None", +".# c #000000", +".a c #dfdfdf", +".b c #7f7f7f", +".c c #006f6f", +".d c #00efef", +".e c #009f9f", +".f c #004040", +".g c #00bfbf", +".h c #ff0000", +".i c #ffffff", +".j c #7f0000", +".k c #007070", +".l c #00ffff", +".m c #00a0a0", +".n c #004f4f", +".o c #00cfcf", +".p c #8f8f8f", +".q c #6f6f6f", +".r c #a0a0a0", +".s c #7f7f00", +".t c #007f7f", +".u c #5f5f5f", +".v c #707070", +".w c #00f0f0", +".x c #009090", +".y c #ffff00", +".z c #0000ff", +".A c #00afaf", +".B c #00d0d0", +".C c #00dfdf", +".D c #005f5f", +".E c #00b0b0", +".F c #001010", +".G c #00c0c0", +".H c #000f0f", +".I c #00007f", +".J c #005050", +".K c #002f2f", +".L c #dfcfcf", +".M c #dfd0d0", +".N c #006060", +".O c #00e0e0", +".P c #00ff00", +".Q c #002020", +".R c #dfc0c0", +".S c #008080", +".T c #001f1f", +".U c #003f3f", +".V c #007f00", +".W c #00000f", +".X c #000010", +".Y c #00001f", +".Z c #000020", +".0 c #00002f", +".1 c #000030", +".2 c #00003f", +".3 c #000040", +".4 c #00004f", +".5 c #000050", +".6 c #00005f", +".7 c #000060", +".8 c #00006f", +".9 c #000070", +"#. c #7f7f80", +"## c #9f9f9f", +/* pixels */ +"........................................", +"........................................", +"........................................", +".......................#.#.#............", +".....................#.......#...#......", +"...............................#.#......", +".......#.#.#.................#.#.#......", +".....#.y.i.y.#.#.#.#.#.#.#..............", +".....#.i.y.i.y.i.y.i.y.i.#..............", +".....#.y.i.y.i.y.i.y.i.y.#..............", +".....#.i.y.i.y.#.#.#.#.#.#.#.#.#.#.#....", +".....#.y.i.y.#.s.s.s.s.s.s.s.s.s.#......", +".....#.i.y.#.s.s.s.s.s.s.s.s.s.#........", +".....#.y.#.s.s.s.s.s.s.s.s.s.#..........", +".....#.#.s.s.s.s.s.s.s.s.s.#............", +".....#.#.#.#.#.#.#.#.#.#.#..............", +"........................................", +"........................................", +"........................................" +}; diff --git a/gtk/testgtk.c b/gtk/testgtk.c new file mode 100644 index 0000000000..b1d698a083 --- /dev/null +++ b/gtk/testgtk.c @@ -0,0 +1,3110 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include <stdlib.h> +#include "gtk.h" +#include "../gdk/gdk.h" +#include "../gdk/gdkx.h" + + +void +destroy_window (GtkWidget *widget, + GtkWidget **window) +{ + *window = NULL; +} + +void +button_window (GtkWidget *widget, + GtkWidget *button) +{ + if (!GTK_WIDGET_VISIBLE (button)) + gtk_widget_show (button); + else + gtk_widget_hide (button); +} + +void +create_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *table; + GtkWidget *button[10]; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + table = gtk_table_new (3, 3, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_border_width (GTK_CONTAINER (table), 10); + gtk_box_pack_start (GTK_BOX (box1), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + + button[0] = gtk_button_new_with_label ("button1"); + button[1] = gtk_button_new_with_label ("button2"); + button[2] = gtk_button_new_with_label ("button3"); + button[3] = gtk_button_new_with_label ("button4"); + button[4] = gtk_button_new_with_label ("button5"); + button[5] = gtk_button_new_with_label ("button6"); + button[6] = gtk_button_new_with_label ("button7"); + button[7] = gtk_button_new_with_label ("button8"); + button[8] = gtk_button_new_with_label ("button9"); + + gtk_signal_connect (GTK_OBJECT (button[0]), "clicked", + (GtkSignalFunc) button_window, + button[1]); + + gtk_table_attach (GTK_TABLE (table), button[0], 0, 1, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[0]); + + gtk_signal_connect (GTK_OBJECT (button[1]), "clicked", + (GtkSignalFunc) button_window, + button[2]); + + gtk_table_attach (GTK_TABLE (table), button[1], 1, 2, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[1]); + + gtk_signal_connect (GTK_OBJECT (button[2]), "clicked", + (GtkSignalFunc) button_window, + button[3]); + gtk_table_attach (GTK_TABLE (table), button[2], 2, 3, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[2]); + + gtk_signal_connect (GTK_OBJECT (button[3]), "clicked", + (GtkSignalFunc) button_window, + button[4]); + gtk_table_attach (GTK_TABLE (table), button[3], 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[3]); + + gtk_signal_connect (GTK_OBJECT (button[4]), "clicked", + (GtkSignalFunc) button_window, + button[5]); + gtk_table_attach (GTK_TABLE (table), button[4], 2, 3, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[4]); + + gtk_signal_connect (GTK_OBJECT (button[5]), "clicked", + (GtkSignalFunc) button_window, + button[6]); + gtk_table_attach (GTK_TABLE (table), button[5], 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[5]); + + gtk_signal_connect (GTK_OBJECT (button[6]), "clicked", + (GtkSignalFunc) button_window, + button[7]); + gtk_table_attach (GTK_TABLE (table), button[6], 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[6]); + + gtk_signal_connect (GTK_OBJECT (button[7]), "clicked", + (GtkSignalFunc) button_window, + button[8]); + gtk_table_attach (GTK_TABLE (table), button[7], 2, 3, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[7]); + + gtk_signal_connect (GTK_OBJECT (button[8]), "clicked", + (GtkSignalFunc) button_window, + button[0]); + gtk_table_attach (GTK_TABLE (table), button[8], 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[8]); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button[9] = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button[9]), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button[9], TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button[9], GTK_CAN_DEFAULT); + gtk_widget_grab_default (button[9]); + gtk_widget_show (button[9]); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_toggle_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "toggle buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_toggle_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_toggle_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_toggle_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_check_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "check buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_check_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_check_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_check_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_radio_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "radio buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_radio_button_new_with_label (NULL, "button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_radio_button_new_with_label ( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + "button2"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_radio_button_new_with_label ( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + "button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +bbox_widget_destroy (GtkWidget* widget, GtkWidget* todestroy) +{ +} + +void +create_bbox_window (gint horizontal, + char* title, + gint pos, + gint spacing, + gint child_w, + gint child_h, + gint layout) +{ + GtkWidget* window; + GtkWidget* box1; + GtkWidget* bbox; + GtkWidget* button; + + /* create a new window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), title); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) bbox_widget_destroy, window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) bbox_widget_destroy, window); + + if (horizontal) + { + gtk_widget_set_usize (window, 550, 60); + gtk_widget_set_uposition (window, 150, pos); + box1 = gtk_vbox_new (FALSE, 0); + } + else + { + gtk_widget_set_usize (window, 150, 400); + gtk_widget_set_uposition (window, pos, 200); + box1 = gtk_vbox_new (FALSE, 0); + } + + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + if (horizontal) + bbox = gtk_hbutton_box_new(); + else + bbox = gtk_vbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing); + gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h); + gtk_widget_show (bbox); + + gtk_container_border_width (GTK_CONTAINER(box1), 25); + gtk_box_pack_start (GTK_BOX (box1), bbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_container_add (GTK_CONTAINER(bbox), button); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) bbox_widget_destroy, window); + + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Cancel"); + gtk_container_add (GTK_CONTAINER(bbox), button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Help"); + gtk_container_add (GTK_CONTAINER(bbox), button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +void +test_hbbox () +{ + create_bbox_window (TRUE, "Spread", 50, 40, 85, 28, GTK_BUTTONBOX_SPREAD); + create_bbox_window (TRUE, "Edge", 200, 40, 85, 25, GTK_BUTTONBOX_EDGE); + create_bbox_window (TRUE, "Start", 350, 40, 85, 25, GTK_BUTTONBOX_START); + create_bbox_window (TRUE, "End", 500, 15, 30, 25, GTK_BUTTONBOX_END); +} + +void +test_vbbox () +{ + create_bbox_window (FALSE, "Spread", 50, 40, 85, 25, GTK_BUTTONBOX_SPREAD); + create_bbox_window (FALSE, "Edge", 250, 40, 85, 28, GTK_BUTTONBOX_EDGE); + create_bbox_window (FALSE, "Start", 450, 40, 85, 25, GTK_BUTTONBOX_START); + create_bbox_window (FALSE, "End", 650, 15, 30, 25, GTK_BUTTONBOX_END); +} + +void +create_button_box () +{ + static GtkWidget* window = NULL; + GtkWidget* bbox; + GtkWidget* button; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), + "Button Box Test"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, &window); + + gtk_container_border_width (GTK_CONTAINER (window), 20); + + /* + *these 15 lines are a nice and easy example for GtkHButtonBox + */ + bbox = gtk_hbutton_box_new (); + gtk_container_add (GTK_CONTAINER (window), bbox); + gtk_widget_show (bbox); + + button = gtk_button_new_with_label ("Horizontal"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) test_hbbox, 0); + gtk_container_add (GTK_CONTAINER (bbox), button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Vertical"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) test_vbbox, 0); + gtk_container_add (GTK_CONTAINER (bbox), button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +void +reparent_label (GtkWidget *widget, + GtkWidget *new_parent) +{ + GtkWidget *label; + + label = gtk_object_get_user_data (GTK_OBJECT (widget)); + + gtk_widget_reparent (label, new_parent); +} + +void +create_reparent () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *frame; + GtkWidget *button; + GtkWidget *label; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + label = gtk_label_new ("Hello World"); + + frame = gtk_frame_new ("Frame 1"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + button = gtk_button_new_with_label ("switch"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) reparent_label, + box3); + gtk_object_set_user_data (GTK_OBJECT (button), label); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + gtk_box_pack_start (GTK_BOX (box3), label, FALSE, TRUE, 0); + gtk_widget_show (label); + + + frame = gtk_frame_new ("Frame 2"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + button = gtk_button_new_with_label ("switch"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) reparent_label, + box3); + gtk_object_set_user_data (GTK_OBJECT (button), label); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_pixmap () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *button; + GtkWidget *label; + GtkWidget *separator; + GtkWidget *pixmapwid; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "pixmap"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + gtk_widget_realize(window); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new (); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 0); + gtk_widget_show (button); + + style=gtk_widget_get_style(button); + + pixmap = gdk_pixmap_create_from_xpm (window->window, &mask, + &style->bg[GTK_STATE_NORMAL], + "test.xpm"); + pixmapwid = gtk_pixmap_new (pixmap, mask); + + label = gtk_label_new ("Pixmap\ntest"); + box3 = gtk_hbox_new (FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (box3), 2); + gtk_container_add (GTK_CONTAINER (box3), pixmapwid); + gtk_container_add (GTK_CONTAINER (box3), label); + gtk_container_add (GTK_CONTAINER (button), box3); + gtk_widget_show (pixmapwid); + gtk_widget_show (label); + gtk_widget_show (box3); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_tooltips () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkTooltips *tooltips; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "tooltips"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + tooltips=gtk_tooltips_new(); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_toggle_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips(tooltips,button,"This is button 1"); + + button = gtk_toggle_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips(tooltips,button,"This is button 2"); + + button = gtk_toggle_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips (tooltips, button, "This is button 3. This is also a really long tooltip which probably won't fit on a single line and will therefore need to be wrapped. Hopefully the wrapping will work correctly."); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_tooltips_set_tips (tooltips, button, "Push this button to close window"); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +GtkWidget* +create_menu (int depth) +{ + GtkWidget *menu; + GtkWidget *submenu; + GtkWidget *menuitem; + GSList *group; + char buf[32]; + int i, j; + + if (depth < 1) + return NULL; + + menu = gtk_menu_new (); + submenu = NULL; + group = NULL; + + for (i = 0, j = 1; i < 5; i++, j++) + { + sprintf (buf, "item %2d - %d", depth, j); + menuitem = gtk_radio_menu_item_new_with_label (group, buf); + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem)); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_widget_show (menuitem); + + if (depth > 0) + { + if (!submenu) + submenu = create_menu (depth - 1); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); + } + } + + return menu; +} + +void +create_menus () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *menu; + GtkWidget *menubar; + GtkWidget *menuitem; + GtkWidget *optionmenu; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "menus"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + menubar = gtk_menu_bar_new (); + gtk_box_pack_start (GTK_BOX (box1), menubar, FALSE, TRUE, 0); + gtk_widget_show (menubar); + + menu = create_menu (2); + + menuitem = gtk_menu_item_new_with_label ("test\nline2"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_label ("foo"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_label ("bar"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_item_right_justify (GTK_MENU_ITEM (menuitem)); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + optionmenu = gtk_option_menu_new (); + gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), create_menu (1)); + gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), 4); + gtk_box_pack_start (GTK_BOX (box2), optionmenu, TRUE, TRUE, 0); + gtk_widget_show (optionmenu); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_scrolled_windows () +{ + static GtkWidget *window; + GtkWidget *scrolled_window; + GtkWidget *table; + GtkWidget *button; + char buffer[32]; + int i, j; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + scrolled_window, TRUE, TRUE, 0); + gtk_widget_show (scrolled_window); + + table = gtk_table_new (20, 20, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 10); + gtk_table_set_col_spacings (GTK_TABLE (table), 10); + gtk_container_add (GTK_CONTAINER (scrolled_window), table); + gtk_widget_show (table); + + for (i = 0; i < 20; i++) + for (j = 0; j < 20; j++) + { + sprintf (buffer, "button (%d,%d)\n", i, j); + button = gtk_toggle_button_new_with_label (buffer); + gtk_table_attach_defaults (GTK_TABLE (table), button, + i, i+1, j, j+1); + gtk_widget_show (button); + } + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_entry () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *entry; + GtkWidget *button; + GtkWidget *separator; + + /* if (!window) */ + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "entry"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + entry = gtk_entry_new (); + /* gtk_widget_set_usize (entry, 0, 25); */ + gtk_entry_set_text (GTK_ENTRY (entry), "hello world"); + gtk_box_pack_start (GTK_BOX (box2), entry, TRUE, TRUE, 0); + gtk_widget_show (entry); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + /* else + gtk_widget_destroy (window); */ +} + +void +list_add (GtkWidget *widget, + GtkWidget *list) +{ + static int i = 1; + gchar buffer[64]; + GtkWidget *list_item; + + sprintf (buffer, "added item %d", i++); + list_item = gtk_list_item_new_with_label (buffer); + gtk_widget_show (list_item); + gtk_container_add (GTK_CONTAINER (list), list_item); +} + +void +list_remove (GtkWidget *widget, + GtkWidget *list) +{ + GList *tmp_list; + GList *clear_list; + + tmp_list = GTK_LIST (list)->selection; + clear_list = NULL; + + while (tmp_list) + { + clear_list = g_list_prepend (clear_list, tmp_list->data); + tmp_list = tmp_list->next; + } + + clear_list = g_list_reverse (clear_list); + + gtk_list_remove_items (GTK_LIST (list), clear_list); + + tmp_list = clear_list; + + while (tmp_list) + { + gtk_widget_destroy (GTK_WIDGET (tmp_list->data)); + tmp_list = tmp_list->next; + } + + g_list_free (clear_list); +} + +void +create_list () +{ + static GtkWidget *window = NULL; + static char *list_items[] = + { + "hello", + "world", + "blah", + "foo", + "bar", + "argh", + "spencer", + "is a", + "wussy", + "programmer", + }; + static int nlist_items = sizeof (list_items) / sizeof (list_items[0]); + + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *scrolled_win; + GtkWidget *list; + GtkWidget *list_item; + GtkWidget *button; + GtkWidget *separator; + int i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "list"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (box2), scrolled_win, TRUE, TRUE, 0); + gtk_widget_show (scrolled_win); + + list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_MULTIPLE); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE); + gtk_container_add (GTK_CONTAINER (scrolled_win), list); + gtk_widget_show (list); + + for (i = 0; i < nlist_items; i++) + { + list_item = gtk_list_item_new_with_label (list_items[i]); + gtk_container_add (GTK_CONTAINER (list), list_item); + gtk_widget_show (list_item); + } + + button = gtk_button_new_with_label ("add"); + GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) list_add, + list); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("remove"); + GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) list_remove, + list); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +color_selection_ok (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + gdouble color[4]; + + colorsel=GTK_COLOR_SELECTION(cs->colorsel); + + gtk_color_selection_get_color(colorsel,color); + gtk_color_selection_set_color(colorsel,color); +} + +void +color_selection_changed (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + gdouble color[4]; + + colorsel=GTK_COLOR_SELECTION(cs->colorsel); + gtk_color_selection_get_color(colorsel,color); +} + +void +create_color_selection () +{ + static GtkWidget *window = NULL; + + if (!window) + { + gtk_preview_set_install_cmap (TRUE); + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_color_selection_dialog_new ("color selection dialog"); + + gtk_color_selection_set_opacity ( + GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + TRUE); + + gtk_color_selection_set_update_policy( + GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + GTK_UPDATE_CONTINUOUS); + + gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_signal_connect ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + "color_changed", + (GtkSignalFunc) color_selection_changed, + window); + + gtk_signal_connect ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->ok_button), + "clicked", + (GtkSignalFunc) color_selection_ok, + window); + + gtk_signal_connect_object ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->cancel_button), + "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +void +file_selection_ok (GtkWidget *w, + GtkFileSelection *fs) +{ + g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))); +} + +void +create_file_selection () +{ + static GtkWidget *window = NULL; + + if (!window) + { + window = gtk_file_selection_new ("file selection dialog"); + gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button), + "clicked", (GtkSignalFunc) file_selection_ok, + window); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkDialog + */ +static GtkWidget *dialog_window = NULL; + +void +label_toggle (GtkWidget *widget, + GtkWidget **label) +{ + if (!(*label)) + { + *label = gtk_label_new ("Dialog Test"); + gtk_misc_set_padding (GTK_MISC (*label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->vbox), + *label, TRUE, TRUE, 0); + gtk_widget_show (*label); + } + else + { + gtk_widget_destroy (*label); + *label = NULL; + } +} + +void +create_dialog () +{ + static GtkWidget *label; + GtkWidget *button; + + if (!dialog_window) + { + dialog_window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (dialog_window), "destroy", + (GtkSignalFunc) destroy_window, + &dialog_window); + gtk_signal_connect (GTK_OBJECT (dialog_window), "delete_event", + (GtkSignalFunc) destroy_window, + &dialog_window); + + gtk_window_set_title (GTK_WINDOW (dialog_window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (dialog_window), 0); + + button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Toggle"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) label_toggle, + &label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + label = NULL; + } + + if (!GTK_WIDGET_VISIBLE (dialog_window)) + gtk_widget_show (dialog_window); + else + gtk_widget_destroy (dialog_window); +} + + +/* + * GtkRange + */ +void +create_range_controls () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *scrollbar; + GtkWidget *scale; + GtkWidget *separator; + GtkObject *adjustment; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "range controls"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + adjustment = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0); + + scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment)); + gtk_widget_set_usize (GTK_WIDGET (scale), 150, 30); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_scale_set_digits (GTK_SCALE (scale), 1); + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adjustment)); + gtk_range_set_update_policy (GTK_RANGE (scrollbar), + GTK_UPDATE_CONTINUOUS); + gtk_box_pack_start (GTK_BOX (box2), scrollbar, TRUE, TRUE, 0); + gtk_widget_show (scrollbar); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkRulers + */ +void +create_rulers () +{ + static GtkWidget *window = NULL; + GtkWidget *table; + GtkWidget *ruler; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "rulers"); + gtk_widget_set_usize (window, 300, 300); + gtk_widget_set_events (window, + GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + table = gtk_table_new (2, 2, FALSE); + gtk_container_add (GTK_CONTAINER (window), table); + gtk_widget_show (table); + + ruler = gtk_hruler_new (); + gtk_ruler_set_range (GTK_RULER (ruler), 5, 15, 0, 20); + + gtk_signal_connect_object ( + GTK_OBJECT (window), + "motion_notify_event", + (GtkSignalFunc) + GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event, + GTK_OBJECT (ruler)); + + gtk_table_attach (GTK_TABLE (table), ruler, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (ruler); + + + ruler = gtk_vruler_new (); + gtk_ruler_set_range (GTK_RULER (ruler), 5, 15, 0, 20); + + gtk_signal_connect_object ( + GTK_OBJECT (window), + "motion_notify_event", + (GtkSignalFunc) + GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event, + GTK_OBJECT (ruler)); + + gtk_table_attach (GTK_TABLE (table), ruler, 0, 1, 1, 2, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (ruler); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkText + */ +void +create_text () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkWidget *table; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *text; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "text window"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + text = gtk_text_new (NULL, NULL); + gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); + gtk_widget_show (text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + gtk_text_freeze (GTK_TEXT (text)); + + gtk_widget_realize (text); + + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "spencer blah blah blah\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "kimball\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "is\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "a\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "wuss.\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "but\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "josephine\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "(his\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "girlfriend\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "is\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "not).\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "why?\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "because\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "spencer\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "puked\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "last\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "night\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "but\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "josephine\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "did\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "not", -1); + + gtk_text_thaw (GTK_TEXT (text)); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkNotebook + */ +void +rotate_notebook (GtkButton *button, + GtkNotebook *notebook) +{ + gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos + 1) % 4); +} + +void +create_notebook () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkWidget *notebook; + GtkWidget *frame; + GtkWidget *label; + char buffer[32]; + int i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "notebook"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + notebook = gtk_notebook_new (); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + gtk_box_pack_start (GTK_BOX (box2), notebook, TRUE, TRUE, 0); + gtk_widget_show (notebook); + + + for (i = 0; i < 5; i++) + { + sprintf (buffer, "Page %d", i+1); + + frame = gtk_frame_new (buffer); + gtk_container_border_width (GTK_CONTAINER (frame), 10); + gtk_widget_set_usize (frame, 200, 150); + gtk_widget_show (frame); + + label = gtk_label_new (buffer); + gtk_container_add (GTK_CONTAINER (frame), label); + gtk_widget_show (label); + + label = gtk_label_new (buffer); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label); + } + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("next"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_next_page, + GTK_OBJECT (notebook)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("prev"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_prev_page, + GTK_OBJECT (notebook)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("rotate"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) rotate_notebook, + notebook); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkPanes + */ +void +create_panes () +{ + static GtkWidget *window = NULL; + GtkWidget *frame; + GtkWidget *hpaned; + GtkWidget *vpaned; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Panes"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + vpaned = gtk_vpaned_new (); + gtk_container_add (GTK_CONTAINER (window), vpaned); + gtk_container_border_width (GTK_CONTAINER(vpaned), 5); + gtk_widget_show (vpaned); + + hpaned = gtk_hpaned_new (); + gtk_paned_add1 (GTK_PANED (vpaned), hpaned); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 60, 60); + gtk_paned_add1 (GTK_PANED (hpaned), frame); + gtk_widget_show (frame); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 80, 60); + gtk_paned_add2 (GTK_PANED (hpaned), frame); + gtk_widget_show (frame); + + gtk_widget_show (hpaned); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 60, 80); + gtk_paned_add2 (GTK_PANED (vpaned), frame); + gtk_widget_show (frame); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Drag -N- Drop + */ +void +dnd_drop (GtkWidget *button, GdkEvent *event) +{ + g_print ("Got drop of type |%s| with data of:\n%s\n", + event->dropdataavailable.data_type, + event->dropdataavailable.data); + g_free (event->dropdataavailable.data); + g_free (event->dropdataavailable.data_type); +} + +void +dnd_drag_request (GtkWidget *button, GdkEvent *event) +{ + g_print ("Button |%s| got drag request %d\n", + gtk_widget_get_name (button), event->type); + + gtk_widget_dnd_data_set (button, event, "Hello world!!!", + strlen("Hello world!!!") + 1); +} + +void +create_dnd () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *entry; + GtkWidget *frame; + GtkWidget *button; + GtkWidget *separator; + char *foo = "testing"; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Drag -N- Drop"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + frame = gtk_frame_new ("Drag"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + /* + * FROM Button + */ + button = gtk_button_new_with_label ("From"); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + /* + * currently, the widget has to be realized to + * set dnd on it, this needs to change + */ + gtk_widget_realize (button); + gtk_signal_connect (GTK_OBJECT (button), + "drag_request_event", + (GtkSignalFunc) dnd_drag_request, + button); + + gtk_widget_dnd_drag_set (button, TRUE, &foo, 1); + + + frame = gtk_frame_new ("Drop"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + + /* + * TO Button + */ + button = gtk_button_new_with_label ("To"); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + gtk_widget_realize (button); + gtk_signal_connect (GTK_OBJECT (button), + "drop_data_available_event", + (GtkSignalFunc) dnd_drop, + button); + + gtk_widget_dnd_drop_set (button, TRUE, &foo, 1, FALSE); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +/* + * Shaped Windows + */ +static GdkWindow *root_win = NULL; +static GtkWidget *modeller = NULL; +static GtkWidget *sheets = NULL; +static GtkWidget *rings = NULL; + +typedef struct _cursoroffset {gint x,y;} CursorOffset; + +static void +shape_pressed (GtkWidget *widget) +{ + CursorOffset *p; + + p = gtk_object_get_user_data (GTK_OBJECT(widget)); + gtk_widget_get_pointer (widget, &(p->x), &(p->y)); + + gtk_grab_add (widget); + gdk_pointer_grab (widget->window, TRUE, + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK, + NULL, NULL, 0); +} + + +static void +shape_released (GtkWidget *widget) +{ + gtk_grab_remove (widget); + gdk_pointer_ungrab (0); +} + +static void +shape_motion (GtkWidget *widget, + GdkEventMotion *event) +{ + gint xp, yp; + CursorOffset * p; + GdkModifierType mask; + + p = gtk_object_get_user_data (GTK_OBJECT (widget)); + + gdk_window_get_pointer (root_win, &xp, &yp, &mask); + gtk_widget_set_uposition (widget, xp - p->x, yp - p->y); +} + +GtkWidget * +shape_create_icon (char *xpm_file, + gint x, + gint y, + gint px, + gint py, + gint window_type) +{ + GtkWidget *window; + GtkWidget *pixmap; + GtkWidget *fixed; + CursorOffset* icon_pos; + GdkGC* gc; + GdkBitmap *gdk_pixmap_mask; + GdkPixmap *gdk_pixmap; + GtkStyle *style; + + style = gtk_widget_get_default_style (); + gc = style->black_gc; + + /* + * GDK_WINDOW_TOPLEVEL works also, giving you a title border + */ + window = gtk_window_new (window_type); + + fixed = gtk_fixed_new (); + gtk_widget_set_usize (fixed, 100,100); + gtk_container_add (GTK_CONTAINER (window), fixed); + gtk_widget_show (fixed); + + gdk_pixmap = gdk_pixmap_create_from_xpm (window->window, &gdk_pixmap_mask, + &style->bg[GTK_STATE_NORMAL], + xpm_file); + + pixmap = gtk_pixmap_new (gdk_pixmap, gdk_pixmap_mask); + gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py); + gtk_widget_show (pixmap); + + gtk_widget_shape_combine_mask (window, gdk_pixmap_mask, px,py); + + gtk_widget_set_events (window, + gtk_widget_get_events (window) | + GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK); + + gtk_signal_connect (GTK_OBJECT (window), "button_press_event", + GTK_SIGNAL_FUNC (shape_pressed),NULL); + gtk_signal_connect (GTK_OBJECT (window), "button_release_event", + GTK_SIGNAL_FUNC (shape_released),NULL); + gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event", + GTK_SIGNAL_FUNC (shape_motion),NULL); + + icon_pos = g_new (CursorOffset, 1); + gtk_object_set_user_data(GTK_OBJECT(window), icon_pos); + + gtk_widget_set_uposition (window, x, y); + gtk_widget_show (window); + + return window; +} + +void +create_shapes () +{ + root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ()); + + if (!modeller) + { + modeller = shape_create_icon ("Modeller.xpm", + 440, 140, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (modeller), "destroy", + (GtkSignalFunc) destroy_window, + &modeller); + gtk_signal_connect (GTK_OBJECT (modeller), "delete_event", + (GtkSignalFunc) destroy_window, + &modeller); + } + else + gtk_widget_destroy (modeller); + + if (!sheets) + { + sheets = shape_create_icon ("FilesQueue.xpm", + 580, 170, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (sheets), "destroy", + (GtkSignalFunc) destroy_window, + &sheets); + gtk_signal_connect (GTK_OBJECT (sheets), "delete_event", + (GtkSignalFunc) destroy_window, + &sheets); + + } + else + gtk_widget_destroy (sheets); + + if (!rings) + { + rings = shape_create_icon ("3DRings.xpm", + 460, 270, 25,25, GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (rings), "destroy", + (GtkSignalFunc) destroy_window, + &rings); + gtk_signal_connect (GTK_OBJECT (rings), "delete_event", + (GtkSignalFunc) destroy_window, + &rings); + } + else + gtk_widget_destroy (rings); +} + + +/* + * Progress Bar + */ +static int progress_timer = 0; + +gint +progress_timeout (gpointer data) +{ + gfloat new_val; + + new_val = GTK_PROGRESS_BAR (data)->percentage; + if (new_val >= 1.0) + new_val = 0.0; + new_val += 0.02; + + gtk_progress_bar_update (GTK_PROGRESS_BAR (data), new_val); + + return TRUE; +} + +void +destroy_progress (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + gtk_timeout_remove (progress_timer); + progress_timer = 0; +} + +void +create_progress_bar () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *pbar; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_progress, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_progress, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (vbox), 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new ("progress..."); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_widget_show (label); + + pbar = gtk_progress_bar_new (); + gtk_widget_set_usize (pbar, 200, 20); + gtk_box_pack_start (GTK_BOX (vbox), pbar, TRUE, TRUE, 0); + gtk_widget_show (pbar); + + progress_timer = gtk_timeout_add (100, progress_timeout, pbar); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Color Preview + */ +static int color_idle = 0; + +gint +color_idle_func (GtkWidget *preview) +{ + static int count = 1; + guchar buf[768]; + int i, j, k; + + for (i = 0; i < 256; i++) + { + for (j = 0, k = 0; j < 256; j++) + { + buf[k+0] = i + count; + buf[k+1] = 0; + buf[k+2] = j + count; + k += 3; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + count += 1; + + gtk_widget_draw (preview, NULL); + + return TRUE; +} + +void +color_preview_destroy (GtkWidget *widget, + GtkWidget **window) +{ + gtk_idle_remove (color_idle); + color_idle = 0; + + destroy_window (widget, window); +} + +void +create_color_preview () +{ + static GtkWidget *window = NULL; + GtkWidget *preview; + guchar buf[768]; + int i, j, k; + + if (!window) + { + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) color_preview_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) color_preview_destroy, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + preview = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (preview), 256, 256); + gtk_container_add (GTK_CONTAINER (window), preview); + gtk_widget_show (preview); + + for (i = 0; i < 256; i++) + { + for (j = 0, k = 0; j < 256; j++) + { + buf[k+0] = i; + buf[k+1] = 0; + buf[k+2] = j; + k += 3; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + color_idle = gtk_idle_add ((GtkFunction) color_idle_func, preview); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Gray Preview + */ +static int gray_idle = 0; + +gint +gray_idle_func (GtkWidget *preview) +{ + static int count = 1; + guchar buf[256]; + int i, j; + + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) + buf[j] = i + j + count; + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + count += 1; + + gtk_widget_draw (preview, NULL); + + return TRUE; +} + +void +gray_preview_destroy (GtkWidget *widget, + GtkWidget **window) +{ + gtk_idle_remove (gray_idle); + gray_idle = 0; + + destroy_window (widget, window); +} + +void +create_gray_preview () +{ + static GtkWidget *window = NULL; + GtkWidget *preview; + guchar buf[256]; + int i, j; + + if (!window) + { + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gray_preview_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) gray_preview_destroy, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + preview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE); + gtk_preview_size (GTK_PREVIEW (preview), 256, 256); + gtk_container_add (GTK_CONTAINER (window), preview); + gtk_widget_show (preview); + + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) + buf[j] = i + j; + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + gray_idle = gtk_idle_add ((GtkFunction) gray_idle_func, preview); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Selection Test + */ +void +selection_test_received (GtkWidget *list, GtkSelectionData *data) +{ + GdkAtom *atoms; + GtkWidget *list_item; + GList *item_list; + int i, l; + + if (data->length < 0) + { + g_print ("Selection retrieval failed\n"); + return; + } + if (data->type != GDK_SELECTION_TYPE_ATOM) + { + g_print ("Selection \"TARGETS\" was not returned as atoms!\n"); + return; + } + + /* Clear out any current list items */ + + gtk_list_clear_items (GTK_LIST(list), 0, -1); + + /* Add new items to list */ + + atoms = (GdkAtom *)data->data; + + item_list = NULL; + l = data->length / sizeof (GdkAtom); + for (i = 0; i < l; i++) + { + char *name; + name = gdk_atom_name (atoms[i]); + if (name != NULL) + { + list_item = gtk_list_item_new_with_label (name); + g_free (name); + } + else + list_item = gtk_list_item_new_with_label ("(bad atom)"); + + gtk_widget_show (list_item); + item_list = g_list_append (item_list, list_item); + } + + gtk_list_append_items (GTK_LIST (list), item_list); + + return; +} + +void +selection_test_get_targets (GtkWidget *widget, GtkWidget *list) +{ + static GdkAtom targets_atom = GDK_NONE; + + if (targets_atom == GDK_NONE) + targets_atom = gdk_atom_intern ("TARGETS", FALSE); + + gtk_selection_convert (list, GDK_SELECTION_PRIMARY, targets_atom, + GDK_CURRENT_TIME); +} + +void +create_selection_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *scrolled_win; + GtkWidget *list; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Selection Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + /* Create the list */ + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (vbox), 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, + TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new ("Gets available targets for current selection"); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0); + gtk_widget_set_usize (scrolled_win, 100, 200); + gtk_widget_show (scrolled_win); + + list = gtk_list_new (); + gtk_container_add (GTK_CONTAINER (scrolled_win), list); + + gtk_signal_connect (GTK_OBJECT(list), "selection_received", + GTK_SIGNAL_FUNC (selection_test_received), NULL); + gtk_widget_show (list); + + /* .. And create some buttons */ + button = gtk_button_new_with_label ("Get Targets"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (selection_test_get_targets), list); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Gamma Curve + */ +void +create_gamma_curve () +{ + static GtkWidget *window = NULL, *curve; + static int count = 0; + gfloat vec[256]; + gint max; + gint i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + curve = gtk_gamma_curve_new (); + gtk_container_add (GTK_CONTAINER (window), curve); + gtk_widget_show (curve); + } + + max = 127 + (count % 2)*128; + gtk_curve_set_range (GTK_CURVE (GTK_GAMMA_CURVE (curve)->curve), + 0, max, 0, max); + for (i = 0; i < max; ++i) + vec[i] = (127 / sqrt (max)) * sqrt (i); + gtk_curve_set_vector (GTK_CURVE (GTK_GAMMA_CURVE (curve)->curve), + max, vec); + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else if (count % 4 == 3) + { + gtk_widget_destroy (window); + window = NULL; + } + + ++count; +} + + +/* + * Timeout Test + */ +static int timer = 0; + +void +timeout_test (GtkWidget *label) +{ + static int count = 0; + static char buffer[32]; + + sprintf (buffer, "count: %d", ++count); + gtk_label_set (GTK_LABEL (label), buffer); +} + +void +start_timeout_test (GtkWidget *widget, + GtkWidget *label) +{ + if (!timer) + { + timer = gtk_timeout_add (100, (GtkFunction) timeout_test, label); + } +} + +void +stop_timeout_test (GtkWidget *widget, + gpointer data) +{ + if (timer) + { + gtk_timeout_remove (timer); + timer = 0; + } +} + +void +destroy_timeout_test (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + stop_timeout_test (NULL, NULL); +} + +void +create_timeout_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_timeout_test, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_timeout_test, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Timeout Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + label = gtk_label_new ("count: 0"); + gtk_misc_set_padding (GTK_MISC (label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + label, TRUE, TRUE, 0); + gtk_widget_show (label); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("start"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) start_timeout_test, + label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("stop"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) stop_timeout_test, + NULL); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Idle Test + */ +static int idle = 0; + +gint +idle_test (GtkWidget *label) +{ + static int count = 0; + static char buffer[32]; + + sprintf (buffer, "count: %d", ++count); + gtk_label_set (GTK_LABEL (label), buffer); + + return TRUE; +} + +void +start_idle_test (GtkWidget *widget, + GtkWidget *label) +{ + if (!idle) + { + idle = gtk_idle_add ((GtkFunction) idle_test, label); + } +} + +void +stop_idle_test (GtkWidget *widget, + gpointer data) +{ + if (idle) + { + gtk_idle_remove (idle); + idle = 0; + } +} + +void +destroy_idle_test (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + stop_idle_test (NULL, NULL); +} + +void +create_idle_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_idle_test, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_idle_test, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Idle Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + label = gtk_label_new ("count: 0"); + gtk_misc_set_padding (GTK_MISC (label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + label, TRUE, TRUE, 0); + gtk_widget_show (label); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("start"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) start_idle_test, + label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("stop"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) stop_idle_test, + NULL); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +test_destroy (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + gtk_main_quit (); +} + +/* + * Basic Test + */ +void +create_test () +{ + static GtkWidget *window = NULL; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) test_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) test_destroy, + &window); + + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + } + + if (!GTK_WIDGET_VISIBLE (window)) + { + gtk_widget_show (window); + + g_print ("create_test: start\n"); + gtk_main (); + g_print ("create_test: done\n"); + } + else + gtk_widget_destroy (window); +} + + +/* + * Main Window and Exit + */ +void +do_exit () +{ + gtk_exit (0); +} + +void +create_main_window () +{ + struct { + char *label; + void (*func) (); + } buttons[] = + { + { "buttons", create_buttons }, + { "toggle buttons", create_toggle_buttons }, + { "check buttons", create_check_buttons }, + { "radio buttons", create_radio_buttons }, + { "button box", create_button_box }, + { "reparent", create_reparent }, + { "pixmap", create_pixmap }, + { "tooltips", create_tooltips }, + { "menus", create_menus }, + { "scrolled windows", create_scrolled_windows }, + { "drawing areas", NULL }, + { "entry", create_entry }, + { "list", create_list }, + { "color selection", create_color_selection }, + { "file selection", create_file_selection }, + { "dialog", create_dialog }, + { "miscellaneous", NULL }, + { "range controls", create_range_controls }, + { "rulers", create_rulers }, + { "text", create_text }, + { "notebook", create_notebook }, + { "panes", create_panes }, + { "shapes", create_shapes }, + { "dnd", create_dnd }, + { "progress bar", create_progress_bar }, + { "preview color", create_color_preview }, + { "preview gray", create_gray_preview }, + { "gamma curve", create_gamma_curve }, + { "test selection", create_selection_test }, + { "test timeout", create_timeout_test }, + { "test idle", create_idle_test }, + { "test", create_test }, + }; + int nbuttons = sizeof (buttons) / sizeof (buttons[0]); + GtkWidget *window; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *scrolled_window; + GtkWidget *button; + GtkWidget *separator; + int i; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "main window"); + gtk_widget_set_usize (window, 200, 400); + gtk_widget_set_uposition (window, 20, 20); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gtk_exit, + NULL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) gtk_exit, + NULL); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (box1), scrolled_window, TRUE, TRUE, 0); + gtk_widget_show (scrolled_window); + + box2 = gtk_vbox_new (FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_container_add (GTK_CONTAINER (scrolled_window), box2); + gtk_widget_show (box2); + + for (i = 0; i < nbuttons; i++) + { + button = gtk_button_new_with_label (buttons[i].label); + if (buttons[i].func) + gtk_signal_connect (GTK_OBJECT (button), + "clicked", + (GtkSignalFunc) + buttons[i].func, NULL); + else + gtk_widget_set_sensitive (button, FALSE); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) do_exit, NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +int +main (int argc, char *argv[]) +{ + gtk_set_locale (); + + gtk_init (&argc, &argv); + gtk_rc_parse ("testgtkrc"); + + create_main_window (); + + gtk_main (); + + return 0; +} diff --git a/gtk/testgtkrc b/gtk/testgtkrc new file mode 100644 index 0000000000..e909e314b0 --- /dev/null +++ b/gtk/testgtkrc @@ -0,0 +1,69 @@ +# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..." +# +# style <name> [= <name>] +# { +# <option> +# } +# +# widget <widget_set> style <style_name> +# widget_class <widget_class_set> style <style_name> + +pixmap_path "." + +style "window" +{ +# bg_pixmap[NORMAL] = "warning.xpm" +} + +style "scale" +{ + fg[NORMAL] = { 1.0, 0, 0 } + bg_pixmap[NORMAL] = "<parent>" +} + +style "button" +{ + fg[PRELIGHT] = { 1.0, 1.0, 1.0 } + bg[PRELIGHT] = { 0, 0, 0.75 } +} + +style "main_button" = "button" +{ + font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*" + bg[PRELIGHT] = { 0.75, 0, 0 } +} + +style "toggle_button" = "button" +{ + fg[NORMAL] = { 1.0, 0, 0 } + fg[ACTIVE] = { 1.0, 0, 0 } + bg_pixmap[NORMAL] = "<parent>" +} + +style "text" +{ + bg_pixmap[NORMAL] = "marble.xpm" + fg[NORMAL] = { 1.0, 1.0, 1.0 } +} + +style "ruler" +{ + font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*" +} + +style "curve" +{ + fg[NORMAL] = { 58000, 0, 0 } # red +} + +widget_class "GtkWindow" style "window" +widget_class "GtkDialog" style "window" +widget_class "GtkFileSelection" style "window" +widget_class "*Gtk*Scale" style "scale" +widget_class "*GtkCheckButton*" style "toggle_button" +widget_class "*GtkRadioButton*" style "toggle_button" +widget_class "*GtkButton*" style "button" +widget_class "*Ruler" style "ruler" +widget_class "*GtkText" style "text" +widget "main window.*GtkButton*" style "main_button" +widget "*GtkCurve" style "curve" diff --git a/gtk/testinput.c b/gtk/testinput.c new file mode 100644 index 0000000000..1c6dae0e1d --- /dev/null +++ b/gtk/testinput.c @@ -0,0 +1,379 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtk.h" + +/* Backing pixmap for drawing area */ + +static GdkPixmap *pixmap = NULL; + +/* Information about cursor */ + +static gint need_cursor = FALSE; +static gint cursor_proximity = TRUE; +static gdouble cursor_x; +static gdouble cursor_y; + +/* Unique ID of current device */ +static guint32 current_device = GDK_CORE_POINTER; + +/* Check to see if we need to draw a cursor for current device */ +static void +check_cursor () +{ + GList *tmp_list; + + /* gdk_input_list_devices returns an internal list, so we shouldn't + free it afterwards */ + tmp_list = gdk_input_list_devices(); + + while (tmp_list) + { + GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data; + + if (info->deviceid == current_device) + { + need_cursor = !info->has_cursor; + break; + } + + tmp_list = tmp_list->next; + } +} + +/* Erase the old cursor, and/or draw a new one, if necessary */ +static void +update_cursor (GtkWidget *widget, gdouble x, gdouble y) +{ + static gint cursor_present = 0; + gint state = need_cursor && cursor_proximity; + + if (pixmap != NULL) + { + if (cursor_present && (cursor_present != state || + x != cursor_x || y != cursor_y)) + { + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pixmap, + cursor_x - 5, cursor_y - 5, + cursor_x - 5, cursor_y - 5, + 10, 10); + } + + cursor_present = state; + cursor_x = x; + cursor_y = y; + + if (cursor_present) + { + gdk_draw_rectangle (widget->window, + widget->style->black_gc, + TRUE, + cursor_x - 5, cursor_y -5, + 10, 10); + } + } +} + +/* Create a new backing pixmap of the appropriate size */ +static gint +configure_event (GtkWidget *widget, GdkEventConfigure *event) +{ + if (pixmap) + { + gdk_pixmap_destroy(pixmap); + } + pixmap = gdk_pixmap_new(widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + gdk_draw_rectangle (pixmap, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + return TRUE; +} + +/* Refill the screen from the backing pixmap */ +static gint +expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return FALSE; +} + +/* Draw a rectangle on the screen, size depending on pressure, + and color on the type of device */ +static void +draw_brush (GtkWidget *widget, GdkInputSource source, + gdouble x, gdouble y, gdouble pressure) +{ + GdkGC *gc; + GdkRectangle update_rect; + + switch (source) + { + case GDK_SOURCE_MOUSE: + gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)]; + break; + case GDK_SOURCE_PEN: + gc = widget->style->black_gc; + break; + case GDK_SOURCE_ERASER: + gc = widget->style->white_gc; + break; + default: + gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)]; + } + + update_rect.x = x - 10 * pressure; + update_rect.y = y - 10 * pressure; + update_rect.width = 20 * pressure; + update_rect.height = 20 * pressure; + gdk_draw_rectangle (pixmap, gc, TRUE, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height); + gtk_widget_draw (widget, &update_rect); +} + +static guint32 motion_time; + +static gint +button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + if (event->deviceid != current_device) + { + current_device = event->deviceid; + check_cursor (); + } + + cursor_proximity = TRUE; + + if (event->button == 1 && pixmap != NULL) + { + draw_brush (widget, event->source, event->x, event->y, + event->pressure); + motion_time = event->time; + } + + update_cursor (widget, event->x, event->y); + + return TRUE; +} + +static gint +motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +{ + GdkTimeCoord *coords; + int nevents; + int i; + + if (event->deviceid != current_device) + { + current_device = event->deviceid; + check_cursor (); + } + + cursor_proximity = TRUE; + + if (event->state & GDK_BUTTON1_MASK && pixmap != NULL) + { + coords = gdk_input_motion_events (event->window, event->deviceid, + motion_time, event->time, + &nevents); + motion_time = event->time; + if (coords) + { + for (i=0; i<nevents; i++) + draw_brush (widget, event->source, coords[i].x, coords[i].y, + coords[i].pressure); + g_free (coords); + } + else + { + if (event->is_hint) + gdk_input_window_get_pointer (event->window, event->deviceid, + NULL, NULL, NULL, NULL, NULL, NULL); + draw_brush (widget, event->source, event->x, event->y, + event->pressure); + } + } + else + { + gdk_input_window_get_pointer (event->window, event->deviceid, + &event->x, &event->y, + NULL, NULL, NULL, NULL); + } + + update_cursor (widget, event->x, event->y); + + return TRUE; +} + +/* We track the next two events to know when we need to draw a + cursor */ + +static gint +proximity_out_event (GtkWidget *widget, GdkEventProximity *event) +{ + cursor_proximity = FALSE; + update_cursor (widget, cursor_x, cursor_y); + return TRUE; +} + +static gint +leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) +{ + cursor_proximity = FALSE; + update_cursor (widget, cursor_x, cursor_y); + return TRUE; +} + +void +input_dialog_destroy (GtkWidget *w, gpointer data) +{ + *((GtkWidget **)data) = NULL; +} + +void +create_input_dialog () +{ + static GtkWidget *inputd = NULL; + + if (!inputd) + { + inputd = gtk_input_dialog_new(); + + gtk_signal_connect (GTK_OBJECT(inputd), "destroy", + (GtkSignalFunc)input_dialog_destroy, &inputd); + gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button), + "clicked", + (GtkSignalFunc)gtk_widget_hide, + GTK_OBJECT(inputd)); + gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button); + + gtk_signal_connect (GTK_OBJECT(inputd), "enable_device", + (GtkSignalFunc)check_cursor, NULL); + gtk_widget_show (inputd); + } + else + { + if (!GTK_WIDGET_MAPPED(inputd)) + gtk_widget_show(inputd); + else + gdk_window_raise(inputd->window); + } +} + +void +quit () +{ + gtk_exit (0); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *drawing_area; + GtkWidget *vbox; + + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "Test Input"); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (quit), NULL); + + /* Create the drawing area */ + + drawing_area = gtk_drawing_area_new (); + gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); + gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); + + gtk_widget_show (drawing_area); + + /* Signals used to handle backing pixmap */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", + (GtkSignalFunc) expose_event, NULL); + gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", + (GtkSignalFunc) configure_event, NULL); + + /* Event signals */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", + (GtkSignalFunc) motion_notify_event, NULL); + gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_signal_connect (GTK_OBJECT (drawing_area), "leave_notify_event", + (GtkSignalFunc) leave_notify_event, NULL); + gtk_signal_connect (GTK_OBJECT (drawing_area), "proximity_out_event", + (GtkSignalFunc) proximity_out_event, NULL); + + gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_PROXIMITY_OUT_MASK); + + /* The following call enables tracking and processing of extension + events for the drawing area */ + gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_ALL); + + /* .. And create some buttons */ + button = gtk_button_new_with_label ("Input Dialog"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (create_input_dialog), NULL); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/gtk/testselection.c b/gtk/testselection.c new file mode 100644 index 0000000000..3377cc6230 --- /dev/null +++ b/gtk/testselection.c @@ -0,0 +1,466 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtk.h" + +typedef enum { + SEL_TYPE_NONE, + APPLE_PICT, + ATOM, + ATOM_PAIR, + BITMAP, + C_STRING, + COLORMAP, + COMPOUND_TEXT, + DRAWABLE, + INTEGER, + PIXEL, + PIXMAP, + SPAN, + STRING, + TEXT, + WINDOW, + LAST_SEL_TYPE, +} SelType; + +GdkAtom seltypes[LAST_SEL_TYPE]; + +typedef struct _Target { + gchar *target_name; + SelType type; + GdkAtom target; + gint format; + GtkSelectionFunction *handler; +} Target; + +/* The following is a list of all the selection targets defined + in the ICCCM */ + +static Target targets[] = { + { "ADOBE_PORTABLE_DOCUMENT_FORMAT", STRING, 0, 8, NULL }, + { "APPLE_PICT", APPLE_PICT, 0, 8, NULL }, + { "BACKGROUND", PIXEL, 0, 32, NULL }, + { "BITMAP", BITMAP, 0, 32, NULL }, + { "CHARACTER_POSITION", SPAN, 0, 32, NULL }, + { "CLASS", TEXT, 0, 8, NULL }, + { "CLIENT_WINDOW", WINDOW, 0, 32, NULL }, + { "COLORMAP", COLORMAP, 0, 32, NULL }, + { "COLUMN_NUMBER", SPAN, 0, 32, NULL }, + { "COMPOUND_TEXT", COMPOUND_TEXT, 0, 8, NULL }, + /* { "DELETE", "NULL", 0, ?, NULL }, */ + { "DRAWABLE", DRAWABLE, 0, 32, NULL }, + { "ENCAPSULATED_POSTSCRIPT", STRING, 0, 8, NULL }, + { "ENCAPSULATED_POSTSCRIPT_INTERCHANGE", STRING, 0, 8, NULL }, + { "FILE_NAME", TEXT, 0, 8, NULL }, + { "FOREGROUND", PIXEL, 0, 32, NULL }, + { "HOST_NAME", TEXT, 0, 8, NULL }, + /* { "INSERT_PROPERTY", "NULL", 0, ? NULL }, */ + /* { "INSERT_SELECTION", "NULL", 0, ? NULL }, */ + { "LENGTH", INTEGER, 0, 32, NULL }, + { "LINE_NUMBER", SPAN, 0, 32, NULL }, + { "LIST_LENGTH", INTEGER, 0, 32, NULL }, + { "MODULE", TEXT, 0, 8, NULL }, + /* { "MULTIPLE", "ATOM_PAIR", 0, 32, NULL }, */ + { "NAME", TEXT, 0, 8, NULL }, + { "ODIF", TEXT, 0, 8, NULL }, + { "OWNER_OS", TEXT, 0, 8, NULL }, + { "PIXMAP", PIXMAP, 0, 32, NULL }, + { "POSTSCRIPT", STRING, 0, 8, NULL }, + { "PROCEDURE", TEXT, 0, 8, NULL }, + { "PROCESS", INTEGER, 0, 32, NULL }, + { "STRING", STRING, 0, 8, NULL }, + { "TARGETS", ATOM, 0, 32, NULL }, + { "TASK", INTEGER, 0, 32, NULL }, + { "TEXT", TEXT, 0, 8 , NULL }, + { "TIMESTAMP", INTEGER, 0, 32, NULL }, + { "USER", TEXT, 0, 8, NULL }, +}; + +static int num_targets = sizeof(targets)/sizeof(Target); + +static int have_selection = FALSE; + +GtkWidget *selection_text; +GtkWidget *selection_button; +GString *selection_string = NULL; + +static void +init_atoms () +{ + int i; + + seltypes[SEL_TYPE_NONE] = GDK_NONE; + seltypes[APPLE_PICT] = gdk_atom_intern ("APPLE_PICT",FALSE); + seltypes[ATOM] = gdk_atom_intern ("ATOM",FALSE); + seltypes[ATOM_PAIR] = gdk_atom_intern ("ATOM_PAIR",FALSE); + seltypes[BITMAP] = gdk_atom_intern ("BITMAP",FALSE); + seltypes[C_STRING] = gdk_atom_intern ("C_STRING",FALSE); + seltypes[COLORMAP] = gdk_atom_intern ("COLORMAP",FALSE); + seltypes[COMPOUND_TEXT] = gdk_atom_intern ("COMPOUND_TEXT",FALSE); + seltypes[DRAWABLE] = gdk_atom_intern ("DRAWABLE",FALSE); + seltypes[INTEGER] = gdk_atom_intern ("INTEGER",FALSE); + seltypes[PIXEL] = gdk_atom_intern ("PIXEL",FALSE); + seltypes[PIXMAP] = gdk_atom_intern ("PIXMAP",FALSE); + seltypes[SPAN] = gdk_atom_intern ("SPAN",FALSE); + seltypes[STRING] = gdk_atom_intern ("STRING",FALSE); + seltypes[TEXT] = gdk_atom_intern ("TEXT",FALSE); + seltypes[WINDOW] = gdk_atom_intern ("WINDOW",FALSE); + + for (i=0; i<num_targets; i++) + targets[i].target = gdk_atom_intern (targets[i].target_name, FALSE); +} + +void +selection_toggled (GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + { + have_selection = gtk_selection_owner_set (widget, + GDK_SELECTION_PRIMARY, + GDK_CURRENT_TIME); + if (!have_selection) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE); + } + else + { + if (have_selection) + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, + GDK_CURRENT_TIME); + have_selection = FALSE; + } + } +} + +void +selection_handle (GtkWidget *widget, + GtkSelectionData *selection_data, gpointer data) +{ + guchar *buffer; + gint len; + + if (!selection_string) + { + buffer = NULL; + len = 0; + } + else + { + buffer = selection_string->str; + len = selection_string->len; + } + + gtk_selection_data_set (selection_data, + selection_data->target == seltypes[COMPOUND_TEXT] ? + seltypes[COMPOUND_TEXT] : seltypes[STRING], + 8, buffer, len); +} + +gint +selection_clear (GtkWidget *widget, GdkEventSelection *event) +{ + have_selection = FALSE; + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE); + + return TRUE; +} + +gchar * +stringify_atom (guchar *data, gint *position) +{ + gchar *str = gdk_atom_name (*(GdkAtom *)(data+*position)); + *position += sizeof(GdkAtom); + + return str; +} + +gchar * +stringify_text (guchar *data, gint *position) +{ + gchar *str = g_strdup ((gchar *)(data+*position)); + *position += strlen (str) + 1; + + return str; +} + +gchar * +stringify_xid (guchar *data, gint *position) +{ + gchar buffer[20]; + gchar *str; + + sprintf(buffer,"0x%x",*(guint32 *)(data+*position)); + str = g_strdup (buffer); + + *position += sizeof(guint32); + + return str; +} + +gchar * +stringify_integer (guchar *data, gint *position) +{ + gchar buffer[20]; + gchar *str; + + sprintf(buffer,"%d",*(int *)(data+*position)); + str = g_strdup (buffer); + + *position += sizeof(int); + + return str; +} + +gchar * +stringify_span (guchar *data, gint *position) +{ + gchar buffer[42]; + gchar *str; + + sprintf(buffer,"%d - %d",((int *)(data+*position))[0], + ((int *)(data+*position))[1]); + str = g_strdup (buffer); + + *position += 2*sizeof(int); + + return str; +} + +void +selection_received (GtkWidget *widget, GtkSelectionData *data) +{ + int position; + int i; + SelType seltype; + char *str; + + if (data->length < 0) + { + g_print("Error retrieving selection\n"); + return; + } + + seltype = SEL_TYPE_NONE; + for (i=0; i<LAST_SEL_TYPE; i++) + { + if (seltypes[i] == data->type) + { + seltype = i; + break; + } + } + + if (seltype == SEL_TYPE_NONE) + { + char *name = gdk_atom_name (data->type); + g_print("Don't know how to handle type: %s (%ld)\n", + name?name:"<unknown>", + data->type); + return; + } + + if (selection_string != NULL) + g_string_free (selection_string, TRUE); + + selection_string = g_string_new (NULL); + + gtk_text_freeze (GTK_TEXT (selection_text)); + gtk_text_set_point (GTK_TEXT (selection_text), 0); + gtk_text_foreward_delete (GTK_TEXT (selection_text), + gtk_text_get_length (GTK_TEXT (selection_text))); + + position = 0; + while (position < data->length) + { + switch (seltype) + { + case ATOM: + str = stringify_atom (data->data, &position); + break; + case COMPOUND_TEXT: + case STRING: + case TEXT: + str = stringify_text (data->data, &position); + break; + case BITMAP: + case DRAWABLE: + case PIXMAP: + case WINDOW: + case COLORMAP: + str = stringify_xid (data->data, &position); + break; + case INTEGER: + case PIXEL: + str = stringify_integer (data->data, &position); + break; + case SPAN: + str = stringify_span (data->data, &position); + break; + default: + { + char *name = gdk_atom_name (data->type); + g_print("Can't convert type %s (%ld) to string\n", + name?name:"<unknown>", + data->type); + position = data->length; + } + } + gtk_text_insert (GTK_TEXT (selection_text), NULL, + &selection_text->style->black, + NULL, str, -1); + gtk_text_insert (GTK_TEXT (selection_text), NULL, + &selection_text->style->black, + NULL, "\n", -1); + g_string_append (selection_string, str); + g_free (str); + } + gtk_text_thaw (GTK_TEXT (selection_text)); +} + +void +paste (GtkWidget *widget, GtkWidget *entry) +{ + char *name; + GdkAtom atom; + + name = gtk_entry_get_text (GTK_ENTRY(entry)); + atom = gdk_atom_intern (name, FALSE); + + if (atom == GDK_NONE) + { + g_print("Could not create atom: \"%s\"\n",name); + return; + } + + gtk_selection_convert (selection_button, GDK_SELECTION_PRIMARY, atom, + GDK_CURRENT_TIME); +} + +void +quit () +{ + gtk_exit (0); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *table; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *hbox; + + gtk_init (&argc, &argv); + + init_atoms(); + + dialog = gtk_dialog_new (); + gtk_widget_set_name (dialog, "Test Input"); + gtk_container_border_width (GTK_CONTAINER(dialog), 0); + + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + GTK_SIGNAL_FUNC (quit), NULL); + + table = gtk_table_new (4, 2, FALSE); + gtk_container_border_width (GTK_CONTAINER(table), 10); + + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 5); + gtk_table_set_row_spacing (GTK_TABLE (table), 1, 2); + gtk_table_set_row_spacing (GTK_TABLE (table), 2, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), + table, TRUE, TRUE, 0); + gtk_widget_show (table); + + selection_button = gtk_toggle_button_new_with_label ("Claim Selection"); + gtk_table_attach (GTK_TABLE (table), selection_button, 0, 2, 0, 1, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_widget_show (selection_button); + + gtk_signal_connect (GTK_OBJECT(selection_button), "toggled", + GTK_SIGNAL_FUNC (selection_toggled), NULL); + gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event", + GTK_SIGNAL_FUNC (selection_clear), NULL); + gtk_signal_connect (GTK_OBJECT(selection_button), "selection_received", + GTK_SIGNAL_FUNC (selection_received), NULL); + + gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY, + seltypes[STRING], selection_handle, NULL, NULL); + + gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY, + seltypes[TEXT], selection_handle, NULL, NULL); + + gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY, + seltypes[COMPOUND_TEXT], + selection_handle, NULL, NULL); + + selection_text = gtk_text_new (NULL, NULL); + gtk_table_attach_defaults (GTK_TABLE (table), selection_text, 0, 1, 1, 2); + gtk_widget_show (selection_text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (selection_text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (selection_text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 1, 2, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, 3, 4, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_widget_show (hbox); + + label = gtk_label_new ("Target:"); + gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX(hbox), entry, TRUE, TRUE, 0); + gtk_widget_show (entry); + + /* .. And create some buttons */ + button = gtk_button_new_with_label ("Paste"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (paste), entry); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (dialog)); + gtk_widget_show (button); + + gtk_widget_show (dialog); + + gtk_main (); + + return 0; +} diff --git a/install-sh b/install-sh new file mode 100755 index 0000000000..89fc9b098b --- /dev/null +++ b/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# 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}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + 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;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + 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` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/ltconfig b/ltconfig new file mode 100755 index 0000000000..e9d3a83795 --- /dev/null +++ b/ltconfig @@ -0,0 +1,1415 @@ +#! /bin/sh + +# ltconfig - Create a system-specific libtool. +# Generated automatically from ltconfig.in by configure. +# Copyright (C) 1996, 1997, Free Software Foundation, Inc. +# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This file 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. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A lot of this script is taken from autoconf-2.10. + +# The name of this program. +progname=`echo "$0" | sed 's%^.*/%%'` + +# Constants: +PROGRAM=ltconfig +PACKAGE=libtool +VERSION=1.0f +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5' +rm="rm -f" + +help="Try \`$progname --help' for more information." + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$\\\\]\)/\\\1/g' + +# Same as above, but don't quote variable references. +double_quote_subst='s/\([\\"\\\\]\)/\\\1/g' + +# Global variables: +can_build_shared=yes +enable_shared=yes +# All known linkers require a `.a' archive for static linking. +enable_static=yes +ltmain= +silent= +srcdir= +ac_config_guess= +ac_config_sub= +host= +nonopt= +verify_host=yes +with_gcc=no +with_gnu_ld=no + +old_AR="$AR" +old_CC="$CC" +old_CFLAGS="$CFLAGS" +old_CPPFLAGS="$CPPFLAGS" +old_LD="$LD" +old_LN_S="$LN_S" +old_NM="$NM" +old_RANLIB="$RANLIB" + +# Parse the command line options. +args= +prev= +for option +do + case "$option" in + -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval "$prev=\$option" + prev= + continue + fi + + case "$option" in + --help) cat <<EOM +Usage: $progname [OPTION]... LTMAIN [HOST] + +Generate a system-specific libtool script. + + --disable-shared do not build shared libraries + --disable-static do not build static libraries + --help display this help and exit + --no-verify do not verify that HOST is a valid host type + --quiet same as \`--silent' + --silent don't print informational messages + --srcdir=DIR find \`config.guess' in DIR + --version output version information and exit + --with-gcc assume that the GNU C compiler will be used + --with-gnu-ld assume that the C compiler uses the GNU linker + +LTMAIN is the \`ltmain.sh' shell script fragment that provides basic libtool +functionality. + +HOST is the canonical host system name [default=guessed]. +EOM + exit 0 + ;; + + --disable-shared) enable_shared=no ;; + + --disable-static) enable_static=no ;; + + --quiet | --silent) silent=yes ;; + + --srcdir) prev=srcdir ;; + --srcdir=*) srcdir="$optarg" ;; + + --no-verify) verify_host=no ;; + + --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION"; exit 0 ;; + + --with-gcc) with_gcc=yes ;; + --with-gnu-ld) with_gnu_ld=yes ;; + + -*) + echo "$progname: unrecognized option \`$option'" 1>&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + if test -z "$ltmain"; then + ltmain="$option" + elif test -z "$host"; then +# FIXME This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 +# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then +# echo "$progname: warning \`$option' is not a valid host type" 1>&2 +# fi + host="$option" + else + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac +done + +if test -z "$ltmain"; then + echo "$progname: you must specify a LTMAIN file" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +if test -f "$ltmain"; then : +else + echo "$progname: warning: \`$ltmain' does not exist" 1>&2 +fi + +# Quote any args containing shell metacharacters. +ltconfig_args= +for arg +do + case "$arg" in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ltconfig_args="$ltconfig_args '$arg'" ;; + *) ltconfig_args="$ltconfig_args $arg" ;; + esac +done + +# A relevant subset of AC_INIT. + +# 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 +# 5 compiler messages saved in config.log +# 6 checking for... messages and results +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>>./config.log + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +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 "$srcdir"; then + # Assume the source directory is the same one as the path to ltmain.sh. + srcdir=`echo "$ltmain" | sed 's%/[^/]*$%%'` + test "$srcdir" = "$ltmain" && srcdir=. +fi + +trap "$rm conftest*; exit 1" 1 2 15 +if test "$verify_host" = yes; then + # Check for config.guess and config.sub. + ac_aux_dir= + for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/config.guess; then + ac_aux_dir=$ac_dir + break + fi + done + if test -z "$ac_aux_dir"; then + echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 + echo "$help" 1>&2 + exit 1 + fi + ac_config_guess=$ac_aux_dir/config.guess + ac_config_sub=$ac_aux_dir/config.sub + + # Make sure we can run config.sub. + if $ac_config_sub sun4 >/dev/null 2>&1; then : + else + echo "$progname: cannot run $ac_config_sub" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + echo $ac_n "checking host system type""... $ac_c" 1>&6 + + host_alias=$host + case "$host_alias" in + "") + if host_alias=`$ac_config_guess`; then : + else + echo "$progname: cannot guess host type; you must specify one" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac + host=`$ac_config_sub $host_alias` + echo "$ac_t$host" 1>&6 + + # Make sure the host verified. + test -z "$host" && exit 1 + +elif test -z "$host"; then + echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 + echo "$help" 1>&2 + exit 1 +else + host_alias=$host +fi + +# Transform *-*-linux* to *-*-linux-gnu*, to support old configure scripts. +case "$host" in +*-*-linux-gnu*) ;; +*-*-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +case "$host_os" in +aix*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR cru $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' + +# Set a sane default for `AR'. +test -z "$AR" && AR=ar + +# If RANLIB is not set, then run the test. +if test "${RANLIB+set}" != "set"; then + result=no + + echo $ac_n "checking for ranlib... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/ranlib; then + RANLIB="ranlib" + result="ranlib" + break + fi + done + IFS="$save_ifs" + + echo "$ac_t$result" 1>&6 +fi + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds;\$RANLIB \$oldlib" + old_postinstall_cmds="$old_postinstall_cmds;\$RANLIB \$oldlib" +fi + +# Check to see if we are using GCC. +if test "$with_gcc" != yes || test -z "$CC"; then + # If CC is not set, then try to find GCC or a usable CC. + if test -z "$CC"; then + echo $ac_n "checking for gcc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + IFS="$save_ifs" + test -z "$dir" && dir=. + if test -f $dir/gcc; then + CC="gcc" + break + fi + done + IFS="$save_ifs" + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + fi + + # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". + if test -z "$CC"; then + echo $ac_n "checking for cc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + cc_rejected=no + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/cc; then + if test "$dir/cc" = "/usr/ucb/cc"; then + cc_rejected=yes + continue + fi + CC="cc" + break + fi + done + IFS="$save_ifs" + if test $cc_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same name, so the bogon will be chosen + # first if we set CC to just the name; use the full file name. + shift + set dummy "$dir/cc" "$@" + shift + CC="$@" + fi + fi + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$CC"; then + echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 + exit 1 + fi + fi + + # Now see if the compiler is really GCC. + with_gcc=no + echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 + echo "$progname:394: checking whether we are using GNU C" >&5 + + $rm conftest.c + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF + if { ac_try='${CC-cc} -E conftest.c'; { (eval echo $progname:402: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + with_gcc=yes + fi + $rm conftest.c + echo "$ac_t$with_gcc" 1>&6 +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 +pic_flag= +profile_flag_pattern= +special_shlib_compile_flags= +wl= +link_static_flag= +no_builtin_flag= + +if test "$with_gcc" = yes; then + profile_flag_pattern='-pg?' + wl='-Wl,' + link_static_flag='-static' + no_builtin_flag=' -fno-builtin' + + case "$host_os" in + aix3* | aix4* | irix5* | irix6* | osf3* | osf4*) + # PIC is the default for these OSes. + ;; + os2*) + # We can build DLLs from non-PIC. + ;; + *) + pic_flag='-fPIC' + ;; + esac +else + # PORTME Check for PIC flags for the system compiler. + case "$host_os" in + aix3* | aix4*) + # All AIX code is PIC. + link_static_flag='-bnso -bI:/lib/syscalls.exp' + ;; + + hpux9* | hpux10*) + # Is there a better link_static_flag that works with the bundled CC? + wl='-Wl,' + link_static_flag='${wl}-a ${wl}archive' + pic_flag='+Z' + ;; + + irix5* | irix6*) + wl='-Wl,' + link_static_flag='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + os2*) + # We can build DLLs from non-PIC. + ;; + + osf3* | osf4*) + # All OSF/1 code is PIC. + wl='-Wl,' + link_static_flag='-non_shared' + ;; + + sco3.2v5*) + pic_flag='-Kpic' + link_static_flag='-dn' + special_shlib_compile_flags='-belf' + ;; + + solaris2*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + sunos4*) + pic_flag='-PIC' + link_static_flag='-Bstatic' + wl='-Qoption ld ' + ;; + + uts4*) + pic_flag='-pic' + link_static_flag='-Bstatic' + ;; + + *) + can_build_shared=no + ;; + esac +fi + +if test -n "$pic_flag"; then + echo "$ac_t$pic_flag" 1>&6 + + # Check to make sure the pic_flag actually works. + echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 + $rm conftest* + echo > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $pic_flag -DPIC" + echo "$progname:507: checking if $compiler PIC flag $pic_flag works" >&5 + if { (eval echo $progname:508: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + + # On HP-UX, the stripped-down bundled CC doesn't accept +Z, but also + # reports no error. So, we need to grep stderr for (Bundled). + if grep '(Bundled)' conftest.err >/dev/null; then + echo "$ac_t"no 1>&6 + can_build_shared=no + pic_flag= + else + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + can_build_shared=no + pic_flag= + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + echo "$ac_t"none 1>&6 +fi + +# Check for any special shared library compilation flags. +if test -n "$special_shlib_compile_flags"; then + echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : + else + echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 + can_build_shared=no + fi +fi + +echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 +$rm conftest* +echo 'main(){return(0);}' > conftest.c +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $link_static_flag" +echo "$progname:550: checking if $compiler static flag $link_static_flag works" >&5 +if { (eval echo $progname:551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + echo "$ac_t$link_static_flag" 1>&6 +else + echo "$ac_t"none 1>&6 + link_static_flag= +fi +LDFLAGS="$save_LDFLAGS" +$rm conftest* + +if test -z "$LN_S"; then + # Check to see if we can use ln -s, or we need hard links. + echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 + $rm conftestdata + if ln -s X conftestdata 2>/dev/null; then + $rm conftestdata + LN_S="ln -s" + else + LN_S=ln + fi + if test "$LN_S" = "ln -s"; then + echo "$ac_t"yes 1>&6 + else + echo "$ac_t"no 1>&6 + fi +fi + +# Make sure LD is an absolute path. +if test -z "$LD"; then + ac_prog=ld + if test "$with_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 + echo "$progname:583: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac + elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld... $ac_c" 1>&6 + echo "$progname:601: checking for GNU ld" >&5 + else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 + echo "$progname:604: checking for non-GNU ld" >&5 + fi + + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" + fi + + if test -n "$LD"; then + echo "$ac_t$LD" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$LD"; then + echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 + exit 1 + fi +fi + +# Check to see if it really is or isn't GNU ld. +echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 +# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + with_gnu_ld=yes +else + with_gnu_ld=no +fi +echo "$ac_t$with_gnu_ld" 1>&6 + +# See if the linker supports building shared libraries. +echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 + +allow_undefined_flag= +archive_cmds= +old_archive_from_new_cmds= +export_dynamic_flag_spec= +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_runpath_var=no +hardcode_shlibpath_var=unsupported +runpath_var= + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # See if GNU ld supports shared libraries. + + case "$host_os" in + sunos4*) + ld_shlibs=yes + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + archive_cmds='$CC -shared ${wl}-soname $wl$soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath $wl$libdir' + export_dynamic_flag_spec='${wl}-export-dynamic' + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case "$host_os" in + aix3*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$LD -o $objdir/$soname$libobjs -bE:$lib.exp -T512 -H512 -bM:SRE$deplibs;$AR cru $lib $objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$with_gcc" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$CC -o $objdir/$soname$libobjs ${wl}-bE:$lib.exp ${wl}-bM:SRE ${wl}-bnoentry$deplibs;$AR cru $lib $objdir/$soname' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # doesn't break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs /usr/lib/c++rt0.o' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 don't have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3, at last, uses gcc -shared to do shared libraries. + freebsd3*) + archive_cmds='$CC -shared -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + archive_cmds='$rm $objdir/$soname;$LD -b +s +b $install_libdir -o $objdir/$soname$libobjs$deplibs;mv $objdir/$soname $lib' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + hpux10*) + archive_cmds='$LD -b +h $soname +s +b $install_libdir -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + irix5* | irix6*) + archive_cmds='$LD -shared -o $lib -soname $soname -set_version $verstring$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + ;; + + netbsd*) + # Tested with NetBSD 1.2 ld + archive_cmds='$LD -Bshareable -o $lib$libobjs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def;echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def;echo DATA >> $objdir/$libname.def;echo " SINGLE NONSHARED" >> $objdir/$libname.def;echo EXPORTS >> $objdir/$libname.def;emxexp$libobjs >> $objdir/$libname.def;$CC -Zdll -Zcrtdll -o $lib$libobjs $objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' + ;; + + osf3* | osf4*) + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} -o $lib -soname $soname -set_version $verstring$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -o $lib$libobjs$deplibs' + hardcode_direct=yes + ;; + + solaris2*) + archive_cmds='$LD -G -z text -h $soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bstatic -o $lib$libobjs' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + can_build_shared=no + ;; + esac +fi +echo "$ac_t$ld_shlibs" 1>&6 + +if test -z "$NM"; then + echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 + case "$NM" in + /*) ;; # Let the user override the test with a path. + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + NM="$ac_dir/nm -p" + else + NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$NM" && NM=nm + ;; + esac + echo "$ac_t$NM" 1>&6 +fi + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRSTU]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \1' + +# Define system-specific variables. +case "$host_os" in +aix*) + symcode='[BCDTU]' + ;; +solaris2*) + symcode='[BDTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTUW]' +fi + +# Write the raw and C identifiers. +global_symbol_pipe="sed -n -e 's/^.* $symcode $sympat$/$symxfrm/p'" + +# Check to see that the pipe works correctly. +pipe_works=no +$rm conftest* +cat > conftest.c <<EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(){} +#ifdef __cplusplus +} +#endif +main(){nm_test_var='a';nm_test_func();return(0);} +EOF + +echo "$progname:900: checking if global_symbol_pipe works" >&5 +if { (eval echo $progname:901: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.o; then + # Now try to grab the symbols. + nlist=conftest.nm + if { echo "$progname:904: eval \"$NM conftest.o | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.o | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`echo "$wcout" | sed 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + rm -f "$nlist"T + count=-1 + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat <<EOF > conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + sed 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> conftest.c + + cat <<EOF >> conftest.c +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{ +EOF + sed 's/^\(.*\) \(.*\)$/ {"\1", \&\2},/' < "$nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0}, +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.o conftestm.o + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS='conftestm.o' + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo $progname:962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + pipe_works=yes + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$save_LIBS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $global_symbol_pipe" >&5 + fi +else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 +fi +$rm conftest* + +# Don't use the global_symbol_pipe unless it works. +echo "$ac_t$pipe_works" 1>&6 +test "$pipe_works" = yes || global_symbol_pipe= + +# Check hardcoding attributes. +echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test "$hardcode_runpath_var" = yes; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && \ + test "$hardcode_minus_L" != no && \ + test "$hardcode_shlibpath_var" != no; then + + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +elif test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" != yes; then + # We can't hardcode anything. + hardcode_action=unsupported +else + # We can only hardcode existing directories. + hardcode_action=relink +fi +echo "$ac_t$hardcode_action" 1>&6 +test "$hardcode_action" = unsupported && can_build_shared=no + + +reload_flag= +reload_cmds='$LD$reload_flag -o $output$reload_objs' +echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 +# PORTME Some linker may need a different reload flag. +reload_flag='-r' +echo "$ac_t$reload_flag" +test -n "$reload_flag" && reload_flag=" $reload_flag" + +# PORTME Fill in your ld.so characteristics +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +finish_cmds= +shlibpath_var= +version_type=none +dynamic_linker="$host_os ld.so" + +echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 +case "$host_os" in +aix3* | aix4*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='$libname.so.$major' + ;; + +freebsd2* | freebsd3*) + version_type=sunos + library_names_spec='$libname.so.$versuffix $libname.so' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +gnu*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + shlibpath_var=LD_LIBRARY_PATH + ;; + +hpux9* | hpux10*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + shlibpath_var=SHLIB_PATH + library_names_spec='$libname.sl.$versuffix $libname.sl.$major $libname.sl' + soname_spec='$libname.sl.$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=osf + soname_spec='$libname.so' + library_names_spec='$libname.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + + if test -f /lib/ld.so.1; then + dynamic_linker='GNU ld.so' + else + # Only the GNU ld.so supports shared libraries on MkLinux. + case "$host_cpu" in + powerpc*) dynamic_linker=no ;; + *) dynamic_linker='Linux ld.so' ;; + esac + fi + ;; + +netbsd* | openbsd*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + version_type=none + libname_spec='$name' + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4*) + version_type=osf + soname_spec='$libname.so' + library_names_spec='$libname.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sco3.2v5*) + version_type=osf + soname_spec='$libname.so.$major' + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris2*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +uts4*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$ac_t$dynamic_linker" +test "$dynamic_linker" = no && can_build_shared=no + +# FIXME add checks for striplib and old_striplib here. +# strip -x works for most platforms, though not for static libraries on NetBSD +# HP-UX requires "-r" for library stripping +striplib= +old_striplib= + +# Report the final consequences. +echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 + +echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds;\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +esac + +echo "$ac_t$enable_shared" 1>&6 + +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes + +echo "checking whether to build static libraries... $enable_static" 1>&6 + +echo $ac_n "checking for objdir... $ac_c" 1>&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$ac_t$objdir" 1>&6 + +# Now quote all the things that may contain metacharacters. +for var in old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \ + old_LN_S AR CC LD LN_S NM reload_flag reload_cmds wl pic_flag \ + link_static_flag no_builtin_flag export_dynamic_flag_spec \ + profile_flag_pattern libname_spec library_names_spec soname_spec RANLIB \ + old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + archive_cmds postinstall_cmds \ + allow_undefined_flag finish_cmds global_symbol_pipe \ + striplib old_striplib \ + hardcode_libdir_flag_spec hardcode_libdir_separator; do + + case "$var" in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | archive_cmds | postinstall_cmds | finish_cmds) + # Double-quote double-evaled strings. + eval "$var=\`echo \"\$$var\" | sed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\"\`" + ;; + *) + eval "$var=\`echo \"\$$var\" | sed \"\$sed_quote_subst\"\`" + ;; + esac +done + +ofile=libtool +trap "$rm $ofile; exit 1" 1 2 15 +echo creating $ofile +$rm $ofile +cat <<EOF > $ofile +#! /bin/sh + +# libtool - Provide generalized library-building support services. +# +# Generated automatically by $PROGRAM - GNU $PACKAGE $VERSION +# This program was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# CC="$old_CC" CFLAGS="$old_CFLAGS" CPPFLAGS="$old_CPPFLAGS" \\ +# LD="$old_LD" NM="$old_NM" RANLIB="$old_RANLIB" LN_S="$old_LN_S" \\ +# $0$ltconfig_args +# +# Compiler and other test output produced by $progname, useful for +# debugging $progname, is in ./config.log if it exists. + +# The version of $progname that generated this script. +LTCONFIG_VERSION="$VERSION" + +# Shell to use when invoking shell scripts. +SHELL=${CONFIG_SHELL-/bin/sh} + +# Whether or not to build libtool libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build old-style libraries. +build_old_libs=$enable_static + +# The host system. +host_alias="$host_alias" +host="$host" + +# The archiver. +AR="$AR" + +# The default C compiler. +CC="$CC" + +# The linker used to build libraries. +LD="$LD" + +# Whether we need hard or soft links. +LN_S="$LN_S" + +# A BSD-compatible nm program. +NM="$NM" + +# The name of the directory that contains temporary libtool files. +objdir="$objdir" + +# How to create reloadable object files. +reload_flag="$reload_flag" +reload_cmds="$reload_cmds" + +# How to pass a linker flag through the compiler. +wl="$wl" + +# Additional compiler flags for building library objects. +pic_flag="$pic_flag" + +# Compiler flag to prevent dynamic linking. +link_static_flag="$link_static_flag" + +# Compiler flag to turn off builtin functions. +no_builtin_flag="$no_builtin_flag" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="$export_dynamic_flag_spec" + +# Pattern to match compiler flags for creating libNAME_p libraries: +profile_flag_pattern="$profile_flag_pattern" + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec="$libname_spec" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="$library_names_spec" + +# The coded name of the library, if different from the real name. +soname_spec="$soname_spec" + +# Commands used to build and install an old-style archive. +RANLIB="$RANLIB" +old_archive_cmds="$old_archive_cmds" +old_postinstall_cmds="$old_postinstall_cmds" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="$old_archive_from_new_cmds" + +# Commands used to build and install a shared archive. +archive_cmds="$archive_cmds" +postinstall_cmds="$postinstall_cmds" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="$allow_undefined_flag" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="$finish_cmds" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="$global_symbol_pipe" + +# How to strip a library file. +striplib="$striplib" +old_striplib="$old_striplib" + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using RUNPATH_VAR=DIR during linking hardcodes DIR into the +# resulting binary. +hardcode_runpath_var=$hardcode_runpath_var + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +EOF + +case "$host_os" in +aix*) + cat <<\EOF >> $ofile +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES +fi + +EOF + ;; +esac + +# Detect if we are using a relative or absolute path to ltmain.sh. +case "$ltmain" in +/*) cat <<EOF >> $ofile +# Execute the libtool backend. +. $ltmain +EOF + ;; +*) cat <<EOF >> $ofile +# Find the path to this script. +thisdir=\`echo "\$0" | sed -e 's%/[^/]*\$%%'\` +test "X\$0" = "X\$thisdir" && thisdir=. + +# Execute the libtool backend. +. \$thisdir/$ltmain +EOF + ;; +esac + +echo 'exit 1' >> $ofile + +chmod +x $ofile +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/ltmain.sh b/ltmain.sh new file mode 100644 index 0000000000..cb46c84987 --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,2372 @@ +# ltmain.sh - Provide generalized library-building support services. +# Generated automatically from ltmain.in by configure. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program 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. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +#FIXME: echo=echo +echo='printf %s\n' +if test "X`$echo '\t'`" = 'X\t'; then : +else + # The Solaris and AIX default echo program unquotes backslashes. + # This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # So, we emulate echo with printf '%s\n' + echo='printf %s\n' + if test "X`$echo '\t'`" = 'X\t'; then : + else + # Oops. We have no working printf. Try to find a not-so-buggy echo. + echo=echo + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + save_PATH="$PATH" + PATH="$PATH":/usr/ucb + for dir in $PATH; do + if test -f $dir/echo && test "X`$dir/echo '\t'`" = 'X\t'; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + PATH="$save_PATH" + fi +fi + +# The name of this program. +progname=`$echo "$0" | sed 's%^.*/%%'` + +# Constants. +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.0f + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$\\\\]\)/\\\1/g' + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +if test "$LTCONFIG_VERSION" != "$VERSION"; then + $echo "$progname: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + $echo "$progname: not configured to build any kind of library" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case "$arg" in + -*=*) optarg=`$echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + execute_dlfiles) + eval "$prev=\"\$$prev \$arg\"" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case "$arg" in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION" + exit 0 + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$progname: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$progname: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case "$nonopt" in + *cc | *++) + mode=link + for arg + do + case "$arg" in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx) + mode=execute + ;; + *install*|cp) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$progname: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$progname: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$progname: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case "$mode" in + # libtool compile mode + compile) + progname="$progname: compile" + # Get the compilation command and the source file. + base_compile= + lastarg= + srcfile="$nonopt" + suppress_output= + + for arg + do + # The only flag that cannot be specified is the output filename. + if test "X$arg" = "X-o"; then + $echo "$progname: you cannot specify the output filename with \`-o'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "$lastarg" | sed "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly in scan + # sets, so we specify it separately. + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + # Get the name of the library object. + libobj=`$echo "$srcfile" | sed -e 's%^.*/%%'` + + # Recognize several different file suffixes. + xform='[cCFSfm]' + case "$libobj" in + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "$libobj" | sed -e "s/\.$xform$/.lo/"` + + case "$libobj" in + *.lo) obj=`$echo "$libobj" | sed -e 's/\.lo$/.o/'` ;; + *) + $echo "$progname: cannot determine name of library object from \`$srcfile'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$progname: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + $run $rm $obj $libobj + trap "$run $rm $obj $libobj; exit 1" 1 2 15 + else + $run $rm $libobj + trap "$run $rm $libobj; exit 1" 1 2 15 + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + # All platforms use -DPIC, to notify preprocessed assembler code. + $show "$base_compile$pic_flag -DPIC $srcfile" + if $run eval "$base_compile\$pic_flag -DPIC \$srcfile"; then : + else + test -n "$obj" && $run $rm $obj + exit 1 + fi + + # If we have no pic_flag, then copy the object into place and finish. + if test -z "$pic_flag"; then + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj + exit $? + fi + + # Just move the object, then go on to compile the next one + $show "$mv $obj $libobj" + $run $mv $obj $libobj || exit 1 + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + # Suppress compiler output if we already did a PIC compilation. + $show "$base_compile $srcfile$suppress_output" + if $run eval "$base_compile \$srcfile$suppress_output"; then : + else + $run $rm $obj $libobj + exit 1 + fi + fi + + # Create an invalid libtool object if no PIC, so that we don't accidentally + # link it into a program. + if test "$build_libtool_libs" != yes; then + $show "$echo timestamp > $libobj" + $run eval "\$echo timestamp > \$libobj" || exit $? + fi + + exit 0 + ;; + + # libtool link mode + link) + progname="$progname: link" + CC="$nonopt" + allow_undefined=no + compile_command="$CC" + finalize_command="$CC" + + compile_shlibpath= + finalize_shlibpath= + deplibs= + dlfiles= + dlprefiles= + export_dynamic=no + hardcode_libdirs= + libobjs= + link_against_libtool_libs= + ltlibs= + objs= + prev= + prevarg= + rpath= + perm_rpath= + temp_rpath= + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case "$arg" in + -all-static | -static) + if test "X$arg" = "X-all-static" && test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$progname: warning: complete static linking is impossible in this configuration" 1>&2 + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + for arg + do + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case "$prev" in + dlfiles|dlprefiles) + case "$arg" in + *.la | *.lo) ;; # We handle these cases below. + *) + dlprefiles="$dlprefiles $arg" + test "$prev" = dlfiles && dlfiles="$dlfiles $arg" + prev= + ;; + esac + ;; + rpath) + rpath="$rpath $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi + + prevarg="$arg" + + case "$arg" in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + allow_undefined=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + if test "$export_dynamic" != yes; then + export_dynamic=yes + if test -n "$export_dynamic_flag_spec"; then + arg=`eval \\$echo "$export_dynamic_flag_spec"` + else + arg= + fi + + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + fi + ;; + + -L*) + dir=`$echo "$arg" | sed 's%^-L\(.*\)$%\1%'` + case "$dir" in + /*) + # Add the corresponding hardcode_libdir_flag, if it is not identical. + ;; + *) + $echo "$progname: \`-L$dir' cannot specify a relative directory" 1>&2 + exit 1 + ;; + esac + deplibs="$deplibs $arg" + ;; + + -l*) deplibs="$deplibs $arg" ;; + + -o) prev=output ;; + + -rpath) + prev=rpath + continue + ;; + + -static) + # If we have no pic_flag, then this is the same as -all-static. + if test -z "$pic_flag" && test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + + *.o | *.a) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A library object. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test "$build_libtool_libs" = yes; then + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "$arg" | sed 's/\.lo$/\.o/'` + prev= + fi + libobjs="$libobjs $arg" + ;; + + *.la) + # A libtool-controlled library. + + dlname= + libdir= + library_names= + old_library= + + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $arg >/dev/null 2>&1; then : + else + $echo "$progname: \`$arg' is not a valid libtool archive" 1>&2 + exit 1 + fi + + # If there is no directory component, then add one. + case "$arg" in + */*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$libdir"; then + $echo "$progname: \`$arg' contains no -rpath information" 1>&2 + exit 1 + fi + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + + if test -z "$linklib"; then + $echo "$progname: cannot find name of link library for \`$arg'" 1>&2 + exit 1 + fi + + # Find the relevant object directory and library name. + name=`$echo "$arg" | sed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` + dir=`$echo "$arg" | sed 's%/[^/]*$%%'` + if test "X$dir" = "X$arg"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + + # This library was specified with -dlopen. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test -z "$dlname"; then + # If there is no dlname, we need to preload. + prev=dlprefiles + else + # We should not create a dependency on this library. + prev= + continue + fi + fi + + # The library was specified with -dlpreopen. + if test "$prev" = dlprefiles; then + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + dlprefiles="$dlprefiles $dir/$old_library" + else + dlprefiles="$dlprefiles $dir/$linklib" + fi + prev= + fi + + if test "$build_libtool_libs" = yes && test -n "$library_names"; then + link_against_libtool_libs="$link_against_libtool_libs $arg" + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # This is the magic to use -rpath. + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + flag=`eval \\$echo \"$hardcode_libdir_flag_spec\"` + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test "$hardcode_runpath_var" = yes; then + # Do the same for the permanent run path. + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + + + case "$hardcode_action" in + immediate) + if test "$hardcode_direct" = no; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = no; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = no; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + relink) + # We need an absolute path. + case "$dir" in + /*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$progname: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + + if test "$hardcode_direct" = yes; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + *) + $echo "$progname: \`$hardcode_action' is an unknown hardcode action" 1>&2 + exit 1 + ;; + esac + + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + finalize_command="$finalize_command $libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + finalize_command="$finalize_command -L$libdir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + finalize_shlibpath="$finalize_shlibpath$libdir:" + finalize_command="$finalize_command -l$name" + else + # We can't seem to hardcode it, guess we'll fake it. + finalize_command="$finalize_command -L$libdir -l$name" + fi + else + # Transform directly to old archives if we don't build new libraries. + if test -n "$pic_flag" && test -z "$old_library"; then + $echo "$progname: cannot find static library for \`$arg'" 1>&2 + exit 1 + fi + + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_command="$compile_command $dir/$linklib" + finalize_command="$finalize_command $dir/$linklib" + else + compile_command="$compile_command -L$dir -l$name" + finalize_command="$finalize_command -L$dir -l$name" + fi + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + esac + + # Now actually substitute the argument into the commands. + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + done + + if test -n "$prev"; then + $echo "$progname: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + oldlib= + oldobjs= + case "$output" in + "") + $echo "$progname: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + */*) + $echo "$progname: output file \`$output' must have no directory components" 1>&2 + exit 1 + ;; + + *.la) + # Make sure we only generate libraries of the form `libNAME.la'. + case "$output" in + lib*) ;; + *) + $echo "$progname: libtool library \`$arg' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + name=`$echo "$output" | sed -e 's/\.la$//' -e 's/^lib//'` + libname=`eval \\$echo \"$libname_spec\"` + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + current=0 + revision=0 + age=0 + + if test -n "$objs"; then + $echo "$progname: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 + exit 1 + fi + + # How the heck are we supposed to write a wrapper for a shared library? + if test -n "$link_against_libtool_libs"; then + $echo "$progname: libtool library \`$output' may not depend on uninstalled libraries:$link_against_libtool_libs" 1>&2 + exit 1 + fi + + # Add libc to deplibs on all systems. + deplibs="$deplibs -lc" + + if test -n "$dlfiles$dlprefiles"; then + $echo "$progname: warning: \`-dlopen' is ignored while creating libtool libraries" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -z "$rpath"; then + $echo "$progname: you must specify an installation directory with \`-rpath'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$progname: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo + IFS="$save_ifs" + + if test -n "$5"; then + $echo "$progname: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + test -n "$2" && current="$2" + test -n "$3" && revision="$3" + test -n "$4" && age="$4" + + # Check that each of the things are valid numbers. + case "$current" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$revision" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$age" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$progname: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + version_vars="version_type current age revision" + case "$version_type" in + none) ;; + + linux) + version_vars="$version_vars major versuffix" + major=`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + version_vars="$version_vars versuffix verstring" + major=`expr $current - $age` + versuffix="$current.$age.$revision" + verstring="$versuffix" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + version_vars="$version_vars major versuffix" + major="$current" + versuffix="$current.$revision" + ;; + + *) + $echo "$progname: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Create the output directory, or remove our outputs if we need to. + if test -d $objdir; then + $show "$rm $objdir/$output $objdir/$libname.*" + $run $rm $objdir/$output $objdir/$libname.* + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$progname: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Clear the flag. + allow_undefined_flag= + fi + + if test "$build_libtool_libs" = yes; then + # Get the real and link names of the library. + library_names=`eval \\$echo \"$library_names_spec\"` + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + soname=`eval \\$echo \"$soname_spec\"` + else + soname="$realname" + fi + + lib="$objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are PIC. + test -z "$pic_flag" && libobjs=`$echo "$libobjs " | sed -e 's/\.lo /.o /g' -e 's/ $//g'` + + # Do each of the archive commands. + cmds=`eval \\$echo \"$archive_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Create links to the real library. + for link in $linknames; do + $show "(cd $objdir && $LN_S $realname $link)" + $run eval '(cd $objdir && $LN_S $realname $link)' || exit $? + done + + # If -export-dynamic was specified, set the dlname. + if test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + *.lo | *.o) + if test -n "$link_against_libtool_libs"; then + $echo "$progname: error: cannot link libtool libraries into reloadable objects" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$progname: warning: \`-l' and \`-L' are ignored while creating objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles"; then + $echo "$progname: warning: \`-dlopen' is ignored while creating objects" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -n "$rpath"; then + $echo "$progname: warning: \`-rpath' is ignored while creating objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$progname: warning: \`-version-info' is ignored while creating objects" 1>&2 + fi + + case "$output" in + *.lo) + if test -n "$objs"; then + $echo "$progname: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "$output" | sed 's/\.lo$/.o/'` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Create the old-style object. + reload_objs="$objs"`$echo "$libobjs " | sed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + output="$obj" + cmds=`eval \\$echo \"$reload_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + test -z "$libobj" && exit 0 + + if test "$build_libtool_libs" != yes; then + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "$echo timestamp > $libobj" + $run eval "\$echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs" + output="$libobj" + cmds=`eval \\$echo \"$reload_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj || exit 1 + fi + + exit 0 + ;; + + *) + if test -n "$vinfo"; then + $echo "$progname: warning: \`-version-info' is ignored while linking programs" 1>&2 + fi + + if test -n "$rpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + flag=`eval \\$echo \"$hardcode_libdir_flag_spec\"` + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test "$hardcode_runpath_var" = yes; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + fi + + # Substitute the hardcoded libdirs into the compile commands. + if test -n "$hardcode_libdir_separator"; then + compile_command=`$echo "$compile_command" | sed "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + finalize_command=`$echo "$finalize_command" | sed "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + fi + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "$compile_command " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + finalize_command=`$echo "$finalize_command " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + fi + + if test "$export_dynamic" = yes && test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${output}S.c" + else + dlsyms= + fi + + if test -n "$dlsyms"; then + # Add our own program objects to the preloaded list. + dlprefiles=`$echo "$objs$dlprefiles " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + + # Discover the nlist of each of the dlfiles. + nlist="$objdir/${output}.nm" + + if test -d $objdir; then + $show "$rm $nlist ${nlist}T" + $run $rm "$nlist" "${nlist}T" + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + # Parse the name list into a source file. + $show "creating $objdir/$dlsyms" + if test -z "$run"; then + # Make sure we at least have an empty file. + test -f "$nlist" || : > "$nlist" + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`$echo "$wcout" | sed 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + $rm "$nlist"T + count=-1 + fi + + case "$dlsyms" in + "") ;; + *.c) + cat <<EOF > "$objdir/$dlsyms" +/* $dlsyms - symbol resolution table for \`$output' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define dld_preloaded_symbol_count some_other_symbol +#define dld_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */ +EOF + if test -f "$nlist"; then + sed -e 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> "$objdir/$dlsyms" + else + $echo '/* NONE */' >> "$objdir/$dlsyms" +EOF + fi + + cat <<EOF >> "$objdir/$dlsyms" + +#undef dld_preloaded_symbol_count +#undef dld_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{ +EOF + + if test -f "$nlist"; then + sed 's/^\(.*\) \(.*\)$/ {"\1", \&\2},/' < "$nlist" >> "$objdir/$dlsyms" + fi + + cat <<\EOF >> "$objdir/$dlsyms" + {0}, +}; + +#ifdef __cplusplus +} +#endif +EOF + ;; + + *) + echo "$progname: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + fi + + # Now compile the dynamic symbol file. + $show "(cd $objdir && $CC -c$no_builtin_flag \"$dlsyms\")" + $run eval '(cd $objdir && $CC -c$no_builtin_flag "$dlsyms")' || exit $? + + # Transform the symbol file into the correct name. + compile_command=`$echo "$compile_command" | sed "s%@SYMFILE@%$objdir/${output}S.o%"` + finalize_command=`$echo "$finalize_command" | sed "s%@SYMFILE@%$objdir/${output}S.o%"` + elif test "$export_dynamic" != yes; then + test -n "$dlfiles$dlprefiles" && $echo "$progname: warning: \`-dlopen' and \`-dlpreopen' are ignored without \`-export-dynamic'" 1>&2 + else + # We keep going just in case the user didn't refer to + # dld_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + $echo "$progname: not configured to extract global symbols from dlpreopened files" 1>&2 + + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "$compile_command" | sed 's%@OUTPUT@%'"$output"'%g'` + finalize_command=`$echo "$finalize_command" | sed 's%@OUTPUT@%'"$output"'%g'` + + # We have no uninstalled library dependencies, so finalize right now. + $show "$compile_command" + $run eval "$compile_command" + exit $? + fi + + # Replace the output file specification. + compile_command=`$echo "$compile_command" | sed 's%@OUTPUT@%'"$objdir/$output"'%g'` + finalize_command=`$echo "$finalize_command" | sed 's%@OUTPUT@%'"$objdir/$output"'T%g'` + + # Create the binary in the object directory, then wrap it. + if test -d $objdir; then : + else + $show "$mkdir $objdir" + $run $mkdir $objdir || exit $? + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case "$dir" in + /*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + # Delete the old output file. + $run $rm $output + + if test -n "$compile_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_command="$runpath_var=\"$rpath\$$runpath_var\" $compile_command" + finalize_command="$runpath_var=\"$rpath\$$runpath_var\" $finalize_command" + fi + + case "$hardcode_action" in + relink) + # AGH! Flame the AIX and HP-UX people for me, will ya? + $echo "$progname: warning: using a buggy system linker" 1>&2 + $echo "$progname: relinking will be required before \`$output' can be installed" 1>&2 + ;; + esac + + $show "$compile_command" + $run eval "$compile_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the finalize command for shipping. + finalize_command=`$echo "$finalize_command" | sed "$sed_quote_subst"` + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + cat > $output <<EOF +#! /bin/sh + +# $output - temporary wrapper script for $objdir/$output +# Generated by ltmain.sh - GNU $PACKAGE $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of \``pwd`'. +# If it is, it will not operate correctly. + +# This environment variable determines our operation mode. +if test "\$libtool_install_magic" = "$magic"; then + # install mode needs the following variables: + link_against_libtool_libs='$link_against_libtool_libs' + finalize_command="$finalize_command" +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test "\$libtool_execute_magic" = "$magic"; then : + else + echo='$echo' + file="\$0" + fi + + # Find the directory that this script lives in. + thisdir=\`\$echo "\$file" | sed 's%/[^/]*$%%'\` + test "x\$thisdir" = "x\$file" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld "\$file" | sed -n 's/.*-> //p'\` + while test -n "\$file"; do + destdir=\`\$echo "\$file" | sed 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test "x\$destdir" != "x\$file"; then + case "\$destdir" in + /*) thisdir="\$destdir" ;; + *) thisdir="\$thisdir/\$destdir" ;; + esac + fi + + file=\`\$echo "\$file" | sed 's%^.*/%%'\` + file=\`ls -ld "\$thisdir/\$file" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd "\$thisdir" && pwd\` + test -n "\$absdir" && thisdir="\$absdir" + + progdir="\$thisdir/$objdir" + program='$output' + + if test -f "\$progdir/\$program"; then +EOF + + # Export our shlibpath_var if we have one. + if test -n "$shlibpath_var" && test -n "$temp_rpath"; then + cat >> $output <<EOF + # Add our own library path to $shlibpath_var + $shlibpath_var="$temp_rpath\$$shlibpath_var" + + # Some systems cannot cope with colon-terminated $shlibpath_var + $shlibpath_var=\`\$echo \$$shlibpath_var | sed -e 's/:*\$//'\` + + export $shlibpath_var + +EOF + fi + + cat >> $output <<EOF + if test "\$libtool_execute_magic" != "$magic"; then + # Run the actual program with our arguments. + args= + for arg + do + # Quote arguments (to preserve shell metacharacters). + sed_quote_subst='$sed_quote_subst' + arg=\`\$echo "\$arg" | sed "\$sed_quote_subst"\` + args="\$args \\"\$arg\\"" + done + + # Export the path to the program. + PATH="\$progdir:\$PATH" + export PATH + + eval "exec \$program \$args" + + \$echo "\$0: cannot exec \$program \$args" + exit 1 + fi + else + # The program doesn't exist. + \$echo "\$0: error: \$progdir/\$program does not exist" 1>&2 + \$echo "This script is just a wrapper for \$program." 1>&2 + \$echo "See the $PACKAGE documentation for more information." 1>&2 + exit 1 + fi +fi +EOF + chmod +x $output + fi + exit 0 + ;; + esac + + + # See if we need to build an old-fashioned archive. + if test "$build_old_libs" = "yes"; then + # Now set the variables for building old libraries. + oldlib="$objdir/$libname.a" + + # Transform .lo files to .o files. + oldobjs="$objs"`$echo "$libobjs " | sed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + if test -d "$objdir"; then + $show "$rm $oldlib" + $run $rm $oldlib + else + $show "$mkdir $objdir" + $run $mkdir $objdir + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=`eval \\$echo \"$old_archive_from_new_cmds\"` + else + cmds=`eval \\$echo \"$old_archive_cmds\"` + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Now create the libtool archive. + case "$output" in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.a" + + $show "creating $output" + + # Only create the output if not a dry run. + if test -z "$run"; then + cat > $output <<EOF +# $output - a libtool library file +# Generated by ltmain.sh - GNU $PACKAGE $VERSION + +# The name that we can dlopen(3). +dlname='$dlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Directory that this library needs to be installed in: +libdir='$install_libdir' +EOF + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $objdir && $LN_S ../$output $output)" + $run eval "(cd $objdir && $LN_S ../$output $output)" || exit 1 + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + progname="$progname: install" + + # There may be an optional /bin/sh argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL"; then + # Aesthetically quote it. + arg=`$echo "$nonopt" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir= + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case "$arg" in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$progname: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$progname: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$progname: no file or destination specified" 1>&2 + else + $echo "$progname: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "$dest" | sed 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test -n "$isdir"; then + destdir="$dest" + destname= + else + destdir=`$echo "$dest" | sed 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "$dest" | sed 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$progname: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case "$destdir" in + /*) ;; + *) + for file in $files; do + case "$file" in + *.lo) ;; + *) + $echo "$progname: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case "$file" in + *.a) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then : + else + $echo "$progname: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir="`$echo "$file" | sed 's%/[^/]*$%%'`/" + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$realname $destdir/$realname" + $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? + test "X$dlname" = "X$realname" && dlname= + + # Support stripping libraries. + if test -n "$stripme"; then + if test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run $striplib $destdir/$realname || exit $? + else + $echo "$progname: warning: no library stripping program" 1>&2 + fi + fi + + if test $# -gt 0; then + # Delete the old symlinks. + rmcmd="$rm" + for linkname + do + rmcmd="$rmcmd $destdir/$linkname" + done + $show "$rmcmd" + $run $rmcmd + + # ... and create new ones. + for linkname + do + test "X$dlname" = "X$linkname" && dlname= + $show "(cd $destdir && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $LN_S $realname $linkname)" + done + fi + + if test -n "$dlname"; then + # Install the dynamically-loadable library. + $show "$install_prog $dir/$dlname $destdir/$dlname" + $run eval "$install_prog $dir/$dlname $destdir/$dlname" || exit $? + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=`eval \\$echo \"$postinstall_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "$file" | sed 's%^.*/%%'` + $show "$install_prog $file $destdir/$name" + $run eval "$install_prog $file $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "$file" | sed 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case "$destfile" in + *.lo) + staticdest=`$echo "$destfile" | sed 's/\.lo$/\.o/'` + ;; + *.o) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$progname: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "$file" | sed 's/\.lo$/\.o/'` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Do a test to see if this is really a libtool program. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + link_against_libtool_libs= + finalize_command= + + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$link_against_libtool_libs" || test -z "$finalize_command"; then + $echo "$progname: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $link_against_libtool_libs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case "$lib" in + */*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/`$echo "$lib" | sed 's%^.*/%%g'`" + if test -z "$libdir"; then + $echo "$progname: warning: \`$lib' contains no -rpath information" 1>&2 + elif test -f "$libfile"; then : + else + $echo "$progname: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + if test "$hardcode_action" = relink; then + if test "$finalize" = yes; then + $echo "$progname: warning: relinking \`$file' on behalf of your buggy system linker" 1>&2 + $show "$finalize_command" + if $run eval "$finalize_command"; then : + else + $echo "$progname: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + file="$objdir/$file"T + else + $echo "$progname: warning: cannot relink \`$file' on behalf of your buggy system linker" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "$file" | sed "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + $show "$install_prog$stripme $file $dest" + $run eval "$install_prog\$stripme \$file \$dest" || exit $? + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "$file" | sed 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + # Support stripping libraries. + if test -n "$stripme"; then + if test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run $old_striplib $oldlib || exit $? + else + $echo "$progname: warning: no static library stripping program" 1>&2 + fi + fi + + # Do each command in the postinstall commands. + cmds=`eval \\$echo \"$old_postinstall_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$progname: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + progname="$progname: finish" + libdirs="$nonopt" + + if test -n "$finish_cmds" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + # Do each command in the postinstall commands. + cmds=`eval \\$echo \"$finish_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + done + fi + + $echo "To link against installed libraries in LIBDIR, users may have to:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to their \`$shlibpath_var' environment variable" + fi + $echo " - use the \`-LLIBDIR' linker flag" + exit 0 + ;; + + # libtool execute mode + execute) + progname="$progname: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$progname: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test -f "$file"; then : + else + $echo "$progname: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case "$file" in + *.la) + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then : + else + $echo "$progname: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$progname: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "$file" | sed 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$progname: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "$file" | sed 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$progname: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case "$file" in + -*) ;; + *) + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "$file" | sed "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$progname: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool uninstall mode + uninstall) + progname="$progname: uninstall" + rm="$nonopt" + files= + + for arg + do + case "$arg" in + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$progname: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + for file in $files; do + dir=`$echo "$file" | sed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + name=`$echo "$file" | sed -e 's%^.*/%%'` + + rmfiles="$file" + + case "$name" in + *.la) + # Possibly a libtool archive, so verify it. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $dir/$n" + test "X$n" = "X$dlname" && dlname= + done + test -n "$dlname" && rmfiles="$rmfiles $dir/$dlname" + test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" + + # FIXME: should reinstall the best remaining shared library. + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "$name" | sed 's/\.lo$/\.o/'` + rmfiles="$rmfiles $dir/$oldobj" + fi + ;; + esac + + $show "$rm $rmfiles" + $run $rm $rmfiles + done + exit 0 + ;; + + "") + $echo "$progname: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$progname: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case "$mode" in +"") cat <<EOF +Usage: $progname [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + +-n, --dry-run display commands without modifying any files + --features display configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$progname --help --mode=MODE' for +a more detailed description of MODE. +EOF + ;; + +compile) + cat <<EOF +Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'. +EOF + ;; + +execute) + cat <<EOF +Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments. +EOF + ;; + +finish) + cat <<EOF +Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed. +EOF + ;; + +install) + cat <<EOF +Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized). +EOF + ;; + +link) + cat <<EOF +Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -allow-undefined allow a libtool library to reference undefined symbols + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to dld_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only +library objects (\`.lo' files) may be specified, and \`-rpath' is required. + +If OUTPUT-FILE ends in \`.a', then a standard library is created using \`ar' +and \`ranlib'. + +If OUTPUT-FILE ends in \`.lo' or \`.o', then a reloadable object file is +created, otherwise an executable program is created. +EOF + ;; + +uninstall) + cat <<EOF +Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM. +EOF + ;; + +*) + $echo "$progname: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +$echo +$echo "Try \`$progname --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/makecopyright b/makecopyright new file mode 100755 index 0000000000..5e17fd329e --- /dev/null +++ b/makecopyright @@ -0,0 +1,124 @@ +#!/bin/sh + + +copyright_glib () +{ + cat << EOF +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +EOF +} + +copyright_gdk () +{ + cat << EOF +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +EOF +} + +copyright_gtk () +{ + cat << EOF +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +EOF +} + +copyright_interp () +{ + cat << EOF +/* GTK Interp - The GTK Interpreter + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +EOF +} + + +exclude_files="./glib/gconfig.h" + +for file in `find . -name "*.[ch]" -print`; do + exclude=`echo $exclude_files | grep $file` + + if test "x$exclude" = "x"; then + dir=`dirname $file` + if test "x$dir" != "x."; then + subdir=`basename $dir` + + grepout=`grep Copyright $file` + if test "x$grepout" = "x"; then + backup_dir="$dir/bak" + if test ! -d $backup_dir; then + echo "making directory: $backup_dir" + mkdir $backup_dir + fi + + echo $file + + filename=`basename $file` + cp $file $backup_dir/$filename + copyright_$subdir > $file + cat $backup_dir/$filename >> $file + fi + fi + fi +done diff --git a/missing b/missing new file mode 100755 index 0000000000..e4b838ca92 --- /dev/null +++ b/missing @@ -0,0 +1,134 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996. + +# This program 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, or (at your option) +# any later version. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison touch file \`y.tab.c' + makeinfo touch the output file + yacc touch file \`y.tab.c'" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + touch config.h.in + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print \ + | sed 's/^\(.*\).am$/touch \1.in/' \ + | sh + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + your modified any \`.y' file. For being effective, your + modifications might require the \`Bison' package. Grab it from + any GNU archive site." + touch y.tab.c + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000000..fef1eb9418 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,36 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? + fi + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000000..9788f70238 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/tests/3DRings.xpm b/tests/3DRings.xpm new file mode 100644 index 0000000000..1ca75da752 --- /dev/null +++ b/tests/3DRings.xpm @@ -0,0 +1,116 @@ +/* XPM */ +static char * DRings_xpm[] = { +"48 48 65 1", +" c None", +". c #104010404103", +"X c #1040208130C2", +"o c #104014515144", +"O c #000010402081", +"+ c #1040104030C2", +"@ c #208120815144", +"# c #28A241035965", +"$ c #30C230C26185", +"% c #208130C24103", +"& c #104010402081", +"* c #104000002081", +"= c #000010401040", +"- c #492441036185", +"; c #596559659E79", +": c #30C220815144", +"> c #0820186128A2", +", c #000000001040", +"< c #2081104030C2", +"1 c #514459659658", +"2 c #514455556185", +"3 c #104000001040", +"4 c #000008200000", +"5 c #618569A6AEBA", +"6 c #618569A69658", +"7 c #410345148E38", +"8 c #104020814103", +"9 c #79E782079658", +"0 c #208120814103", +"q c #596571C69E79", +"w c #4103514471C6", +"e c #2081208130C2", +"r c #6185618571C6", +"t c #28A228A25965", +"y c #596561858617", +"u c #96589E79BEFB", +"i c #28A230C271C6", +"p c #38E345145144", +"a c #79E78207A699", +"s c #30C2492469A6", +"d c #410330C25965", +"f c #410351446185", +"g c #AEBAAAAAD75C", +"h c #38E338E34103", +"j c #EFBEEBADEFBE", +"k c #208130C25144", +"l c #9658A289DF7D", +"z c #208110404103", +"x c #28A228A26185", +"c c #8E388A28BEFB", +"v c #208118612081", +"b c #38E3451479E7", +"n c #4924618579E7", +"m c #86178617B6DA", +"M c #30C220814103", +"N c #104030C25144", +"B c #4103410371C6", +"V c #86178A28D75C", +"C c #DF7DDB6CE79D", +"Z c #BEFBC30BD75C", +"A c #410330C271C6", +"S c #30C228A230C2", +"D c #082008201861", +"F c #186130C238E3", +"G c #0000208130C2", +" .Xo ", +" O+O@#$% ", +" &*=+X-;: ", +" >&=,=<11#2 ", +" +O34,X567& ", +" 8X+=,90q9w. ", +" +e<>3r tyu-& ", +" Xi%.= paus+ ", +" Od-@= fga$h ", +" @y7X, Xrjak ", +" 2:eaw+ $ag;@ ", +" .X@8@k@o@X+ +pl9tO ", +" +zX@x$$isikt8o02crv ", +" 8@%ip7757ywbs$Ohn6#. ", +" &0%$p7r215ybw1pzp2-0= ", +" 8tk$#yw21665n;1+%-p$O ", +" O<e7pbryq5am9ay6XMpM>3& ", +" 9.NtpBw16amclVcm1t%kX*88 ", +" +&etd7r6y9ulgglm6>e>3s@83 ", +" +0k$y-y69cgCCCZVam%+#ik8X ", +" O&oi$d725amgCjCZu962ybtx8+p ", +" &X0x$sBym9VZCCCZca;yBbi%08& ", +" =++@sApMy5muZZgum6y2wds:>+& ", +" #tp;1;yB#i25cVucma5;w-pti@8& ", +" .#2alumnBp:@1r59y9y6ywBS$%0X+= ", +" %$wmZVu;#tX8X07r1656y2wbp$k@%@OD ", +" 0Byc9a;h%0>&D&hBrr2r1bwB-AF:0<&*= ", +" kBf;yr#@X+&<%MkhsBwBwpsB#Bktkt8+Oh ", +" xt7B-t8*,3O.X00:$i#dBd#bptFek0X.+* ", +" Xt#b#@=, =&O+X0Ft%ibsp$p$ki%l5sX&= ", +" &<kvX&4 +O*&<X0e:%$pAti%:edugn0= ", +" +X@&+, V,O&>+Xt>tktktv0%@k;Cls+ ", +" =+O*4*X:p;9cy3&&8ve0FMtt$ee0>z7cZ6k ", +" D=D4,=.k$sBs$ee=+X0Fk%-#t%0X&O0nu9bG ", +" ,,434*&ze@F<eeeeee><tdhdSMe<&&XAaawx ", +" 4,4,=+><peeeeee&=<%M%$hSF0X&O&kw5r%Z ", +" D&vSFMF<>&D =0S-2i& ", +" +>puB> >0h7s. ", +" SM5VqM &0t#$8 ", +" XpVV70 &0kMk. ", +" XdyB%z *X<%@+ ", +" &k$b0X+=8X08o ", +" &e:e+=*X.X+& ", +" +X.O+X0O.=, ", +" +>&+0>3&* ", +" &X0k+O, ", +" >v,3 ", +" "}; diff --git a/tests/FilesQueue.xpm b/tests/FilesQueue.xpm new file mode 100644 index 0000000000..586d27ec43 --- /dev/null +++ b/tests/FilesQueue.xpm @@ -0,0 +1,98 @@ +/* XPM */ +static char * FilesQueue_xpm[] = { +"44 31 64 1", +" c None", +". c #E79DE38DDF7D", +"X c #CF3CC71BCF3C", +"o c #71C675D671C6", +"O c #B6DAB2CAB6DA", +"+ c #CF3CD34CCF3C", +"@ c #DF7DE38DE79D", +"# c #FFFFFBEEFFFF", +"$ c #EFBEEFBEEFBE", +"% c #DF7DDB6CDF7D", +"& c #BEFBBAEAC71B", +"* c #BEFBBAEABEFB", +"= c #BEFBC30BC71B", +"- c #71C66DB671C6", +"; c #D75CD34CD75C", +": c #9E799A699E79", +"> c #E79DE38DE79D", +", c #CF3CCB2BC71B", +"< c #B6DAB2CABEFB", +"1 c #BEFBBAEAB6DA", +"2 c #B6DAB6DAB6DA", +"3 c #618561856185", +"4 c #C71BBAEABEFB", +"5 c #AEBAAAAAAEBA", +"6 c #965892488E38", +"7 c #A699A699A699", +"8 c #38E338E338E3", +"9 c #F7DEF7DEF7DE", +"0 c #E79DEFBEEFBE", +"q c #DF7DE38DDF7D", +"w c #C71BC71BC71B", +"e c #C71BC30BBEFB", +"r c #BEFBC30BBEFB", +"t c #B6DAAAAAAEBA", +"y c #410345144103", +"u c #D75CDB6CD75C", +"i c #C71BCB2BC71B", +"p c #BEFBCB2BBEFB", +"a c #9E79A289A699", +"s c #86178E388E38", +"d c #CF3CCF3CD75C", +"f c #CF3CD75CCF3C", +"g c #C71BC30BCF3C", +"h c #28A22CB228A2", +"j c #000000000000", +"k c #D75CD34CDF7D", +"l c #10400C300820", +"z c #E79DEBADEFBE", +"x c #DF7DDB6CD75C", +"c c #514459655965", +"v c #8617861779E7", +"b c #DF7DD34CD75C", +"n c #CF3CCB2BCF3C", +"m c #618555555965", +"M c #861786178617", +"N c #30C234D330C2", +"B c #EFBEEBADE79D", +"V c #DF7DDB6CE79D", +"C c #D75CE38DD75C", +"Z c #514449245144", +"A c #186120812081", +"S c #79E77DF779E7", +"D c #6185659569A6", +"F c #9E7992489E79", +" .XoOX+ ", +" @#$%&*=-o;: ", +" @>,=O<12*&:-<3X ", +" >%&1*4*2*OO**56758790 ", +" 9qX+we=r*&e<<<251t5555yu9 ", +" $qu++;ipi=p*=p**2tOOO27a5s<- ", +" #9udfXi;,gi&**4**4r*Ot5t55tehj ", +" 0qku+u;+d,gg=*=r*&**&<255t<*yl1 ", +" $$zq@%xk%uf;,w,i=i=e**r=12tO1=8cvj ", +" $@%>.%.%%%xbkx,w+ni,wwrwe*4*1=;8mMNj ", +" zz@Bz>>>V%%%C+u;;dfnnfwggi&=&X+yZsNll ", +" af#9@B0>q>qqq>xk.;;;kfX+XnXw=g,fycMhhN5 ", +" al5#9$$>qzBV.%x%%b;x+fnf+,X,iiqym6NAo-j ", +" #roS%#$zz>>V%%xkk%f;;+df,XnwnVZD:8AS-j* ", +" D-9Oy*9$Bz>q%qx%%u;x;;dknX+d>Zm:hhSDjr ", +" a3o+>S3z#90@@z.%>qCC%uu;ff%@Zm:NhMoj= ", +" wlvvo#:3599$>B>q>%%%%+f;fk$ymaalMvjr ", +" 0.a--S49mct9$z@.qkkqC;xu%@Zm5AlvSj* ", +" ohu%3:Z:9@y609q@@>..>Cx>$Zm5NhMvjr ", +" -j797Zv5705y=#$0>>V.%>#Z378AMMj* ", +" Zj9Xo-McBXDv%90.%%#9cc78AsMj* ", +" 8hM#M-DSF96cvz0>z#c35Nhs6j1 ", +" jl9#o63vx#-D###mmt8N66j* ", +" 5jc@fZF3o%+ZFDm<8A6FjO ", +" :j50sSay<$ss2Nh:FjO ", +" 6880&SDMF.rNNFFj1 ", +" 8jr#:SFScA6ajO ", +" Alr$DSysajO ", +" >jy#51:jO ", +" %Dy*gjO ", +" alla "}; diff --git a/tests/Modeller.xpm b/tests/Modeller.xpm new file mode 100644 index 0000000000..62e27f9853 --- /dev/null +++ b/tests/Modeller.xpm @@ -0,0 +1,117 @@ +/* XPM */ +static char * InterfaceModeller_app_2_Tile_xpm[] = { +"48 48 66 1", +" c None", +". c #86174D344103", +"X c #69A651445144", +"o c #8617410330C2", +"O c #69A6410338E3", +"+ c #30C218611861", +"@ c #AEBA6DB66185", +"# c #71C638E328A2", +"$ c #69A634D328A2", +"% c #30C228A228A2", +"& c #79E73CF330C2", +"* c #BEFB9E799E79", +"= c #8E3869A66185", +"- c #514424921861", +"; c #A699A289B6DA", +": c #A6999E79A699", +"> c #71C65D756185", +", c #9E799A69A699", +"< c #8E3882078E38", +"1 c #861779E78617", +"2 c #A6999A69AEBA", +"3 c #8E388A289658", +"4 c #71C675D679E7", +"5 c #96588A289E79", +"6 c #30C230C238E3", +"7 c #C71BC71BC71B", +"8 c #9E79A289AEBA", +"9 c #AEBAAAAABEFB", +"0 c #96589248A699", +"q c #A699AAAAB6DA", +"w c #AEBAAAAAB6DA", +"e c #D75CD34CD75C", +"r c #EFBEE79DEFBE", +"t c #BEFBB6DABEFB", +"y c #B6DABAEAC71B", +"u c #AEBAAEBAB6DA", +"i c #E79DDB6CDF7D", +"p c #96588E389658", +"a c #596559656185", +"s c #AEBA8E388E38", +"d c #CF3CCB2BCF3C", +"f c #9E799A699E79", +"g c #86177DF78E38", +"h c #69A6659571C6", +"j c #AEBAAEBABEFB", +"k c #96589E799E79", +"l c #B6DAA699A699", +"z c #E79DC71BC71B", +"x c #B6DAB6DAB6DA", +"c c #861786179658", +"v c #B6DAB2CABEFB", +"b c #BEFBAAAAAEBA", +"n c #C71BBEFBC71B", +"m c #514441034103", +"M c #41033CF34103", +"N c #492428A228A2", +"B c #AEBAA289B6DA", +"V c #618530C22081", +"C c #69A630C228A2", +"Z c #69A630C22081", +"A c #596528A22081", +"S c #492428A22081", +"D c #618528A22081", +"F c #596520811861", +"G c #69A628A22081", +"H c #FFFF14514103", +" .X ", +" .oO+ ", +" @.o#++ ", +" @.o$%+ ", +" @.&#++ ", +" @.o#++ ", +" @.o$++ ", +" @.&#++ ", +" .O#++ ", +" *=-$++ ", +" ;:>+++ ", +" ;,<1% ", +" 2,34 ", +" 2;,51 ", +" 2,,,,6 ", +" 7777 28888,6 ", +" 77777777 2829,,,06 ", +" 9qwwe7rrrrr77rr 828,9tyt,6 ", +" uuwriirrieiiieii77pa< 82,8,,,8,06 ", +" s=1ttiieeeeded77eufgh>j,8,8,k,0,6 ", +" =@lzieeeeee77eeex:fpcg4>9,,,,qjv6 ", +" =O=blt7eeee7deenw:ffp<gha:t979;06 ", +" =OO@=@zieeee7ex:::fffff0,v72444h6 ", +" =OOo&Osst7iee7wkf:f:ff;t721444ham ", +" =#&&&&OO@di7eu:ff:fferiv114444hmMX ", +" =O&&&..o.sdp33fff:errrii7cc1hhh6mmNX= ", +" =O&&&@.o.@sberrrrrriiuxuxnB;44aMmVCO#OX ", +" =O&&o@..o.zrrrie777nnxtuxx:x;n:>mV##&&O$mX ", +" =O&&o....zrrieieuxunx7txx:nnfwpMmVZ#$ZZZVVN ", +" =O&oooo.*rrde77ewxnxxtnw:f4M%M%+NA#$Z$ZZVmN> ", +" =Oo&ooo@iree7inxn7nnuuff4h%M>m%S-AZ$CCZDZmSX ", +" =O&o.o.@rrn7eulun7xxuwp4mm6ahM%--AZCCZDDDANX ", +" =Ooooo.*rixenuwwn7nxupph%M>>h6mAADVVZVVDDANX ", +" =O&o.o.zrexwwnwuxxnughX%mahhmMN-AZCCVVDDAAN> ", +" *XOoo.*iin7n777xxxtphaM+ama>MSNFVCZZVVDAAAS> ", +" 1O..izewxux7nuuux4%++%hha>%N-DDCZZVDAAAASX ", +" 1.=ituu:uButnxxuX%>hh>M%++NADZZZVDADAA--X ", +" :e7f::lnn7*ppnx6ahm6++mNN-ADCZVDDAAAA-SX ", +" 7nupp:wxxg%MMau6%++NmmmADADVVVVVDAA---NX ", +" 7uBgh1wwxg6h>m%:MmmVNAVDZVZCVZZDAAAAF-S+X ", +" nfgaM%pnwhX6%mXb6$DVVZC$C#C$ZZDVAAA---+NX ", +" 27a%MaM47:mN.OoolmODGZ####$$ZZVDDA-----SSX ", +" 2gmg<m6p7wmmOo...O$GZ####$$CZVVDAAA----++X ", +" qBcaM <gxgmXmo.@.o&$$##$$$CZZZDADA-A-++-NX ", +" M6> paMa HX.@@@oZ$###$$CZVDDAAAA---SS+X ", +" 43 p=&@@&&$##$CCCVVVAAA--+S+S+%X ", +" k =o@.##$VVmmmNNNSSSSSS%XXXX ", +" s>OSSNmN>>aaa177777 "}; diff --git a/tests/marble.xpm b/tests/marble.xpm new file mode 100644 index 0000000000..1ef2607610 --- /dev/null +++ b/tests/marble.xpm @@ -0,0 +1,408 @@ +/* XPM */ +static char *granite07[] = { +/* width height num_colors chars_per_pixel */ +" 384 384 16 1", +/* colors */ +". c #000000", +"# c #111111", +"a c #222222", +"b c #333333", +"c c #444444", +"d c #555555", +"e c #666666", +"f c #777777", +"g c #888888", +"h c #999999", +"i c #aaaaaa", +"j c #bbbbbb", +"k c #cccccc", +"l c #dddddd", +"m c #eeeeee", +"n c #ffffff", +/* pixels */ +"aacfedbbcbbaaaaaaaaabaabaaaaabcbcbbbabbchfdcccbbabbbaaabaabcbaa#aa#######a#aaaabcddeefhec##dgbabbaaadabbcfbaa##########aaabbaaa#a#####a#aa###a#aaabbbbcbbbccdedaaaaa#aaaaa#a#abaaabbabbbeddbbaaaaaca##a#aaaba########aaaadcababbabdehd.##.a######.cgdcb###b##.##.##aaaaa####abcba######a##aac#a##a####aa#aa##babbbcfccbbbcdccccecbbbcbbbcdccddcbcdfeecbhhjihhgffc.aaa####.#######aaaaaaaabbaaaaa", +"aaacedccbbcbaaaaaa#bbaabbbaaaabcaabbbbbbafhfccbbbbbbabacbacbaaaaa##########a###abbcdeghhhcagb#ababaaccbacdfca#a####aa###aaaaabaaa#####aca#aabaababbcccccccbcdfdaaaa###aaaaaaaaaaabbbbbbccccccbbcbcaaa##aaaaabaaaa###abdaccceebaaaabehja####a######..#aeec#bb##########aa#####abba#########aaca########aa#aa###aaaabddbbbbbbbbbbccbbabbbbabbabbabcbcbcefhfeddccefhhijheecb#...a####aaaaaaaabaaaaa", +"aaabccccccdbabcbaaa#aaaaaaaaaaabbabbbbbccabefdccabcbbabacccbaaabaa######a######aaabceiiiihije#bbabbaaeaabcedcaabaa########aaaabaa##a###ab#aabcababbccccccdeeeecc#a##a##aaaaaaaaaabbbbbbbcccbbbdcbbcdaa#a#aabbaaaaa###acbaa#bccaa#abcfig.#######.#######acddgefdda#######a########a#######aaaaaa#a######aaaa#####aaacdcbabbaaabbbcaaaaaaaaabbbaaabbaabbbcbcbabbabcdeefghjkjgc#..####aaaaaaaaaaaa#", +"#aaaaaacbccbcabbbaaaaaabcaaaaabbbbbbabbbcbaabffccbccbccbbcbaaaabaaaa#aa#aa##a#aaaaabbikkjhijicabbbcc#faaacdebcbda#########aaaaaaaaa####aa##cacccabcccdccccdddfdcbaa##a##abbbabccbbcbbbccccaaa#abbaaba#a##abbbbbaaaaaaaaaaccaaca##aabcfic.###aa#######a####bddeeddb####.##.###aaa#########aaaa###aa####aaaa#######aabdbbbbcabbbaaaa#aaaaaaaaabaaabbbaabbbbdbbaaabccccccdcefhhkhda##aaaa#a#aaaaa##", +"#aaabaabcecbaa##bcaaaaaaaababbabaaabbabbaabb#chhfdccccbcbecaaabaaaaaaaaaa####aaaaaaabdgjkkijijdabbdcabfaabcecbbec###########a#aaaabaa#######abbaaaadddedddeeefeccaa###a#aabcccdcbcbbbbccbbbbaaaaa#aabbaaaabbbbbbaaaaaaabbbbbaaa####acegha##a#aabbb####a##adccdedbcc#######.###a###a#######aaa#a#aa##..#aa#########abdbaabbabbbaa###aaaaaaaaaaaaacbaaababbdbabbabcbbcbcbccbbdegjkgb#aa#aa#aaaaaaa", +"##aa#aabccccaaaaaaaa#aaaaaabbaabbbaaaaabbbcbbcfhhgfcccbbbbccbaabbaaaaaaabaa#aaaabaaaabbcehkljjdabacccbgbaaccdb#adea#########aa#abaaaaa#####ac#ba##accdedddefffeaba##a#aaaaacccccccbbbcccaabaaaaaaaaa#aaaaabcbbaaa#bbbbaaefccdbaaa#aaacdei##aa##aabbbaaa#a#cdcccccbcea.#########bbaaa######a###a#aaaa.#aaba####.###abcbaaabaabbbaa###aaaaaaaaaaaabbaaaaaaaaaaababcbbcbbaabbbdddeghheba##ab#abaa##", +"#####bbaaaaabaaaaa##aa#adccaabaaabbbbabbabbbabccbccfdbccbbbbbcaabcaabaaabbaaaaaaaaaaaabbbcglli#accbbbddgabcddbbaacea#a##########aaa#aaa##aaaa####aabcddeeefffgdbbaaaa###baabbbbbbcdabdcbcaaabaaaaaaa#aaaaaabcbbbbadfbbbaejhhebbccaaaaaccfi.aba##abaaaba####ecbbccba#fc.####.##.bba#a#######aaaaaaaaaaa##aaaa######abcdaa#aaaabaaa###aaaaabaaabbbaaba##aaababcbbcbbbbbcbaaabbccccddgggeb#aadca###", +"#####bcaaaaaabcbaaa#aaaabcccaaaaaaabaaabbbbbbbaacbabeeddddccbcbbcccbabaaaabaabaaaaaaaaabbbbglmdbcbaabebdgdbcecbbaabdbaa#########aabbaaaa#aa#a##a#aabbdceeedccdcbbaaaaa##aaabbcbbbabaaabbababbaaaa#aaaaaaaabcdccbbbabcbbbcfijfbcdcabb#abcbif#abb##aaabaaaa##fcccbbcaa#db#..##.##.aaa#########ab#aaaaaa#aabaaaaa#####abdbbaaaabbaaaa###b#a#aaaabaaaaaaaaaaaaaabbabbbbaabbbaaaabbbbbbbceffecccbaa##", +"#####abaaaaa#accbbbbaaabaaaaaaaaaaadcbaabbabbbabbdcaacgfddddcdddcadfcaaaabcbbabaaaaaabcabbbdjliacbababcbdfcdeeaaaaaabba########a##aa#aabaa##a######abddeggca#bcbaaaaaa####aaaaaabbbbbcbbbbbaaa##a#aaaaaaaabcbccbbaaaabaabfgfiecccccbbaaaccicbbbcbaaabaaabb#ceccccdca##aacdb######aaa###a###aabaaaaaa#aabca#abba#####abca##aaaaaaaaa##a##aaaaaaabaaaaaaabaaaacbcbacdbaaabaaaaaabaaaaabbcddccbaa##", +"####aa#aaaaaaabccbabbaaaaaaaaaaaaabfaaabbcbbbbbabdebaabdffddedefedccecccdcbbbbbccbccbbbbbbccekldaabaaabccbfaaaaaaaaaaaba########aaaaaaaaba##aaa###aabbccfgfaababbbaaaaa#aabbaabaaccaabcccbcbaa##aaaaaabaabbbccbbbaabbbbbbdddghdbbbcccb#abcdebcccbaabbbabbcbaecddddbaa##.#acdeca#######a#aaaaaaaaaaaaaaabba##abba####aacba##aaaaaaaaaaaaa##aba#abaaaaaaabaaaabbbbbbcbabbaabbaaaaabaaaaaaaaccbaa##", +".####aa#aabaa##bccbaabbbba#aaaaabbaefdaabbbbccbbbaddaaabadeeffhhhffdedddeecbbbbcccbbabcbabbcfjjlkeaaaaacdadcaa#aaaaaaa#ab######ba#aaabbabcaa#aa###babcddcedba##acbaaaaaa#ababbbacbbbcccdfffbaa#aaaacbaabcbabccbbcbbbbbbcbbccedbbbccdccbaabcgb#bccbbbababbbcccdededcb#a####...addcba##aabbbbbbbbaaaaabba#aaa##abba####abbaa###a#aa#aa##aaa#a##abaaaaaaaaabababbcdbcb#baaaaaaaaaaaaaaaaaa#aaaaa###", +"######a##aaaaaa#accbaaabbbaaa#aaababdcaaabbbbcccbbbdbabbbacdccgecadbbbcdccddeddcccccbaabcbbcgjhhjgeb#aacdcccaa#aa#aaa#a#aaa##aaaaa#aaabbaabb#aa###aabccddeccbbbaabcbbbcbbb#aacbbadbabcccddbaaa#aaaaabbbbabbbbcdbbbabbcddcbbbccaabbbccbbaaaadi##abbbbbbbaabbbacdeedbd######aa####bceda#aabbabaaaaaaaaba#aaaaa#aabaaa###acaaaa####aa##aaaaaaaa#aaaaaaaaaaababaaaaabcaaaaaaabbcbaaaaaaaaa###aaaa###", +"##########aabaa#accbbabbbbbba##aaaabbcbbbbbbbbcbaaabdbbbbbbddccbbbbaaaabbabbbbcefefdcbaadbcddje#debgfbabecdc####aa##a###a#aa#aa##a##aaabbcabbaa###aabbcceedbcbaaaabdcccbabaaabbbbabbccbbaaaaaa#aaaaaaaabbbbbcbccabcccccdcccbbbbabbababbba#abfe#aaaaaaaabccbbaaaedddc######adcaaaa##dfcaaaaaaaaaa#aaaaa##aabcaaabbaa#aaab###aa###aaaaaaaaaaaa##aaaaaaaaaabaaabaaabcabaaaaaaabcbaabaaa##a###aa####", +"#########aaaaaaabbcbbbbabcbaacbaa##aaabaaabccccccbaabecabbbcddbacdeba#aaaaabaaabbdfgedcbaccdcgica#aadghdbddd#aa#aaa#a###aaaabaa#####aaaaabbbbbba#aaabccceecbddbaa#bbccabcbbbbbacccdbbdabbaaaaaaa#aaaa#aabbbbcccdcbcbbccccccbcaababbdbabbba#bbgaabaaa#aaacccdcddbeedba#a##a#aba#aaaa##decbaaba#aaa###a#a###abba#bba###aaba####a####aaaaaaaaaaaa#aaabbbaaabbaabbaabbaaa#aa#a#abbaabbbaaa#aaaa#####", +"############aaaaaaacbbbbbbbaa#aaa#a##aaaaaaaacbbbbbbabdcabbbcdbaccdba#aaaaaababbcbbdddedccddefihaa#aaahiiiffd#aaaa#abaa##aaaaacaa##a#bcaaaabbbcaaaabccdddecabaaaaacbbbabbccccccbbdbdfdaabbaaa###a#aaaaaaaabbbbbbbaaabdcddccbbbbabbbccaabbbaabfdaaabaa#aa##aabbbbbddba##aa#a#aa##aaaaaabcdbbaaa##aa#####a#aaabbaaaaa##abb######aa###aaaaaaaaaaaaaaaaabaaaaaaaabbbbaaabaaa#aaaaaaabbbaaaaaaaaa####", +"###########aa#aa#aaaccabbaaaaaaabb#######a#aaabcbbbabbaeebbccbcbacdaaa##a#aabbbbccbbcbcdegifdfgifba##aaaagigha#aaaaabbaaaaaaaaabaaa##acaaaaabbbbbbabcdddefeba####abbaabccccbbbcbadcbcbaabba#aaaa#aaaaaababacccbaadbabbccedcccbbccbbabaaaaa##ade###abba#aa##abbba#cebb.#a####.#a#aaaaaaaaacfca#aaa###aa###abaabaaaaaaaabbaa#######aaaaa#aa#aaaaaaaaaaababdaaabbbbbababaaaaaa#aaaaaabbaaabaaaaa###", +"##########a#aaabaaaaccaaaaaaabaaaaaaba###a##abaaabbababaccbcbbcccaaba#a###aaabbccdccccccdeegggfigaabb#aaa#fffcba#abbaaaaaaaaaaa#abba##aaa##aabbbcbbbbcdeegfeb####aabaabacbbbcbccaabbabaaaaaaa##aa#aaaaababbabbcbcdbbcccbddcdcccabcbbababba###afba#aabba#acaaabbbbaddb##aa####.####aabbaaaabffcaaaaaa##a##bcabbaaaaaaabbbc#a#a#######aaaaa#####a##ababbbbbaaaabbcbaaaaaaaaaaa#aaaaaabaaababaaaaa#", +"#######a#####a#aaaaabcbaaaaaa#aabaaaaaa###abbabaaaaaccaaabdbccbccbaaca#####accddcccccccddeeefikjeabcca#a#abfifbaa#abbbbbaaaaaaaaa#bbba#bcaaaaaaaccbcccceffeccaa##aaabbbcabbacbddbbaabdbaaaaaaaaaaaaaaabbbaabbbbbbbbbcbbccccdcdcccabbbbbaaba###dcaaaabbaaabaabcbccaadba#aaa########aaaa##aaaacgdbaaaa####cfffda#a#aaaabbdbaa#aaa########aaaa#aa##aaabbabbbaaabbbaaaaaabaaaaaaaa#aaaaabaaaaaaaaa#a", +"a###########aaaaaaaabbaabaaa###abaaa#a##a###a#aaaaabacaaabccbbbcbbbcbb####a#bdfbbccccccdefecdgiiddaabbaaaabacfeaaaaaabcccbaaaaaaabaaacaa##aaaaaaabccddcfgfgbabaaa#aaabbcccbccbcddbbacabbbbbbbbaaacbaaaabcbabbbbbcbbcbccbccdccdccdcbaabbbaabaaade#aa#baaabaa##abbcbacdb#.#abbccc#.##aaa####aa#aeeaaaaaaabbabddfgfba#aabcd#aaaa########aa##a##aaaaaababbaabbbbbabccbababaaaaaaa##a#aaaabbaaaaaaaa#", +"#a###a######aaaaaaaacdaaaaaaaa#aaaaaaaaaa#####a###abbbbaaaaccbbbcbbbbaa#aaaaaeecabcccbccdedcdfgigeaaaacbaaabaacbaaaaaaabcbbbaaaaaaaaabccaaaaaaaaaacccceffffbabb#a####aaaabcccccddcdedbbbbaabcabbbccbccbcbcbbbbbbbbbcecbccccceccccdccbbaaaaaaabce#bbaaa###aaa##ababcacda#abb##a#######a#########bfdca#abcbaabaabcffddbabdc#aaaaa##########aa####aaaaaaabbabbbbbbbcbbbcbaaaaaaaa#aa#aaaaaabaa##b##", +"##a#########aabaaaabcdbabaaaaa##aaaaabaaba######a##ababbbbbabbbbcbcdddbbaa#abceecabccccccdddfedgjgdbaaabaaabbbaaba#aabaabaccaaaaaaaabbccbbbaaabaaabcddefgfebbbb#aa####aaaabbcccccbbfeccbbbaaababbbbbbbccba#abbbabbcdccdcbddcddcccdcddcbaaaaaabcfbadaa#######a#abbacbbcc###a#a########a######a##aabdcabccbbababaaaacdfededbbaa#aa##aa######ba#aa#aaabbabaababcbbcbcbbbabbaaaaaaaa##aaabaaacba#a##", +"##########a#abaaaaabbbcbbbcaa###a#aaaaa##aba#######aaaaaabbdccbaabccdddecaaaabccdbbacccddcdefdfgiifcba#bbaaabbaaaababbbbbbbabbaabaaaacbbbcbbaaaaaaaceeeefffbaaaa###a##aaaabbcbbbddcddddcbcbbaaabbbbababbabaaabababbbbcccdccddcddccccdecaaaa#abccfbbaaa#######aabbaacabe###a#aa#a#a##.aa#######a#aa#cfeecdcccccabbbabacggcabbaaabbaaaa####aabb#aaaabbababbbbbbcccbbbbbcccbbbaaaa#aaaaaababbaaaa##", +"######a####abcbaaaaabbccbcbaa###a##aaa##a###aa######aaaaaabdgebaaabbbccacbaaaaabbbaaabccddcdeeffgigbaaaaaabaabcaaababbbbaabbacbaaabbaaaababccbabbabbdffefhdcaaa###aaabba#aababcbdeeccceccccbababbbbabbabbaaaaaabbaabbcbcccccdcddddccccdcaaaababcdeaba#####.###aaabaab#b####a####a##aa#b########aaaaabedddcccccaaaabbcabeaaaabbccbaaa#abbaaabbbaaaabbbaaacbcbcbbdccbaabbacbbbbbaaaaaaaaabbaa#####", +"######aaa#abbcbaaaaabdccbbaaa#######aaa#####aaa##a#a##aaaababcbbaaaaabdebbbaaa##aaaaaaaabccddeefggieaaaaaaaacabaabbbabbbbaaaabbaaaaaaabbbabbccbaabbbdfgghebbbaa#####abba#aabbbcbccdcbbbcddcccbbbabbabbbabbabaaaaaaacbbabcbbccccddddccbcccaaaaaabbdcbc##########aaacbbaa####a####aa###a#aa###aaa###abbceddedcccbaaaacccdca##a#abbbabaaaabaaabbba#aabbbbbbccbbbbaaacccbbcbbaaabbbbbbabaaabaaaa####", +"#######aa#aaccabbabaabdecbb#a########aaaa####aaa#aba##a#aaaaaaabbdcaabdcbcaacb####abb#abaabccdeffghfdabaaaa#acbbbbcbabcabcbaaaabbbabaaaabbbbbcccbbbccdfedccbbb#########aaaababbacccbcbbbddbdcccccbbbbaaaabbaabbaaaaabaabbbbccdcceedccccacbaaaabbbbddb####aa######aabbaa####a####aa#aa###a#####aa#aabbddeccddccbbbabbbbceb###aa#aaaaaa##aa####aaaa#abbbbbccacccbaa#accbbbbbaaababbabaaaaaaaaa####", +"##a#####aaaaaabbbbabacdddccaa########aa#a#####aaa#aa#aaaaaaaaaaaabcabbcbbbbababa###baaaaaaabccdeeehifbabaaa###abbcbbcaccbcbbbaabbbbabaaabbbbbbbbcccccddbccbbbbba#######aaabbbaabbcccbdcbbdbbddcdcccbabaabaaaaaaaaaaaaaaaabbcccddecccbbacccbbbaabbbceca############aaaaa#############a#############aaaaabccddcbbbabbbbbbba#####a##a####aaa#######aaa#babaabbcbaaa##abbbaabbcbbbbaaaaaaaabbaaa####", +"#########abaaabbabbbbbddeccca##aa######a#aa####bbaaaaaaaaaaaaaaaaaabccbcccebacfdb#####aaaaaaabcdddcfgfccbaa##a##abcbbcbbdcccccabbabaababbbbbbbbbbcdccddbabbbbbba########aaababbbacdccccaabcbbcabddddbbaaabbabbbaaaaaaaaabbbddcddecbccbbbdcbabbbaabbcda#############abaaaa############a####bb##a####aaaaabcffdcccbbbbbbbb#######aaa###aaaa#######aabaaaabbcbaaaaaaaa#aaaaaabbccbbaaaaaabbbaaa####", +"#########aaabbabcbbbbbdddcbaaaaa###############aabaaaa#aaaaaaaaaaabbabbdefffccbba###aa##aaaaaabcdceecggdcbbaa##aa#aacbb#bcdddddabbbbbabbbabbbbbbbccfeedbbbbbbcbba#a#####a#acababbbdcbcbabbabaabaabeedcaaaaaaaabcbbaaaaaaabbcdfdddccbbbbcbccbabbbaaabcda########a#aaaaaaa#aa#####aaabaaaaaaacb##aaa#aaababbcdefddbbcbccbaa#####aaaaaaaab##a########aa#abbcccbaaaaaa###aaaaabaabccbbbaaaaaaaaa####", +"########aaaaaaabbbbbbcdedbbbbabaa##########aa###bbb###a##aaaaaaabbaabbbdfeedb##a#a##aa###aaabbbbccdefbfecbbbaaa####a#adb#acdecdfcbaabcbbbbcbbbbbbcdeffbcccabbcdbbba#a###a#aabaaaaaccccbaaaaabbbbaabdfedaaaababbbbbaaaaaaababbcedcccbbbbaccccbaaaccbbabeb######aaaaa#aaa###a######aaaaaaabacbca#aaaaaabbbbccdegfeccccccbcbaaa#####aaaa#aaaaa###a###aaaabbbcccb##a#aaa#aaaaaaaabbdeddcbabaaaaa####", +"#########a#aabbbbbbbbdddccbbba#aaaa##aa##a####a#bba#a#a#aaaabaabbbabbeedeeefdaaaa#####bb##aaabbabcddehgifffdcbaaaa#aa#aaaaaccdeddcabbbcbbbccbabbccdceeecdcaaaabbcccaaaaaaaaaaaaaabacdddbaabaabbbbcccccfdbaabbaabbcaaaaaaababbcccccbbbbbbbccbcca#acbbbbbda#####aaaa####ab##a######aaaaaaabaccbaaaaabbbbbbccceffcdeedcbbbbaaaa#aaaaaaaaa#aaabaaaaaa##aaaabbbcbbcbaa#####aaaaaabbbcccddcbbaaaaa####", +"##########a#aabbcbcbbcecccbbbabaaaaaa#####a#aaaabbaa##ba#acaaababbbbbbbcdcfgdbbbaa####aba##aaaabbbccdfefhfgedecaaa##abaaaaacbabebbbbbbbbcccbcbbbbddbedbddcaaaaaabdccaaba#aaaaaa#bbbbbaddccaaabcbbdcbbcbddabbbbbbbccaaaaaaaaabcddcbbbbbbbbbbbbbbaaaabbaabe#########a####bb#aa#####aa#aaaabccdbbbbabbcbbbccccdccbaaeffdbca#aaaa#aaaaaaa#aaaaabaaaa#aaaabaabbccbbcceb#bcaaaaaaaabbbbcdcbbbaaaaa####", +"#######aa#aaaaabbccbbcdccddcabaaaaaaaaa###aaa#aabcaaa#bba#aabaabbbbbbabcccdfedcaa##aaa######aaaabbbbcdddghhgfedcbaaaa#aaaaabcbbbccbbbbbbbcbccdcccccbeebccbbbaaaaaccccccba#aaaaaaabaaabbbddbbbbcccbcccbaceeacbbbcbccbaaabbabbbbceccbbbbbabbbbbbbab#aabbbbcc#.######a####.bcbcba####aaaa#bedccbbbbbbbaabccddedaaaaa##beeda#aaaaaaaaaaaaaaaaaaaaabba##babbabbbbcbbbccccbbaaaaabbabaabddcbbbaaaa####", +"##########aaaabbbbccccbcddddbaaaa##a#a#a###aaaa#baabbaaaaaaaabbbabcbaabccbddfebaaba#ba######aaaabbbbbcddfiiigggedbaaaaaaaaaabcbabccbbbbbbbcccddddccceecccccbbaaaabccddbbba#aaaaaaaaabcbbbcccdccbcbabcbabceecbabbbbbbaaaabaabbbcddbbbbbbbbaabbbcbbbbaaabcbdc########..####ccccba#abbaaaabddbabbbcabbbbcccceeca###aaa##aaa##a#aaaaaaaaaaaaaaaaaaaaa##aabcbbbbbbbccbbbbcddaaaaacbaaaabddbbaaaaaa###", +"############aaabbabcddccdbcdcbcbbbaaaaa##a##aaaa##abaaabaaaaaaabbaacaabddabcefc#aabaaa###a####aaabbbbbbddgihhfffgeaaaaaaaaaaaaabbbcbbbbbbbbbcddeeedceccdcccccaaaaabcbddbaa#a#ab#aaacbbbbbbddebbbbccbbbabbbedbaaaaaaaaaaaabbabbccecbbbbccbbbbaabbbbcc#aaabbcc######a#####.bccabbacbababaabdcabbbabbabbbcbdecabaa##aaaa####aaaaba##aaaaabaaababa##aa#aaabbbbbbbbcbbbbacbedbaaa#bbaaaabcbbbbaaaa#aa", +"#######a####aaaaabaabbcccbabbbbbbbcbaaa######a#aa######aaaa#aaa#acbbbabeeebabddbaaabaa####aa#a#aababbbbbcehhgeeffdca##aaaaaaaaaabbbbabbbbbbcdcdddfgfhcbbcbbbcbaaaaabcccdbba###baaaabcbbaabcdeecaaabbbbbbaabddecaaaaaaaabbbbbbbccfcbcbbbbbbbaaaaabbbcca#aabacc#######a####acdcbbbbbbaaaabbccaabbbbbbbabbceecabb#aa#aaaa#######aaa##aaaaaaabbaaaaaaaaaaaabbbaabccbbcbaaacgdaaaa#aababbbabbbbaaaaa#", +"###a#####a#aaaaaabcbacbbddcaaabbbbbbbaaaaaa##a#####a####aaaaa#aaabdbcbbedefcaaabaaaaabaaa#a##abaaaaababbbcfgggfeefea##aaaaaaaaaaabcbbbbbbbbcdcdddefgeabbbbaabccaabaaceddeeaaa##aaaaaabbbabbcdedbabbbaaaaaaaacfecaaaaabaabbbbbbcdfdbccbbbbbaaaaaabbbcdbaa#aabdb#########a#acdcccbaaab#aabccbbbbbbabbbceedccbcbbaaaa#baa#a###a#a##aa###aaaabaaaaaaaa##aaaabbaaabcbbbbbabbdfeaaaa#ababbcbbaabaaaaaa", +"#####a#####aaaaaabbbbbbbcddcbabccaaabbaaaaa#a##a##a######aaaaaabaaaaacbbbffeaaaababbabbbbbaa##bbaaaabbbbcccghghgeffbaaabbaaaaaabbabccbbbbbbcdddefggecccbabaaabbbacbabbdddecbaa####aabaababbcccdcabaa#aaa###abceedcaaaaabbbbccddefdccdccbcbbaaaaabbccdccdb#abbd###a#####a#a#cddcccaaaaaaaaabccbbbbdeefbba##aabaaa#aaaaaa#aa###aaa##a####aaaaaaaaaaaa##aaaabacbabbbbbcbbbbcfgbaaa#aa#abbab#aaaabba", +"##########abaaabbbbbcbcdcccdcbbbcbbbbbba#aaaaa#a############aa#aaaaaaababbdeaaaacbbbbbddcbaaa##abaaaabbbbcccghhhedecababcbaaaaaababcbbbbbccbddceggffecccbbbaaabca#aaaadddedcb#a##aaaabbbabbbbcccdd###aaaa#aa##bcefeddcddccefdddfdcccccccccbbaaaaaabccccdddaabbda########ab##bbbddcbbaa#aaaabcbbbcdddccaaaaa#abaaaaaaaaaa#aa#aaaabaa#####aaaaaaaa#######aabaacbabbbbbbcbbbbdfbbaaaa###baabaabaaba", +"###########aaaabbcbbbcccbddbcdccbbbbcabbaaaaaaaaa###a##aa###aaaabaaababbccbbdb#abccabddbbbba#aaaabdbbaabbbbcdehihbaabbbbcdcbbbbaababbedcbbaccdddeeefedabbabaaa#aaa#aa#beeeeffca###aaabbbcbbbbbbcced#a###a##aaa#abffgfedcccfhcbdebcbccdccccbbaaaaaabbcccccddbaabdcb#.#aa#aaa##abdddcbbbaaababbbbbcbdbabbbbbb##ababbbaaaaa#aa#aa##aaa######ababaaa#####a#aabcbbbabbbbbbcccbbbeabcbba###aaaaaaaaaab", +"b#########aaaaababbbbabbbbdebcccccbbbabaaaaaaaaaaaa########aa#abbaaabbabbdbcbbbaaadcbcbdbabba##aa##abcb#aaabcdcfhgdabbbccdcbcbbbbbbabcgdcbdbbdedeeehfgdbbbbbaaaa#aaa#abddddgeedcaaaaaabbbdccccccbceeaa###a###aaaacfghhgedccggefbccccccccccbbbbbbaabbcccccccdaabaaccb#aaa###a##adedccbcbaaabbbbcbbcddbaaabbbbaadbbaabbaaa##abaaa#aaaaaaaa#aaabaa########abbadccaaabbbcccccbbdcbcbbba###aaaaaaaabb", +"aa##########aaabbbbbbbaabbaccbceeebbaabbaabaaabbbbaaa###aaaba#aabaaaaababbccggcbaabccbbbccbca##aaaabdbbabbabbcdddghbabbccddcbbbcbbbbbccgfcbccceddddeddedddcbababaaaaaa#accdeffedbaaaaaaaacccccbbbccffb#a#####aaaaabfhgghhhhgghecbccbccccccccbbbbaaabbbbcbbbcdcbbabbcb#####abca#abccccccabbbbbbbbbdddbaaaaabab#cdba#aabaaaaaaaa#aaa#a#aa#####aaaa#######aabbbbccbbbabbdeddcbbeaabbcb###aaaaaaaaab", +"baaa######a#aaabaabdbbcbabbaccccedaaaaaaaaaaaaaaadbaa#aaaa##aaaaaaaaabbbcbcccdbaaaaabdcbacbcdcaaaaaaaabaaccbbccdddhgcabcccdecbcbbcbbabadedbbcdedcddeeccdddeeedcbbcbaabbbabbcddddec#aaaaaabbcccccbccdffc##a##a#aaaaaafheffhgeccefcbbcbcccccccbbbbaaabbbbccbbddedbabbcc.##a##abc###cdcccbcbbbabbbaddccababbbaaabaddba##aaaaaa#aaa#a#aaaaa##aa##aaaa#######abbbbccbcbbbbdefeeccecaaaaa####aabaaaaaa", +"bb#a########aabbbaaababcccdaacdbbaba#aaaaaa#aaa##acaa###aa#aaaaaaaaaaabcdcccaaaaaaaaadbcbbbbacc###aaaaaaaacbbccdcdfggbbbcccdecccddcbbbacdfdbcdebbbcccdcccccdcbefccbaaaaabcbbccabdfcaaaaaaabbdddccccccefe##a##aaaaaaaadfghhhdbbcccccbcbbccdccbbbcaaaabbbbdccddeeba#bbda######.acabbddccabcbbbbbbbddccaaaaaaaaaaabdca#a#aaa#aaaaa##a#aaaaa##aa##aaa#a##a##abbbbccbbdbbccefffeccd#a########abaaaaaa", +"aa##########aaaaabaabbaaccdcaacbbaab####aaaa#aaaaaa#a####abaaaaaaabcaaabddcacda#aaabacbbbbddddcbaaa##aaaaa#abbdcccdegfbbcdcdefccddccccbcbbfdccecabccbcbbbcdddcbffdcccb#aacbaabcbbeecaa#aaaabcedddccccddfeb#####aaaaaabbehhfcccbcccccbbccccccbcbcbbaaabbbcdcceddcbbabba########bcbbcdcbbbbbbbbaacccccaaaaaaaaaaaabcba####aba##aaaaaa#aaaaaa##a#aaaaaaa#aaabaabbcbbbbbbbdffffeeeaa########aabcaaaa", +"aba#a#aa####aaaaabbabbabbaccaaabaaaa#######a####aaaaa####aaa#bbaaaabaaacbddcbccaaaaaaaaaaacdeabcbba#a###a#aaabccccdeegfcbcdddeedcdccddccccfedddcbbccbbbbbbccddedecccdca#aaaaaaabacedcddcbabaabccccccccceccd####aaaaaabaacdghhfecccccbbccccccccbcbbbaabbbcccccddcddceaca########cdccdccbbbbbbbbbccbcdcaaaaaaaaaaaaaaba#####aaaaaaa###aaaaa##a####aaaa###aabbbbbbccbdbbbcdefffgaa#a#######aabaaaaa", +"aa#####aa###aaababbccccbbbbcbaaababa#######a#aabaaaaaa####aa#abbaaaabbaabbdcbbcdbbbbaaaaaabcddbcbba#####a#aaabcdccceefhgbbdcceeeeccccccddeefeeecccacccbcbabbccdefdbcebaaaabaababbbcdcdfffdabbbbbcccccccecade#aa#aabaaaabaackijkidbbbcbccccccccbcbbbbaabbccccccccddegfdaa#######ceedcbbcaacccccbcccccbaaaaaaaaaabaaaaaaaaa####aaa.baa######aaaa####baaa#aaaabbbbbccdcbbcddedfgfb##########abbaaa#", +"#a########aaaaaaccbbcdcccbbbba#aaaaaa#####aa#aaab#aaaa#.###aa#aabababcbabaccbccdedaaaa#aaaaabccacbaa#a######aacbcccdffhigeccccdeedddccbcddffdefcbabbbcdecbabbbbcddecddbbaaabbabbbcccddeeffabbabbbbcccccdecdedb#a#aaabbaaaaahifgikfcbcccccccccccbbaaabbcbbbccbbbbcccdhea#a#####aedfebccccbbcbcccccccbaaaaaabaa#aaaaaaaaaba#b###aaa#b#######a####aa##abbbabaaabbbbbcdecbbcdedefghc#########abcedcb", +"a############a#abcbbbcddccbbbcaaaaaa#a####a#a###ba#aa#######aaba#bbbbbccaabcccddeebaaaa##aaaabaaabaaaa#####a#aaaabcbdeggihfccccdddffdcbcccdfcbcbbbbbbccbbbbabaabcdfebcbbca##aabbbbcdcdfffeeaabbbccbbcccdeeddeed##aaabaaaaachgcccfijebbcccccccccbbaaaaabbbaabbaabbcbbcfecaaa#aaadcddbbdcccabbcccbbbabbaaaa#aaa###aaaaaaaaaaaaa##aaaaba######a######a#abbbbbbabbcbbbddcabcddddefgfa########aacedcc", +"#######aaa#####aaaccccddcdcccbbaaaaa####a####a#aaaa#aa#######abaaabbccacdaadccdddccba#aa#bbaaabaaabaaaaaa#aaaaaababbbdeffiiebcccdddeedcccdcfbcbbbbaabcbbbbbbaaaabcdeefeeddedbaaabcbdccefffffabbbbbbbbbcdcdddddefbaabbbbabaeidccddcejgbbccccccccbbbbaaabaaaaabaaabccccdffebaabbaaddcc#cdccabcccccbbbbbaaaaa#aaaa##aa#aaaaaaaaabaaaba#b##a####a#a#a##a#aabbabbaabbbbddecbbdcccddeega.##.#a##aab###", +"#########a#####ababccbbbdcccccabbb##aaaaaa#aaaaa##aaaaaa#..###aaaaaaccbbdcbbccdbccdaa##a#a#aaaaaa#ba###a#a#aaaaaaabbbcdeefhgeccedbbcdedeedgebbbbbbbbcdcbbbaabaaabacccddccccbdcaabbadddeefffgfbabbbbccccccccdddbggbaabbbbabhefcccddddihdccccccccbbbababaaa###aa#aabbbcdeeffa.##abcfedabccbcccabcbbbbbbabaaaaa###aaaaaaaabaaaaaaaaaaaaba#######aaab#####aaabaaaabbbaceffecbccddccdec#####.##aa#aa#", +"#aa########a####abbccbbccdcccbbbbba#a##aaaaabaa#aa####aaba#.##baaaabccdabdbabbbbbcccbaa####aaaaaaa#aaaa######aaaabbabccdfeehihfggfdbceedddeddfdccbbcbbbbbbbbbbaaabaccccbbccdddecababedefffffhgdaaabccbcccccdddbfhfbbbcbbackdeeccdddccfhgbccccbbbaabaaabba#####a#aabbbdeddeda.###aeddcbaaccccccccbbbbbabaaaaaaaaaa##aba##abbaaaaaaaaaab######aa##aa###aaabbbaaaaabbbeffffdcdcdeffda######.###aaa#", +"#aaa############aabcdcbcdcfedeecbbaba##aaaaabaa###b#a##aaaa####abaaacdcaacdaacbcaaaaaaaabc##aaaabaaaaaa######aaaaabbbdddeddfhhhhhhfcccffffdbaabcbdbabbbbbbbbbbaaaaabbcccbbbbcfdedbbadeddeefdefhffecbbcbcccccceddgibbbbbbdecccbbccccddddhidccccbbaacaaabba########aabccedddeda####cdcecbccccddddcbbbbbabbaaa#a#####a#######abaaaaaaa#aaaa#a##aaaa#a####aabaaaaaaaaabccddfgfddefge################", +"##aaaaa#aa######aaabdccbccdeefebbaccb###aaabcbaa########aa######aaba#bdbbbcabbbbbbaaba##aba#####ababaaa##a#a##aaaabbcddedddeeefhghfddccdhecbbbaaaababbbabbabcbaaaaaabbccbbbbbbeefdbbbddbddffdggihiebbbcbbcccccedeicbcbbcdccccccccddddddcfifccbbbbabbabbbaaa####aa#aabcedddefeb##.bdcdeccbcccdddcbabbbbaaaaaa#aa############abaa#aaaaa#aaaaaaaaaa#######aabaaaaaaaabbabbcefgecbcc############a#a#", +"##aaaa####aa##a##aaabcdcbbccdcdccbcaba##aaaabbbaa#aa#a####a######aabaaabaaaaaaaabbba#aa###a##a###abbbaa#aaaa#a##aabbcededddddeghggcdfedffddcbbbaaabbbbbccabbbbbcaaaaabccbbbbbbeccefdbcdbcbcefefhgghdbbcbcccccccdcefedbadccbbcccccddddddddeggcbbbaacaabbbaaa######aaaabdcdeedefbaa#deddcdcbbcdedccbbbcbaaaaaa##################aaaaa#aa##abaaaa#aaa#aa##aaaaaaaaaabaabbacdbacbaaba###############", +"##a#aaa####aa##a##aaabbbbbcdeccbbaaaaabbaaabbaabaa###aaaa#########aaab#aaaaaaaaabbaaaa#a#a#aa#a#aabaaaa###abb##aaaaabcdeeddefghhhebbbfebbdddccbbbbbaaabdcbcbcbacbaaabbabcbbcccddbbcefecdcbbbcddehgggcbbcbcccccccdddffbbdbbbbbccccddddddddddegcbbaabaaabbbaaa######aaabbbcdefdeca#ddedcdddbacadedccbbbbbabaaaa###############.####aaa##a###a##aaa#aaa#abaabaaaaaaaaaaaaabcdbaaaa#a########a##a###", +"a##a#aaaa#####aaaaaaabcccbbcdebbaaba#a#bbaaabbaaaa####aaa#####aa#abaaaaaaaabaaaaaabbbaaaaaa#aaaaaababaaa####aaaaaaaabcddddefedhhgbbbbcefbcdedcedabbbababbbcbbbbbbaaabbaabbbbbcbcddbbbcdcebbbbdcabehhebbbbcccccccceddhfddbbbbbccccddddddddddcdfdaaaaaababbaaaaaaaaaaabbbbccddcdfededffddddcbcabcddccbbcbbaaaaa#####################aa##a#a#######aa###aaaaaa###aaaaaaaaaabbccaabaaaa######a######", +"aaaabaa##aa####aaaaaabbccccbcccaabbba#a##aaaabbb######aaaaba##aaaaababb##aaaaaa#aabaaaa#aaa#aabaaaaaacbaa####aaaaaaabcdeddefefhheabbbbbdfgfgedcfaaabbbbbbaaaaaacabaa#baaabbabaabbdeeeccabdccbbbcaachifbbbcccccbcccddejkeabbbbccccddddddddddccceebabbaabaaaaaaa#aaaabbbcbbcccddefgedfedddcccbaabcdcccbcbcaabaaaa########.##.########aa###a########aaaaa#a###a###aaaaaaaaababccaabaa#########aa#a#", +"##aaaacb########aaaaabbbbcccbdcddbbcbc#aaaca##a#aba######abca#aaaa#aa###aa###aaaaaabbaaa#a###aaaaaaa##bcbba###a#aaaabbceedddehgfdaaabaccbfhiihffcaaaaccbaaaaaaacabaaabbaabcbbbbbbbcbdeffedfdb#acaabafjgbbcbcccbccccdefiicbbbbacccddddddddccccbbcfbbbbbabaaaaaaaaaabbbcbbbbccccdegfecfdbaabdabbbbcccdcccbbbbaaaa###################a#aa##a#a##a####a#aaaaa###########aaaaaabbbbbaabaa#######aa###", +"###aaacba#######abaabbdcbbcdcbbefcbabcbbaaaaa####aa#a#a#a#a##aaab###a#aa####abb#a#aacbaa####aaaaaaa#aaabdcbaaaaaaaaabaceefeeffffbaaabbabccehigfeeddefdbabaaaaabbbabaabaaaaabbbbbbabccbabdedda##aaabbachhbbcbccccbbcccdeghebbbaccddddddddddccccbacecbabaaaaaa#aaaaabbbccbbbbcccdcdgfdfebbbbbcccbcbcddccccccbbaaaaa################aabbaaaa####aa###a##aba#############aaaaabbbddbbaba##########.#", +"####aaaba#######aaaaabdfdbbcccbbdebbaaaab#aaa#a###aa###aaa###aba#####aaa#####aba#aaa#baaa#####aaaaa###aabcccaabbbbbcbbbdfffgeccebaaabbbbcbbeffedccfghhebaaaaaabbaaaaaaaabaabbabbbbbacbbbbcbdda####abbabghabbbccccbbccddddghdaabcddddeedddddcccbbabdfdaaaaa##aaaaaabccccccbbccddcbefdffdcbbbcdccbbccddcccccbbbaaaa################bbccbaabaa#aaaaaa#aabba##a#########a#aaaaabbccbcabaa###########", +"#####aaaba#######aaacccefcccbcdccbcbbaaaaa#abcba#########aaaaaaa######aaaa####aa##aaa#aaaaaaa##aaaaa##aaaccddcccdddddcceeffdccdccbaaaaabbbbcfggdddfffggfebaaaaaaaaaabaaabccbbbbbbbabccbbbbbcbdb###aabbbbghbacccccccccccdddfigdbcddddddeddddcccbbbabbfeabaa#####aaaabcccccbcbdddecegfffcccabbccccbbccdcccccbbbbaaaa############a#aaaababaaaaaaa#aaa##aaaa#aaa##########aaaaaabbcccbbdba#########.", +"#####aaaaa######aaabddefcccbabdccccbaaaaaa###aaa######aaabaabbba#######aaaa####a###aaaaaa#a##a#aaaaaaaaaabcddddcdeeedefgfefecdaabbaaaaabbbbbadfebcfdfgffeeecaaaaaaabaaacabdbaaabbbcdcbbbbbbbbccb#a###abbaegcabccccdcccccdddcfihfdccdddddddddcccbaaaaaddbaa######aaabccccbcbccdddhfcfgecccbbbbcbccbccbccbcccbbbbaaaa#a##########aaaaaabccbcba#aa#aa#aaaaa#aaaaa###########aaaabbaddedaa##a#.#####", +"####aaaaaa#######cffdabcbcdcbbadfbcbbaa###a#aaa#aaaaaaabaaaababaa#######a##a#########aaa##aa##aa#aaaaaaaaabdeddccddddddffeeeec#a#aaabbbaaabbbcggdcfeeeeegfdccbabccbbaaabbbcaaaaabbbcdbbbbccbbbdbaaa###abbccebabbccccbcccccddcdfhjhedddddddddccbbaaaaaabdda#######aaabbddccbbdddedccdgeeedccbbccdccbccbcbccccbbbaaaaa#########.##aaabbaabbbcbaaa###aaaaaaa#a#a#a########aaaaabbaccddeb###########", +"########aaa######acddbabcbbcccabcddcaabbaaa##aaaaaabbbcaaaabbaaaaaba########aaa#aa###aaa###aa##abaaaaaacbbbcdffeddeccdffffeddbaaaa#abbaaaabaabegebdfeddeffeddddcdddcabbacbcbccbaabbacccbcdbbbcdb#aa##aabbbbbffbbccccbccccccdddedfkkidddddddcccbbaaaaabbabdb#a#####abcccdbccccddfcccdfgeedccbbbcbccccbbabbcccbbbbbbaaa############a#a#aaaacacbaaa####aaa#aa###a##a######aaabaabbbbbbdfa##########", +"#################abbcbaacccccbccaacbcaaaaaaaaaaaaaaabccabbbbaaab##bb######a#aba##aa##aaaaa##a#a#acabbbacdcbcddffffdgeefefeddcb#a##aaaaabaaaaaaddfdcfdccccccdcbcbcccecbbabccdddddcbbbbccccccbbbceb#aa###aaaabbfgbacccbcccdcdddeedgjkihccddcccccbbaaaabaabaadca####aabbcccbcddccefdcdeeeedddcacbccccccbabaaabbbbbbbaaaa###########.#####aaaabacbba##aaaaaaa####a####a######abbabbcbcbcdb###a##.##.", +"###########aa#####bdbaaaaccddbbdcba#bbaa##aa#aaaabbbbbbaaabaaaaba##aa.####aaa##a#aaaaaabbbaa#####abaabbbbbccdddeefeffddefdccaa####aaaaaaaaaabaeefdedeccbabbbdddbbccccabbbbbbbbcdcccbcccccccccbaaaa#a####aaaabacgcabbcccdddefffedgijfehdcccccccbbbaa#aaaaaaabcbaaaaaabbccdcdddefgecddeefedccbbbabccbbbbaaaaaabbbbaaaaaa################aaabcbabbaa#aaaaa#aaa###a####a####aaabaabcbbbcbba###aa####", +"############a#####abaaaaaabddccbcdddbaaaa###aaaabaaabbbaaaabbabba###b######aa######a##aacbcbba##a##babbccccdddddeeefgfeedccdb####a#aaaaaaaaaaadefedecbabbbbbcddddbcddcaabaaaaaabbbbbaabbccdcccbbbcb#a##aa#aaabbbfdbbccddddeffffefggeedjhedcdcccbbaaaaaaaaaaabbcaaaaabbcdcccdeefgdcccdefeccbbbbbbbccbbbbaaaaaaabbbaaaaa#######aa######aaabbbcab#a#aaaaaaaa#a##a#####abaaa#abaabbbbbbdccc####aa#.#", +"###aaa###a#a#a####aabaaaaaabdbbbcecdcbaaaaaaaa#aaaaaaaaaaaaabccbb###a########a#a#aaaaa##aaaabca#a##aabbccccccdcccbbbbcbcabbbb#a#a#a#aaaabaaaabbeffddeabcbbbbcccccdccbbbaaaaa#abaaaaaaaaaababbbbbcbb#a##a##a#aaaabefcbdeeddeffffffeddfbchjieccccbbbaaaaaaaaaaaacfcabbbbcdddcdehggffeeddgfecbbccbbbccbcbbaaaaaaaaabaaa######a##aaa####aaaaaaabbaa##aaaaaaa#aaaa#####aabbaaaabbbbbbccccddbaaaa####.", +"####aaaaa#aaaa#aaaaaaabbaaabccbbbcddbbdcbaaaaaabaaaaaabbbbaaaaabaaa###############aaaaa##a#aaaaaaaaaaabbccccdcbbbaaaaaaaabaaa#######aaaaabbbabaacffffbbbbbbbbbbbbccccbaaaaaaaaaaaa##aaaaaaabbccca#######aa###aaaabcgfcdeeefgggggggeffcbbehkjebbcbbaa##aaaa#aaaadheabbbcdddcegfbccdfffgggedccccbbbbbabbbaaaaaaaaabaaaaaa######aaaaa#aa##aaaabaaaaaaaaaaaaa##aaa##aaa#acbaaabababbcccdecbaaaa###a#", +"#######a###abaaaaaaaaaaabbdccccbbbceefebcaaaaaa#aaaaaabbbcccaabaaa###aaa#######a###aaaba##aaaaaaa#aaaabccccccbbbaaaaaaaaabaa###a###a#aaaaacbababa#eeedbbbbcddbcbccbccccaaaaaaaa#a#aaaaaaaabbbbcba########aa####aabbbghdeeegggggghggfedbbbcdikgbbbbbaa#aaaaaaaaaabheaabccddegdccccdddccfffddbbabbbcbbbbbbbbbbbaaaaaaaa########a###aaaa#a#abaaaaaaaaaaabbabaaaaaaa#a##ccaaaaaaaaaabcccbacaaabaa###", +"##a#aa#####aaaaaaaaaa#aabbbabbcbbabcdeedcbbbaaaaaaabbbccdddccccbbccbdcbcca########aa####aa##a#aaa###aabbccdccbbbaaaaaabaaaaa#########aaaaabcaaabaa#dfcccbcccbcccccdccccdbbaaaaaa###aaaaaaabbbcb######aa###aaaa###abbcfheeffghhghhijifcbbbbbehjhcbbba##aaaa##aaa##afgdbbcefecdcdccddddddeedcbabbcbbabbcbbbaaaaaaaabaa######a#a#a###aaaa#aaabaaaaa#aaaaaaaaaaaaaaaa#a#bcaaaaabaaaaabbcccbcabbbaaa#", +"aaaaaaaaaa#aaaaaaaaaaaa#abaa#aaaaaaaaabcbbaabbbabbbbccddddddefdbcdccdecddcaa##aab######baaaa##ab###aaaabbbcccbbaaaaaaaaaaaaaa########aaaaaacdbaabaa#dcabccdddcccccdeeddddddbaaaaaa###aaaaabbbca#a#########a###a##aaabcegefgfhhggiiihddbbccbbfegihfb###aaaaa#aaaa##adgfefecbddccccddcedccefdcbabcdcaabbbbbbbaaaaaaaaaa#a####aaa#aa###aaaabaaaa#aaaaaaa#aaa##aaabaa##abcbaaa#aaaaaaabbbbdddbbbaaaa", +"aaaabbabaaaaabaaaaa#a#aaa#abaaaaabaaaaaaaaababbbbccdddeeefdfffedccbbbbcccccaaaaacb#abaab#aaba#aaa###a#aaaabccbaaaa##aaa#abaa###a##a#aa#aaaaacca#abaaadbabddddfededcbbcaaabcddcaaaaaa###aabbbcdca######a####aa##aaaaabbcdkgghhhhhgiigecabbbccffedgiida#aaaaaaa#aaaaaabfecbccccbbbabbbddddddccbaaacdcbbcbbbbbbbaaaaaaaaa##################baaaaaaaa######aa#aaaaa#a##abbbbaaaaabbaaaababbddcbbbbaa", +"aaaaabcccbbbaabaaaaa#aaaaa#aaaaaaaaaaaaabaaabaaabbbcdffefgffdcccdddcccccbaabaaacbab#aa##aaabb#a#a##aaaaaaabbbcaaa###aaaa#aaa#a###aaa#abaaaaaacccbaaaabcbaaccbbdccbbbababba#abccbaaaaaaaaaabdeabaa##########aa####aaaabbceghghhihiihhgcbbbbbbegdcdedhhdd#aaaaaaaaaaaaabdccccccaaabbbbcddddfeffdbbabcbbbbbbbbbaaaaaa###a#########aa#######acbaaa#####aaaa##aaaaaaaaa#a#aaaaaaaaaabbbbaabbccddbbbba", +"aaaababbbccbbcbaaaaaa#aaabba#aaaaabaaaaababbbbbaaaaaa#aabbcaaabbbbbbbbbcbaaaaaabaaaa####a##aaaa######aaaaaabbbbb#######a#aaa#a###a##a#aaa#aaacbbcbabbabcabbbcddbaaabbaaaa##aaaabbaaaaaaaabbcdbaaa###########a####aaaaabbbcfihghhhihhhdabbbbbbeeccccbdehfaa##aaaa#aaaaaabedccbaaaabcdcddcbfeffddeedccbbbbbbabbaaaaa#############aa########ababaa###aaaaa###aaaaaaaaa##abaaaaabbbbbbbbbbbbcdffabaa", +"aaaaabbacbbbabaaaa#aaa#aaaacba###aaabaaaaaababaaaaaaaaaa##aaaaaaaaababbccc###aabaaaa##a##aaaaa#aa##aa#abaaaacccb##a#a#a#aaaaa####aaaa###a#aa#ababdbbbabcbabbbbbbbbbcbbaaaaaaaaaaba#a###aaacbcdaaaa#########.#####aaaaaabbccfkjgfhhifdfdaaababbffcbbbbbacgda#aaaaaaaaaaaaaddcba#aabccccdbbdeefeddfdfecbbacaaaabbaa##############aaaaa#######a#aa###aaa####aaaaaabaaaaaaaba#aaababbbcccddddgihcabb", +"baaaaababccccbbaaa##aaaaaaa#cddb#####aabbbbaaaaaaaaaaa#####aaa##aa#aabadedca#abbaaaaaa####aaaa#a#aaaaa##aababcbca#aaaa#####aa###a#aa##aaaaa#a#aaacbaabbbcbabcccbbbbcbabba#aaaaaaaa#bbaaaaabbadb###################aaaaaabacbgkkihhggfedaaaaaaaceecbaaaaabffgeca#aaaaaa###acdca#aaacbbccbcbeeefffdabdfecabaaababbaa#a##########aaaaaa#######abaa##aaaa#####aaaaaaaaaaaaaabaaabaabbbbbcdegghffdabb", +"bbaaaaaabbcccccbbaaaaaaabaaaabccca###aabcceebaaaaaaaaaaa#a##a#####aa#aaaddbbaaabaaaaaaaaaaaaabb##abb#aaaaaaabcbba##aaa###aaa#########a#aaaaaaaaaaaaaabbbccbaabccbcbbbbbaaaaaaaaa##aaabaaaaccbed#################.##aaa#aaaaacekljihhhdbaaaaaaabdeedbaaaaaabceffdaaaaa#####abdd##abbbbccccbcedfeddbbbbdddbbaaababaaa#################aa#aa.###aa##ba##aa###aaaaaaabaaaaabaaaaababbabbbdfhjifeecba", +"bbbaaababaabbcccbaaaaaa#aaaaa#aaba##aaabcbbccbaaaaaaaaaaaaa#aa####aaaaaabccbaaa#aaaabaabaaaa#abdca#acaaaaabaabbaba#aaaaaaabba##aaaaaaaaaaaa##a#aabbbbbbbccbbbacbcbabbbbbaaa#aaa##aaaaaacbccccdbbba#a########a#.####aaaaabaaaaafklljhfcaaaaaaaa#dcgfcbbaaabccccdggcbaaaaa#aaaacdaabbbbbbbbcbddeeddccccbbcecbaaaaaaaa#a##############aaa##a####aa##b###aa#aaaaaaaaaaaaaa#aabaaaaaabaabbdggghhfbdeb", +"bbabbaaaaaabbcbccbabba#aaaa##a#aaa#a#aaabbabbbaaaaaabbabaaaa#a#####aaaaaadcba###aaaaaaaaaaaaaaabbaa#abaaaabbbcbaa#aaaaaaaaaaaa#aaaaaaaaaa#aaaaaaaabbbbbbbcbababbbcbbbbaaaa###a###aaaaaaaccddcddbaaba#aaaa####a#.#.#aaaaabbaaa##djlljc#aaaaaaaa#afdfebaaaabccccddegfdbaabbbbbbabddbbbbbbbbbadceedcdcccbbabdebaaaa#aaa#############aaaaaa#ab####a##ba#####aaaaaaaaaaaaaaaaaaaaaaaaaabcdfebbbabbbcc", +"ecabbaaaaababcdcccbbbcdbaaaabbaa#aaaa##aabcbbbaabaaabbaabaaa#aa###aaaaaabecbaa#a#a#aaaaaaaaaa#aaaaaaaaaaaabbcbaa###aaaaabaaaaaaa#a####aaa#aabaaaaaabbbbbbdcbbabbbcbbaaaaa####aaa#aa###aaabcccccbaabbba##a####aa#####aaaabaaaaa##ahlkfa#aaaaaaa##fbbecaaaabccbcdddceghecbbccccbbbccddbbabaa#ccedddddccbbaaacfbaa#a##a############a##aaaaaaaaa##a###ca#aa###aaaaaaaaabaaaacabbaaabbbbddea###aaaabc", +"abbcbbbbaaaabbccbbbbaaaa#a#aaaabcaaaaaa#aabbbbaabaaccbbabaaaaaaaaaaaabbabdcbaaaaa###aaaaaaaa#aaaaaabbbaabbbabaa#aaaaaa#aaacbbaaa##aa##aaaaabcbaaaaabacbccccabaabaacbcbaaa####aaaaa####aaaabdccdba#abbaaa#######a######aaaaaba#####dljfa#aaaaaaa#ddaadcbccbbbbccccdccehihfddccccccbbdfaaaabbbceefedddcbbbbaaaecaaaaa##a###a####a##a##aaaaaa####a###ba#aa###aaaaaaaaabbbbacbbbbbaaacccdd#####aaaab", +"babbbcccbbbaacdbccbbbaaaaa######aaaaaaaa##abbbbabaaabbaaaaaaaaaaaa##abbbdcccbaa#aa#####aa#aaaaaaaaaaabcbabbabaa##aaaaaab#accbaaaaa#aaaaaaabcddbaaaaabbbccccbaabbbbaabbbbaa###aaaaa#####a#abceeeaaa#aaaaba#######a#######aaaaaaa###.cgjgb#aaaaaaaafcaacdcdcbcbbcbbccdeefeeghfeccccbcddc#aabaaaeffeccccbbbbbaaacdcaaba##aa##a#aa#aaaa#aa###a####a####b#a##aaaaaaaaaaaaabbbbcababbbbcdddeb#a#####aa", +"bacbbcddcbbbbacddccbabbaaaaaa#a##aaaaaa####aabbaaaaaaabaaaaabaaaaaaaaabbcccbbabaaaaa#a#aaaaaaaaaaaaaaaabbccbbba##aaa#aaaaaabbbaaaa#aaa##abbaabbcbaabbcccccbbbbbabbbabbbbaa#############aaabbcedbaaaaaa#aaa######a########a#aaaa##a##adhjc#aaaaaaacdb##bddcbbbbaabbccefgecceffgfcbceccedabbaaacffdccbbbbbbbbbaabccbbaaa#aa####a###aaaaa#a##bb##a###ab##a###aaaaaaaaaaabaaabbbcbcbbbcefeb#####aa#a", +"aaccbcddcbbabcbcddcbbbcbaaaaaaaa#aaaabaa##a#aaaa##aaaaaaaaaaaaaa#aaaaaaaaabbccaaaaaaa#aaabbaaaaaaaaaa##aabccccbaa#aaaa#abaaaaaaaaaaaaaabbbbaabbaccbddedcbbbbbabbbcbcbbcaaaa############a#aacbcba##aaaaaa#aaa#a###########a###aaaaa####adid#aaaaa##eca##addcbbaaaabbcddefddefddgiedccccffbaaaaaefeccbbbbbbbbbaabacdbbba####aa#a##a##aaaaaaccbba###.aa#aa#ba#a#aa#aaaaabbabcbccbcbcccegc######ba#a", +"abcbbccdedcbbbabdddcbabbbbbaa##aa#aaabaa######aaaaaaaaaaaaaaa#aa#######aa#aabcbbaaaaaaaaabcaaa###abaaa#aaabcbcb#aa##aa#abbaaaaaaaabbcaaaaaabbgecbbbbccbbbbbabcabbcbbbbaaaaa##############aaabaaaa#aaba#######a###########ba#aaa#aaa###aabffcaaaaaabeb####cdcbaaaaaaabbccdeffeeegihfddddffcaaaabefeccaabbbbbbbaaaabdba#aa####aaaaa###aaaacccbbba#######aaaa#aa#a##aabbbbbbbccccccccddgf#aa##a#aaa", +"aabcdddddddbbbccabcdccbaaaaaa#####bbaaaa#######aaaaaaa###a#####a#########aaaacbbbaaaa#accdddba#a#aaaaaaaaabbbcbaaaaa#aaaabaaaaabba#bdaaaaabeecbbcbcbccbbbbabbbbbbbabbbbaa#aa####a########aaaaacaabaabaa#######aa########abbbbaa##aaaa###aaegfb#aa##dcaaaabddbaaa##a##aaabcdfgffgiggfffedefea#aabffccbaaabbaaabaaaaacbaaaaaaa####a##aaaaaabbabaaa##aa##aaaaa######aabcbaabbccccbbddedeeaaaaa#baaa", +"aabbdeedeedddaccbbbcbcccbaaaaaabbaccaaa#a#aa###aa#aaaa#########aa#a#####a##babbbbbcbbcfdccccbbaabaaaaabaabbbccbbaaaaaaaaaabaaaaaaaaacfcaaabcbbaaababbcaabbbabbbbbaaacbabaaa####a##.########a#abd##baaaaaa##.###aa#######abbadb#a#########aaeiib####bca#aabadcba########aabccdgghgfeddddeedegdaaabdedbbaaabbabbaaaaa#cbaaaaaaaa#a##a#aaa#abbbbaaa#aa##aaaaaaa#####aaabaabbbbccbbbcdecef######acaa", +"baabcccddedddbacccbccdcbbbbaa####aa##aaa###a###aaaa#a#####aaaa#a#aaa###aaaaabbbbbabcgjfdccbbbaaaaaaaaaaaabbacccba###aaaaaaab##aaaabbbdfdbaabdecbbbabaabbbbbbbbbbbbababbaaaaaa######.########a#acdb#aaaaaaa######aa######abbccb####aa######afiifa###bca#aaaabcbba#a######aaabcdeefcbcedccccceffaaaaacdbaaabbbaabbabaaabcbbaaaaaaaaa##a#a##abbaaaa#ba##aaa###a####aaaaaaaaaaccbbbcccdeff.######aaa", +"a#aabbbcdeddcccbcccccdcbbabaaaa##a###aa#a#a#####aa##a###a##aaa####aa#a#a#aaabbaabbbbbffdccbbbabbaaaabbbbbabcbbbaaa##aaaaaaaaa###aabcbbcdfdaacebbbbbaaabbbbbbbbbaaaaabbabaaaa###aa############abcdcaaaabbaaa######aa#####abbbdc#############adghf###cdaa##aaaabbaa##.##.##aaabcdecedbbcdecbbbccebaabacdaaaaabbbbbbbaaaaabdcbaaabaaaaa##aa#aaabaaa#bcaaaaaa###aa#a#a#aaaaaaaaababccdceec##########", +"###bbbbcdeddddcccccbccbccbbbaaa#####.#a##aa######a##aaaa###aaaaa##a###aaaaaabbbbbbbccddcdcbbbbbcdbbbadecccccbcb###a###aaaabaaaa###accbbccfhcacbbbabbabbbbbbbbaaabbbaabbbaa####aa#########.####aabcbaaaabbaaaa#####a#####aabacfb###############dhhc.ddb###a###bbca#.#....##aaabcdccecbbccedbbcccedbabbdcbaaaaaaaabaaabaaaacccaabaaaaaaaaaaa#abaaabbcaaaaaa###########aaaaaaababbbceeda.#####a###a", +"#baaabbcdeddddddddbbcccbcbbbbaaaa################aaababba####aaaaaa###aaaaaaabbaabbdecbccccccbbbccccbcbbbcbbddeeca###aaaabccaaaaaa##abbbbcdedbbabbaaaaabbbbbbbbaaaaaaabbaa#######aaa##########aabbbaaabbaabaaa########aaaaaabdfb####aa#########cghhceba###a##aabaa#.....###aaabcdceebbbbbddcbccbcdcabcedbbaaaaaaaabaaaaaa#cddbbbaaaaaaaaaaaaaaaaccbaaaaaba#a#a######a##a#aaaaaaccdeed####aa####a", +"aaabaabccceeddeedcabbbcbbcbbbbbbaaaaa#########a##aaaaabbcbaa#aa#aaaaa#aaaaaaaaaaabbcddcbbbbbbbbbbbbbabbbbbbaabbdgfba#aaaaabbaaa##aaaaaabbbcceedaaaaabbabbbabbbbbbaaaaaabba#######aba#########a##abbcaabcbaabbba########aabbaabddca#aaaaa#########adjhaaa#aa#####aaa#...####aaabbcccfdabbbbbddcccbbccacffccbaaaaaaaaababaaa##bccccbabaaaaaa#aaaaabdcaabbaaaaa#########a#a#aaa###bcddhga####aa####", +"##aabbbbcdffeddeebdcbbbbbcbbcbcbaaaaaa##.##aa######aabbbbaaaa#aaaaaaa##aaabb#aaaaacddfbcbabbccbccbbbaabbaaba#abadfdbbaaaabcaaaaaaaaabbbababbceedaaaabbabbbbbbbbbbaaaaaaaaa##.#####aa#########aaa#aacdabbbaaaaaaaa#######bbbbccdcddbaabbaaa####aa###bhgea#######.##aaa#####aaaababbbcebababbabdeccbbbceffeecbaaaaaaaaabaaaaaaa#bcccbbbbaaaaaaababbbbbaaaabaaa#######a##a#aa#aaaaabddhg###########", +"#a#aaabcdddffdddeeedbbbbbcbbbbcbbbaabaaa#a##a##aacaaaaaaaaaa#a##aaaaacdaaaabaaaa#accdeaaaaabbbbccbbbbaaaaabbbababcdddcccbbaaaa#aaaabbbaaaaaabdeeeaaaaaababbbbbbaaaaaaaaaaaa###a####ba####a####aaaaaabecaa######aaa#####a#ababccccbcbabaaaaaaa###a####dijdb########a#a###aa##a#abbbbddbaaaaabbabdddcfeffffeccbbaaaaa#aaaaaaaaaa#abccbcabaaaaaaaabbaaababaaaaa#aaaa###aaa#aaaaaaaaabchga#####aaa##", +"#a#a###abccdddefdeeecbbbbbbaabbbbbbbbba#########abaa#aaaaaaa##a#aaaaaccbaaabbabbcbbccfbcaaaababbbbbaaaaaaaaaaaabbbabbabaabaaa#aaaaaabbabaaa#abcdfea#aaaabbbbaaaaaaaaaaaaaaaa#######bba##########aaaabcedbb#######aa#####a##abdcbbccbaaaaaa#aaaaa#aa###bgjjga#######aba#aadba##aabbbccbaaaaabbaaabedffeffffdcbbaaaaaaaaaaaaaaaa#aaaccbbbaaaaaaaaaaaababbbaaaa#aaa#####aaaaaaaaaaabbbghc#####aaaaa", +"a##a#aa#aabccbdfgeefeccababbbaabaabbbaa#a##.######aaaaaaabba##aa##abbbcbcbbccacbbdedgheccbbabbaaaaaaaaabbaaaaaaaaaaaaaaaaaacbbba#ababbbbaaaaaaabdeeca#aabcbaaaaaaaa#aaabaaaaa####.##ba###########aaabbceeba########a#########cbbbabbbaaa#aa#aaaaaaaaa###djkjb#b#..#abbcaaabcba##aaabbcaaa#aaaaabaacfffffedffccbaaaaaaaaaaaaaaaaaaaabcbbaaaaaa##aaaaabaaabaa#aaaaaaa#a#a#a#aaaabbbbccgc######aaa#", +"##aaaaaa##aaccbaeihfgggcbabbbaaaaacbbceceeca########aaaaaabaaaaaaaabbbdcccdebbcbbabacedecbbbabaa#aaaaaabbbbaaaaaaaaaa#aaaaa#abbbbacbbbbbbaaaaaaaccddbbbbbbbaaaaaaaaa##aaa#a##a#####aa#############aaabbceeea########a########aaaaaaaabbaa###a###aaa######agjkhgfb.#aabddaaaaaaa###aabdb##b###aaaaa#cffffeeeeeccbaaaaa#aaaaaaaaaaaaaabcbaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabbbbbdfeba####aaa#", +"#a#aaaaa###aacca#cjjhhjebcbaa##a##acegebdcbdb#.#cbcaaaaaaaaaaaaaaaaaabbcdgiecbbaaabbbcbcdcbbbbbaaaa#aabaabcbaaaaa#aa#aa#aaa###aaaaaa####a###aaaabcddbcbbbaaaaaaa#aaaa#aaaaa##a#####baa#.#######a##aabbcdddffa##.####aa##.####aaaaaaaaaabaaa###########a####chhiihc..ceffbabaaabaaaaabccaacc###aaccbbegfffededdccbaa#a#aaaaaaaaaaaaaaaabcbbaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabcccefeaaa###aa#a", +"aaa#abaaaa##aaba##eiiikhccbddefeeffgecccdccdeffefddc#aaaba#aaabaabbaaaabcdhfbbbbaaacdecbbaabbbcbbbbaaaabbbbbbaaaaaa#######a###aaa#aaaaa######aaaaaccbcbaaaaaaa####aa##aaaaa#####a##############a##aaabcccccdfb##.#####a######aaa#aaaaaaaaaaa##########aaa##.#aejjifb#cffacbbbaaa#acbbcc##ddda##cddeefgfffeedddcabbaa#aaaaaaaaaaaaaaaaaaacbbaaaaaaabbabbbcaabaaaabbabbbbabbbbbbbbbbbdfc####a##aa#", +"#aaa#a#a##a####b###dgkkjgccfiifdfdeeccddddcdcccccbca#aa##aa#aaaaabbbaababeggdbaaaaadfcbbbbbbcccbabcbaaaaabcabbbcbaaaaaa##########a#a########aa##a#accbbaaa#########aa###aaaa###aaa####.#########b##aabcbbcddfb###############aaaa###abbaaba#aaa#########aa#####djjjifbcebccdcba#bbacbcb##addccdcdeeefgfffeecbccbbbaaaaaaaa#aaaaaaaaaaaaaabbaaaaaaabaabbbbbaabababbbbbbbbbccccbbbbcced####a###aa#", +"a##aaaaaaaaa#a#ba..#agkgfecfikgddcccdcccbcccbcbcbbdba##bccaaa#bbccccbaabbefffcaaaabdfbbbbbbbbccaaabaaaaaaabcbbbabbbbaaaa#######aaa############aa###abbaaa####a############a####a#######.#####a##aaa####aaaacfa#######..######aaaa###a#cdcbbbabcbaa#aab#########.chiiihfcddeghhgdccdabdaa#addcddceefeeffeeeedbbcccbbaaaaa#aaaaaaaaaaaaaaaaabbbbaaaaaaabaabbaaaababbbbbbbcccdccdcbbceea####aa###aa", +"a####aaaabaaabbab#.#aaeecdhfijfcccddcccbbbbccbbbccaaa###.a#abccccbcbcbbbbbff#a###abcebabbbbccbcaabbaaaaabccbbbbbbbbbbbaaa#aa####aa##############aaaa#ababaa##############a#a######a####################aabbcacaaab#####.#.##abbaa###aaabcacbcaaaaaaa#aa#########.bgihiifcdgijjjiidaaabe#a#bdcbccccddddddecdecbbbccbbaaaaa##aabbaaaaaaaaaaabbbbbabbbaaaabbbbbaaabbbbbbbccdddedddefeffa####a#####a", +"#######aaaaaaaaaa#.#abcdaahkkjgbbcccbbbbbcbbcbbbbaaaa#a######abddedccccbbacffcbb##acccacdcabbdccdbabaaaa#abbbbbaabbbbcba###a############.##.###########ababaa##################a##a###.################aaabcbcdbbbaa##.#.#.#aabaa###abcdcaabaa####aa#aabbb###a###.#bgjhacegijjjjjjhedfgea##cbbbccbbbcccccdcccbbbccaabaaaaaaaaaaaaaaaaaaaaaabcbabaaabaaabbbbbaababbbbbbccddddedffceedb######aa###", +"aaa#a####a##aaa##a.##acda#cejjfdbbbbbabcbaabbcbbaa#aaa##a#a###baecbdfedddefhhgefea#cedbafecbbcbecbbccbbbbabbbbbbbccabbcdcaa####################.#######aaaaca##########################.########a######aaaaccccbbca#a########aaaa####bedcaabaa##aaaabaaabc########..#figefhikjihhhhiijiihd##bbcdbcccbcccddebcbbbbcdbaaaaaaaaaaaaaaaa#aaaaaabbcbbbbbbbabbbbbbbabbbbbccddedeedffa###a#####aaaaaaa#", +"###aa############a#.##bccbbbbehhaabbbaaabbabbcbaba#aaa#######becdda#fgecddeehghegdabdecaabedbcaacbbddbbbbbbcbbbbbbdbaaccccba#########a################aaaaabcaba###############################a#####.###aaaabccbcb##a######aab##a###accbca#b#####aaaaaaaaa###.####...diihiiihfgeffeffhijid##ddcdccccccddddccbbaabddcaaaaaaabaaaaaaaaaaaaaaabbcbbabbababbbbbbbabbcbccdddedefc.##########aa#aaaa#", +"#aaaaa#aaa##a######.#abbccaaaabgfb#ababa#aaaacbaaaaabbbab####edeefeccgedcddehhfacebadecaaaabcccbbbbcbabbbbbcbbcbccccccabccdb#######abb###a##############aaaacbccba##########a######.########a###a#########aabcceccb###a#####aaaa##aaaaacbb##ac######aaaaa##aaa#######..diihffffffdeddddefiigaaeddddbbcdddccdccbaaabcedbbbaababaaaaaaaaaaaaaaaabdcbaabbababbbbbbbbbbbbcceeegc.#############aaaaaa", +"aabcbbaaaaaaaa########bbcdbaaaaaffa#aaaaa#aaabbaaaabcdeddabaefcdddefcgfddddeghcccffddbaaabbbbbccbccdbcbabbbbbbcbbbbbdcabbbddb########bca#a#######a##a###aaaaaaabdbaa#aaa####aca##...###aa####a##a########aaabbbdecc##aaa############aa#abba##a#########aa#aaaaa########.bgiedcccdccccccccdhigdeeeeedcdddccbcebaaaaaaceebbbbbbbababaaaaaaaaaaaabcccccfedcbbbbbbbbbbbbabcfffe############a###aaaaa", +"a#aaedbbbbaaa#a#######abddca#aaaadcaa##aa####aabababbbccccfggcbcccccfgeccccdddffedfecddcbbbbccbbccdcddbbbbbbcbbbaabbcc#abaacba########aa##..#######aa####aaaaa###bbaaa#aaaaa#cc###a.####aa##aaa#########aaabbbbadcdaaabba##########a#aa#bbaa##a#######a#aa#aaaaaa#######.ageccbbbbbbbbbbbcbehigffeedddddccbcccbbaaa#accdcbbbbbbaaaaaaaaaaaaaabbcbccdbaadfdcbbbbbbbcbcefccba#################aaa#", +"#aaacbaabbcbbbaa#######abcca##aaabbcba########abbaaabaabccdcbabbbccbcedccccccccccccedbbcdbbbccbcbbcbcbbbbbbbbbbabbbbcccbbaaaaaa##a####a#aa####.#####aa##a#aaaaa##abbcaaaabbbabcaaa#.#.###aa#a##a########aaabccabbddbaabaa####.##.aaaaaa##bba##############aaaa##a########.#bddbbbbbbbbbaaaaabfhhgfeedddccbccbdabaaabbbccddcbbbbbbaaaaaaaaaaabacbbcceb#a#babcbbbbbbcbce##.####################aa#", +"aaaaaa#aaaababba#######abcccb#a#aaacddb######aaaaa#aaaaabbbbbbbcbbbbcdcbcbccbccccddbababcccccccccbbbbaaabbbbccbdcbbbbabcbbaa######aa#aaa############aa#####aaaaa#acbabaa#baabbcb#a##.#####baaa#########aaaabcdcccccbaaaa##########abaaa###aa##############a####aaa########.##dcbbbbbbbaaaaaaaabghgffedccccccbbcabbaaabbcbdedbbbbbbaaaaaaaaaabaaabccdecbcabbbcbbbbbcbeea###aa####################", +"aaaaaaaaaaaaaa##########acceeba###bbbcda#######a####aaaaabbbabbabbbbbcccccccccbcbbcdcbaabbcbcccccbbbbbcabbbbddegebbbbbbbcaaaaa#########a######aba#####aa#####abaaaabcbb#aa##abaaba#####a##aaaaa######aaaaaaacccccbccaa##a#######aa#aabaa##aaa####aa########a#aaaaaa###########addcbbbaaaaaaaaaa#fieeeddcccbbbbbaaabaabbaaabdedcccbaaaabaaaaabbaabbbcdebaaccbbdddcbbcdc#aaaa###########.########b", +"aaaaa#aaa#aa#############abcdfdaaaabcdf###aaaa##a#####aaaaabbccabbaaaabbbcccccbcbabbccbbbbbbbbbbbccbbcccbbbcdcdedecabbbbaaaaaaa########abb##aa#aaabaa#aba###a#aa#aabcccbabb###aa#aaa######aa##aa######aaaaaaaccccdaba###########aaa#aaba#aaaa#aa##a########aca##aaa######a######cffaaaaaaaaaaaaa#ehfeeedcbbbbbbcbaabbbbbbbaadeeefedcbaabbabbccbabbdcbcaabdcccccceedffb##aa####################a#", +"aaaaa###aaaaaa#####.####aabccfgbaabbcfeda##aaabaaaaaa#aaaaaaaccbccbaaabcccbbccbbbbbbcbbbbbbbcbbbbbcabcccbababccdeccbabbbbaaaaa#aa########aaaaaaaabedaa##a#aaabaaaaabaccbaaaca###aaaaaa#####a###aa###a##aaa#aaaccbbabaa############aaaaaaaaaaaaa#########a##acdaabaaaa############acecaaaaaaaaaaaaafhffeddcbbabbcbbabbbbbbbbaabbdeddfeddbabbbdcabbabbababbbcbcbccddffcdaaaa##a###################", +"aa#a#####aa#aaaa#########abcdcfeaaacbdccfcbbbdddbbbbbaaaaa#aaaabcbaabbbcccbbbcbbcccccccccbbcbcccbbbbbcccbbabbacddedcaabbabaaaaa##aa########cb##aa#cfdaa##aaababbbbaaaabbbbaabaaa#abaaa#####a#bbaaaa##a##aaaaaabbccdaaaaa#####bb#####aa##aaaaaaaa############aabbbbaaaa##aa##########deaaa###aaaaabcgiggddccccccccabbbbbabbaba#aabcaacccccbbcdbaacbbabbbbabcbcdddd####abaa#a##a#a#aa############a", +"aaa#####aa#a#aaaaaaa######abccdfa#bbcddbcccdcdaaccdecbbbbbbbaabccbaaabbcccbbbccbccccddccccccddccbbbbbbcccbbbbbcccdddbabbbabaaaa########.####bba##a#aca###aaaaaaaaaaaaaabbbaabaabaaabba#######ababba.##aaaaaaaaabcdcb#aaaa#####a##########aaaaaa#a####aaaa##.##abbba#aab#aba#aa#a#####cgeaa####aa#aabfiigdccccbccccbbbbaabbbbaaaaaabccbbccccdabcbccaaaaabbbccdebdbaaaaaaaaa#a######aaaaa#########", +"#aa#a###aaa####aa##a#####aabbbbeb#abbceeba#a####aaaba##cdbbbcccdccbbbbbbccbbabcbbbcbcddccccccddddddccdcabbbcbccbbbddcbbbbbbbaaaa#########.####aaa####a#a#aaaaaaaaaaaaaabbbbaaabaaaaaaba####a#.a##ab##.a##a##aaaabbddb##aa#####aa######.##aaaaaa#aa####a#aaa###abbb###acaacaaaa##a#####bff###a##aaa#aacghhfccbcbcbbcbbbbbbbcaaaabababbdccccddbbccccaaaaaabbccee##aaaabbacaaaa######aaa#aaaaaaa###", +"#aaa##########aaaaa########bbbbbea#babcea#a######aaa####bccddcddedcccccccccbcbccbbbcbcddddcccbbbcccdefedcbaacbbcbbbbbbbbababaaaa############.###aa#a##aaa#aaaaaacbba##abbcbaaa#aaa#aa#########a#######a##aa#a#abbcbcc#a############aa####aaaaaaaaaa#######aa###aabaa##bbaaaa#a##aa######dea#####aaaaaa#behhdccbccacbbbbbbbcbbbaabbabbbcdcccdddbbbba#aaaaabbddb#######bcaaaaaa######aaaabbbaaaaaa", +"aa#aa##########aaa########aabbbbbedbaabddcb#aaaa#aaaa####cccaacdeeggecccccccbbabbbbbbbbccddcccbbbbcbcddeedcbaaabbabbbbcbbbabaaaa###########.#####aba#######aaaaaabbba#aabbbbaa###aa##a#####.#a#.#.####aa##aa#aaabccbca#aa#..########a######aaa##aaa#########aaa#aaaaaabcaaaa##a##a###a#a#bdb#aaaaaaaaaaabcfhfccccabbcbbbbcbcbbbaabaabbabcddcdcccbba##a#a#abddb########aaaaa#aaa####aaaaaaaabbaaa", +"aaa#aa##########aa#a#a#######abbabgebaabacca#ba#aaabaa#########a##bdeddeedddcbbbbbbbcbabacdddcccccbbbcdcdcdcabbbbbbababbbccbabaa###############aaabb####aa##aaaaabbbaaaa#abbbaa###aaaa###a###a##....###a##aa##aaabbbca##aa#.#######aaa##aa######aaa#########abaabaaaaaacbaaaaaa##a###a##a#afb##a##aabbbaaaaeggecebcbbbabbbcbbabaabbbbbbabbdddccccccabaaaaaaccc#####a#aaaa#a#####aaaaaaabbbaaabaa", +"aaaaa############aa#a########.#abbcffcabbceccaaaaaaaaa###a###aa#######aaeebccccccbbbbcbbccbdddccccccbbbccbbbbbbbcbbabbbbbccbbbbaaa########.#aaa#a##aba#aa##aaabbbabbbaaa###abaaa#########aa##a############aa###aabcc#aa#aaa#######.##aaba#aaaaaa##aaaaa######baaaaaaa#aaaaaaaaaa###aaaaaa###ebaaaaaaaaaaaaabbfhgedbbbbbcbbbbbbabbbbbbbabbbbddecbcbbbbbbcbbbceaa#####aabca#a#a#a##a#aaaaaabbbbbaa", +"aaaaaaa####aaaa#aa###########..#aabdddbbcccccaaaaaaaaaa##a##aaa###aa#####eddedddcddccbccbccccbbcbbcedbbcccccbbbbbbbbababbbcbbcbaaaaa############a#a#aa#aaaaabbaabaabaaa#aaa#abaaa#######aaaa#a###########.#aab##aacc#aa####a######..##aa#aaabbaaa##aaaaaaabbaabaccbaa###aaaaaaaaaa##aaaaa##a#ccbaaaaaa###aaaadgggfeababbcbcbcbbaabbbbaaabbbccddbcbbbbbcdccccca#a#a###aaaaaaaaaaaa#aaaaaaababccba", +"aaabaaa#a#######a#aaa####aa###.###bcdcbcbabddbaacbbababaa#a##aaaa#aa#aacdccbddddddbbbbbaa#aaa######bfggfdcccbabbbbabaaabcbccabbaaaa#########a#aaaaa#######aabaaabbabbaa####aaaabaaa##aa##aaa#b####.#########abb#aaee##a###.##.##.###..####abccccbaaaaaaaaabcdaabbccba##a#aa#aaaaa#a#aa#aaaaaaaabebaaaaa#a##aabbfghhgedaaabbbccababcccbbbaabccbcccbbcbbcdcdcaaa########aaaaaaaaaaa#aaaaaaababbccb", +"abaaaaaaaaaa######aaa########aa####bbccbbaabceaa#cbbbbbba#a##aaaa#aa###debacb#aacabaa##aa###########.#afhgeecbccbbbabaacbcccbbbbbbaa#a#########aa#aaaa####aaaaaabbbbbbbaa###aaabbba###a##aaa###.#######ba##aaadbaabeaa##aa#..###.##########abaaabdbaaababababbaabddbaa##aaaaaaaaaaa#aaaaaaaaaaa#aecaaaaa#aa#aaabdghhhfecccbcbbabbacccccbbbbbcbbbbbcbabbdcbcba########aaabaaaa##a###aaaaaaaaaabbb", +"baaabbaaaaaaaaaaaa###########aaa####acccbaaaabcbcabbbbbbba#####aaaba#acbcaa#aaaa#abaa############.#####.dhihgeefccbbbbaabccbbbbbbaaaa##########a#aa#aa####aaa#aabaabcbbaa####a#aaaa###a#aaa################abbeebbbdd##a#######..####.######aaaaabcbbbbbbbbbbb#abcccbaaa#aaa#aaaaaa###aaabaaaaaaa#bcbaaaaaaaaaaaabehhhfedaaabaaabbccccbabbbbccbbabccbbbdcbbaaa#######a#aabaaaaa#aabaaaaaaaaaaabb", +"bbaaaaaaaaaaaaaaaaaaa#########a#a####bbcbaaaaabeecbbaaabbaba###a#aaa##cedb#aaabaaaaa##a#########.##.###a#bfgedeffdccccbaaacdccccbbaa###########aaa######aaba###aabaabbbaaaa#####aa#a##abbaa####.##.####aaa#acbddddfega#a#######.######.##a#aaaa#aaaaaaaabccddebaba#bcba##aaaaaaaaab#aaaaabbbcaabaaaaccaaaaaaaabaabbehhfgebaaaaaaacdcccaabbcbbcbbbbbcdcbbcaaa#a######aa#abbaaaaaa#abbaaaaa#aaaaab", +"bbbaaaaabbbaaabaa#aaaa###.#######a####abb#aa#a#cfecaabbaaaba#######aaa#bddcdaaabaaaa#a#aa######.########ba.a####bfddcccbbacdccccccaa############aaa######adb###aaaaaaabaaaaaa###aaaa##abaaa#####..#####aaaaabbcdeedfgd#aa########.#######a##aa#aaaa#a###a#abeedecc##aaba#aaaaaaaa#bbaaaaabbbbaaaaaaaaaccbaabaaababbadgggfdb#aaaaaabcbbbbbbccccdcaabbcdcccbaaa#######aaaaaaaa##aa###aaaaaaaaaaaba", +"bbbbaa#aaaabaaaaaaaaaba#a######.#######abbbca##acdedcaabca#a#.###a######bddcfcaabaaa##a##a#####...##aa####a####a#abbccddcbbddedccccbaa####a######aaa#####acb###aaaaaaaaaaaaaa###########aaa####.####a##aaaaacdeceeeedc##aa########..#########aaaaa##a###aaaaaabcdedcb##aa#aaaaaaaaacbaaaaabbbbaaaaaaaaadfdaabaaaabbbbcdggfebaaaaaaacccbbbbbbccdcccbbbdcecba#####a####abbaaa#######a#aaabbaabaabb", +"bbaacbabaabaaaabbaaabbaabb#.####.#######abbcba#aabecdbaccaa#a#.##aa##a###acacecbaaaaaa##########..######..abaa#aa####aceeddceggeddccbaa##########a#aaaa##aaa##a##aaaaaaaaaaaaa#########aaa####a#aaa####aaaabbdffffgebca#ab#######.#..#aa######aa###aa####aaaa#baabbdcc##b##aaaaaaaaabaaaaaabbbbaaaaaaaabcegcabaababbbbabgfgfdaaaaaabbabbbabbbcdddbcbccccdbaaa#a##a###aaaaaaa#########abbbbccbaab", +"baaabbaaababaabbaaaaaaaaaaa##############abbaa##aadd##abbaaaa#.##aaa##a####aabcbaaa#aaa###a######..####.#..cdcbbbaa###abdcdedfghffddcbba###########aaaaaaaaaaaaaaaaaaaaaaa#aaaa########a#aaa#####aaa#a#aabbccddghhhfcca#aa##########...##########aa#aa###aaa##aaaa#a#bb####aaaaba#a#aaaaaaaabbcbbaaabaaabbefdabaabbbbbbbbfgggfdcaaaaabbbbbbbccdbdbcbcccbcbba##aaaaaa###aa#aaaa########bbabbbbaaa", +"aa#a#aaaaaaaaaaaaaaaaaabbabaa#######.#.####aaaaaaabdeb#aababaa####aaa#abba#####aaaaa###a##bdba##a######....acdbabbaaaa#####cddaeggffedcba##########aaaa###aaa#abaaaababaaaaaaaaa##a###abaaaa###.#bbaaaaabdcddeefhhifdda#bb#aa##aa######..########ab##a###a##a#aaaa#abaabaaa#aaaaaaaaaaaa#aaaababbbbaaaaaaabcffbbbabaabbbaacefggdba#aabbbbcbacddccecbbbcccbba##aaaaaaaaaaa#a##a#a#######aaaabaa#a", +"ba###aaaaa#cbaaaaa#abababa#a################aabbbbbbbea#aaabbaa#####a##adc##aaaaaaba##a####a########.#####...aca###########.####cffdcdecaaa#######aaabaa##aaaaaaa#aaabbbaaaaaabaaaba##babba######accbbbbbfccdeegdgfggeb#dc#####aaa#####...#######aaaa#aa##a#aaabaaa#bbaaaaa##aaaaaaaaaaaaaaabaabbbbbaaaaababbegdbbaaababbaabffffecb#aabbbbcbbcdddecbaabcbaaba#aaaaaaaaaaaaa###a########a#abbaabc", +"a#######a###aa#abaaaabbccba###.##############abcbcbbcbea#aaaaaaa#######.##ba#a#aa#a#a#a##a####.###########..###ba##############a#aeedbadfcdddcbb##aaaaaaa#aa#aaaa#aaccbbbaabbbbbabcbbcdccb######abcdbddeeefddddb#afdcfebdca#####aaa######.#####aaca####abaa#aa#abcb#accaaaa##aa#aabbaaaaaaaaaaaabbbaaaaaaabbbbbgdbaaabbbbaaaccffgfdcaabbccccccddddfcbaaaaaaaaa#aaabbaaaaaa#a#aab####aa##aaa#bcc#", +"aa###########aa#aaaaabbabbaaaa##..###########abdcccccbcdcaaaaaa#a##########aabb#abaa##########...#.########.######################.bfdaaccefddddbaaaaaaaaaaaaaa#aaababcccbbbbbccbbcddcabca####aaacdcabeggfdda.##.#cc#aefdbaaa###aaa###.##.####aaaaa#a###abd##a###ababbdc#aa#aaaaaaaabaaaaaaaaaaabbcbbaaaaaaabbbbgfbaaabbbbaabbbcefffddbabbcdccccedcabaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa#aaaaaaa", +"aaaa##########a######.#a#abbaa##########a####abdedcccccccba##########a######aaaa#abaaaaa#######..################aa#aa###############ddabedcgededbbbaabbabaaaaaaaaaaabbccccccbccdddba###abacbbcccba####aaaaaaaa##.###acfcaaa##aa#a############aa#####a#a##aea#aaa#aabbcda##aaa#aa#aaaaaaabaaaaaaababcbaaaaaaaabbbgfbabbbabaabcdcbdefffdbbcccccccdda#aaaaaaa##abaabbaaaaaaaabbbaaaa####a##aaaabaa", +"aaaaabaa#######a###a##.###abbaa###############acdeccbbccdga##########a######.#aabaaaaaaaaa#a############.###aa###aaaaa###############.cdbbdefhhhfdccccbbbaaabaaaabbbbbccccdddcdccdb#####bbcbcddba####aa####a#a#####.##aedaaaa###aaa#######..#########a###a#bbbbbaaabbbbaba#aaaaaaa#aa#aaaabbaaababbabccbaaaabaabbbggdabbbbcbbbddcbcbdffdcaccccacccd#aaaaaaaaaa#abbbaaaaaaaabbabbabaa#aa####aabaa", +"aaaa#aaa##########a###.##aaaaaaa####.##aa#####abccdcaabccffa##########a###aa####aabaaabaa#aaa####a######..###a#####aaa############aa###bdddeeddfgfeeeddcabaaabbbbbbbbbbcdddddeeeecaa####abbaaaa#######a#a########.###aaadaaaa#####aa########.#..##.##a######aaabbba#bbca##a###aaaaaaaaaaaabbaaaabbbaabddcaaaaaaaaabfgdaaabbbabdacdbcbdfffdbbdccbc#cbaa##aaaaaaa#aaaaaababaaaa#abbaaaaa#aaaaaaa#a", +"###a#aaaaaaa######accbaaab#####aaaa####a#######accccabacccfe##.############aa####aa###aaa#aa####.#########.##########a############abca##bfcfabbbcaafffffdbbbbbbbbbabbcccdeeedefcaaaaaa##aaaaaaaa################a#.###abbcaa#aa#aaaaa#######....########aa####a#abba#bbbbaaaaaaaaaaaaaaaaaaabcabbbbbbabeedaaaaaaaaacfgecaabbabbacdbabcffffccccdda##aaaaaaaaababaaaaaaabaaaaaaaaaabaabaa##abb####", +"a########aaa#######cddebba########aaaaaa#######abccccbabcdefea#.########aaaaabb##aaa#####aaa##.....#.##.##############a#####.#####aabcbaabfc######.afggggcbbbcbcccbbbccceeeeffhgccbaaa#aaabbaa#a######aaa########a#.##aacdba##ab#aabb##.#.####...########aa#####aaaaaaaabbaaaaaaaaaaaaaaaaaaccbabbbbbbabefdaaaaaaaaabeffabaaababdedabbcfffecccddaaaaaaaaababaaaa#aaaabbbaaaaaaaabbaaa#aa##ba###b", +"#####aa#####aaaabbaaaacdb.#a#########aaa########abcbbbbbcdeeeefc.######aaaabaacbaaaaa##########..#..#....##############a###########abbbba#bd#a######aabbcfedccdddccccdddeeeeefgiedeebaaaaaabaaaa#aaaaa#aaaa###########aabcca##aabaaabba#....#....##.###.#aaa#######a#abaabbaaaaaaaaaaaaaaaaaaddbbbabaabbbddaaaaaaaa##adfecbbbbacddedbbccdffdccddaaa#aaa#bbaabca##a#aaabbaaaaaaaaaaaabb#aaaa###a#", +"####aaba######aa#abbaaaba###aa#############.####aabcabcbbdegfebc.########abbbaaaaaaaaaa#########.....#.#.######.#######aa#####.#.##aaabbbbbc##a#######..##ehfeeeedddcedeffeeeeehf#abcecccbabbbbbaabaaaaaaaa########a###aacdba#aaaabaaaaa#..##..##.#..####aaa##a####aa#aaaabaaaaaaaaaaa#aaaaaabeeccbababbbbbaaaaaaaaaaaabcffbbbbcdccdcbbbcdfgfedcabaaaa##bbababa#####abbaaaaaaaaaaaaaaaa#aaaaaa##", +"#a###aabaaaa###ba###ab##ba###a#############..###aaabcaabbdedefgb####aaa###aaaaaaaaabaaaa###########...#.############################aabbbadcaaa#####.######bfhhgggffffffffeeeefhhcaa##acfffeedddbaabaaaabaa########a####abebaaaa#a#a#aa############.###..#aa##a###aba##aaaaba#aaaaaaaaaaaaaaaaccdcdcbbbbabbbaaaaaaaaaaaaacfeaabbbbccdabccbdfffed#aaaaabaaaaaa#aa###aaaaabaaaaaaaaaaaaaaaaaaaaa##", +"###aaa#aaaa#a##.a##a#aba#aa###########.#.#....####abcbbbbccdffegb...##aa###abaaaaaaaa#a#aa#######aaa###.####.#####################a##abbcfda#aaa###########.#acfhihhhijiiiihgfhhgcaaaa#..acccddccecccbaaabcb#######aa###abcdbaaaaa#aaa#aa##########.##########aa##aaa#aaaa########aaaaaabaaabbaaababaacbbabbbaaaaaabaaaaa#cefdabbbabbcbbbccdfggeb#aaaaaa###aaa#a###aabbaaaaaaaaa#aaaaaaaaaaaaaa#", +"#aaaaaaaaaa##aaaaaaaa#aaaaaa##.###aa###.###...####aabdbbabbcfeced.#########aaaba#aaaaaa##ca#######aaaa######.########.########a#####aaabdhgfeaaaa#############.#aaba#addfghiiiiheb###aaaa###.####bdbcdcdcbbca##a##a##a##aabbdbaa####aaaaaaa#############a#.##aaaaaaaaa##aaa##a#a#acbaabbabbbaaaaaaaabbbbbaabbbaaaabaaaaa#a#bfgebaaababbbbbbbcggfeaaaaaaaaaaaaaaaa####aabaaaba###aaaabaaaaaaaaaaa", +"a##ba#abaaaaaaaa####aa###bbaa##.#######b#####.#.###aacbbaabcdeccc##.########aabbba#a##aaa#bba######aaaaa#################.######aa##aabbfhhihdabaa##############aa######.##a#bgfb###aaaaaa########cbacccdfeecaa###aa##a#aaabcdbab##ababaaaaa##########aaa#####aaaaaaaa#a#aaba##aabfdaa#aaaaabbbabaaababdbbbbbbbbbbbbbaaaaaaa#dffcbaabbbbbbbbbcefgdba#abaaaaaaaaa#aa##abbbaaacba##a###aaaaaa##aaa", +"aaaaaaaaaaaaaaaaaa#####a##aaaa########ab##.####..###aadccbbacdcaa###.######aabaaabb#aaaa###############aa#####a#####.##############aabbbehhhfcaaaa#####.########aaaa##aaa##a#.#caa####aa##########cdbbbbbcedefdcbbaa##aaaababbdbaaaaaaaaa#aba#########aa######aaaaaa#a#aa##aaa##addbbaaaaa#aaaaabaaaaaaccccdcbbabbbcbaabaaaaa#cfgdbabbbbabbbbbcfgedda#aaaaaaaaaab#a##aabbbaaaba#aa###a#aaaaaa#aa", +"aaaaaabaaaaaaaa#accb#########babaa###aaa##.##a##.####abcbccabdeaaab#..######aaaaaaa#####################aaa####a#####.############aaaabdgihgcbaaa################aaaaaaaaa#aa###a######a##########dbaaaaaaaacbcefgfddcccddegdcbdbaabaaaaaaaaaaa######aaa####aaaaaaaaa#############aaaaaaaaaaaacaaaaaaaaabbbbdeccdccbbbbaabaaaaabefecbbbabbbbcbcegededcaabaaaabaaaaaa##aabbbaaaa#aa#aaa#bbaaaaa#a", +"a##a#aaaaaa###aa#bbcbaa##aaa#aaaca##abb########a#####aacbbccbdeaaaba#########aaa##a#a####.################ba#########.##..######.bbabaaehhhgbaaaa#################aab#aabaa#aa###a##########a.###.ab#aa#abababbbcbcdcaacecccdefdc##abaaaaa##aa########aaba#aaa#a#aaaaba#a#aa#a##.##abaaaaaaaaabbabbaaaaaaaaaaccbbbcdbbbbaaabbbabbdgfdbbbabcbcccdddeeedcaaaaaaaabaaaaa##aabbaaaaa##aa####aaaaaaa#", +"####aaaaaaa######abbcca##aaaaa##abbabba#a#####aaa######aabccedfaaaab#########aaa###.#######################b########.#ba#...##.#acbccccfgggebaaaa##a###############aababaaaa#a##a#a####a##a########c#aaaaaaaabbaaaaabccdebabbbdgeaaabbbaaaaa##a#######aaab##a##aaaaaabaaa###aaaa####ba#a##aaaaaabbaaaaabbaaaaacbbbcbbbcbbaaabbbbcbcfgecbcbbbccddccceddccaaaaaa#bbaaaaaaaaaaaa#aaa##a#aa#a#aa####", +"##a###aaaaa#######aaaaaaaaaaaaa#aabbcaaaaa#a###aa########aabeeea###aaa#######aabb#####a######.#######aa##.######aaaabedccbbb##bbbbaabbbbccdeaa##a##a########aaa#####aabbbba#a#aaa#a####a###########caba###ababbbaabbabcdcddcbabehcaaaaaaaaaa############ab##aaaaaaaaaaaaaa#baaaaa###bb#a##aaaabbbbbaaaaabbbaabbbbcccbabbbaaaabbccccbfffcccbccccbccccddeedaab#aaaabaaabaaabaaa###aaa###bb##a#####", +"aaaa##aaaaa#aa#######a#abbaaaab######aaaaa#aaaa#aa#######aabdefb#aaa#bc#######abcb#####a#################aa#a..###aabcdfffggfdcbbbbbaaaaaabdeaaa###########aaaa#####aabbbbbaaa#aaa#####aa#a##.#####aaaaaa##abaabcbbbaaabaabbbbcdefaaaabaaaaaa##a######aaa######aaaaa#aaaaaa##aaaa###aa#aaabbbabbaabbaaaaaaaabbbbbacccbaaaaaabbccdccdefegffdccecbccccdeeddcbaaaaaaabbbcbaaabaaaaaa#######aa######", +"#aaaa##aaaa#############abaaaaaba##aaaaaaaabaaaaaba#####a##abdgca#aaadeb########bba#####aa#aaaaaa###aaa#ab#aa#.###.#acfhfddgccbaa#aaaaaa#abcfaaaa#######aaabbaaa#####aaaaaaaaa#aaaaa#aaaa##########aaaa#aa##aaa#acccabaaba#a###acdbaaaaaaaaaaa###a##.##aaaa###a###aaaaaaaaa###aaaa#abb#aaaabbbbbbbabaaaaaaaaaacbbbccbbbbaabaaacccccdfdbdfgeefcddabccbcedddccbbaaaaaabbbababbaa#aaaa#a##ab##a####", +"##aaaa#############aa#####abaaabda##abaaaababbaaaaba####aa#abbdeaaaaaadf###############a#aaabbbbba#aa#aaaa#baba.#accbffffgddcbbaa#####aa##acfeabaaaaa###aabcdcbba######aaaaaaaaaaaaaaa#aaa##########dbaa########bbdcaab#abaaa##abceaaaa#a#aaaaaa#a###.######a#####aabaabb#aa#####a#bcbaaaaa#aaaabbbbbaaaaaaaaaaccccbccabacaaaabceeeeggdcdfffccccca#bbcbddeccccca#abbbbbbbaaabaaa#a#aaaaab#######", +"##aaaa####.##########baaa##aaaaabda#aaaabbaaccbaaaa#####aaaaabbcbbaaabdgfe###aaa#######a##aaabbabbb#a#a#aabdceeedcabcaeddcfhecdb#########aacdhcbccbbbbbbbbdehhedba##aaaabbbbbaaaaaabbaaaaaaa########cba#######a#abbda#aabcbaa##aabceaaa######aaa##aa########aaa##aaaaaa#aaa###.###aabaaa#aaa#aa##abbbaa#baaaaaaabbbbbbdbbabaaaacaddacbbbbddccccbbda#cbbcdcddeccccbaabbbbca#aabaaaaaaaaaaaaa#####", +"#aa###a####.##########aa#a##aaabaccaba#aabbaccbaaaaaaaaaaaaaabbccabaabeffeebbcb#.####.#aaabbaabbccccccccdddcec.#aaaaaaadccbbcccca.#######aabdhecdddeeeddeefecbbeedcaaaaabbbbbbabbbbcbbaaaaaaaaaba##aba####a####aacdccaa#ccbbaa##aabcdaa########a##aa########aaaa##aaaaa##aaa#########aaa##aa#aba#aabbbaaaaaa#aaaaaabaaaccbaaaaabccababbbb###bcbcbbecabbccdcddcdcccaaababbbbaaaaaaaa#aaaaaaaaa###", +"#aa#aa##########a######a#####aaaaabc#abaaaabbcbbaa#a##aa#baaabbbbbabbcfffgghebdcbbacacbbbbbbbcbccdccfdaaabdedcaaabaaaaacccbbbbbbcb########abcfgedeffeeeegfcbbcbadgdddaabbbbbbbbbbcccccbbaabababbbaacbaa#########abcccbabccbbbaa##aabcb#a#######aa######a#a##abbbbabaa###a#aa########.bbaaa#aaaaaa#aaabbbccbaaaaabbbbbbbaaaaaaaaabbbccccaaa###bcdbabcbbbabcdddcbddccbbaaaabcccabaaaa#aabaaaaaaba#", +"#aaaaa#######a####a###aa##.###aaaaabc#abaaabbcbba###aa####a#aaabbbaabcdcdeccdecccccba##aaabbaaaaaa##beaaabacfdeaabdecb#bdcbbbbbbaca#######abcdegeeeeffgfdabbccddeehhhfdbbbddeeccdcccdccbbbbbbcccbcca##a###a########aa#.aceccbbaa#aa#acb###.#####aa#####aba###abcdcbcbaaaaaaa#####a###bc#abaaaa#aaa#ababbbbccbaaaaabbcccbcbaaaaaabccdacccb#a###abddbbbbbbabbcebcbbdcccbbaabbabcabaaaaabcbaaaa#aaa", +"aaaaaaaaaaa####aa#####aaaaa.###a#aaaccaaabaabccaa##aa#######aaaaaaaaadc##abaaaaa###a#######a#########cb#aaaacdddb#bbdda#becbbbbbbac#######abceffhffffda##babcccdeeddbddeecdcdebdeeccdddeddcccdeba#b###aa##a#########a###bedbbbbaa#a##aca###.#####aa####aaa####bbcdddbaaaaaaaaa#######adbbabaaa##aaaaaaacbabbccbaabaabbccccaaabbcbdcbcecccaa#a#a#adcabbbbbcbbcbccaabccdcbbbbcacbaabbaabcbaaaabaab", +"bdbaaaabbaaaa#aa##a#aba#############abcaabababcba##aa#########aaaaaaabdb##aaaaaa###a##################b####aaccdeaabcbbaaeddbabbbabb#######bdfhghhgda###aabbcccecbbbdcccefdbbcbcb#eefgghggfeegdaa##a###aa#######aaa#####bedcabbaa#####acb##########a##aaaa####acbccccaaabaabbbba####a##dbba#aaaaa##aaaabdababbccbabaabbcddcbacbbccdacdbba#####aaaabcbbbbbbbccbbababbcddcbabbbabaaabcaaabaaacabaa", +"aacdbaa##.##a##aa#aa#aba###.#########abca##aabbbca#..###########aaa##aab######aaaa#########aaa#a###aa#######aaccdfbabbaaaeeddbbcbbbdbaa#abcdfhjigca######abccbadb###cfbcbbecabbba#begfhggddcggdbbaaa##############a#aa#.cddccbaaaa#####ab##########aaaaaba####accbbbbaaabaabbbabb#######aba###aaa#aa#aaabcaaaaabccbabbcccdedcbdbbacdcdccaa##a#aaaaabcbbbbbacccbaaaabaccccbaaaaaaaabbbbaaaaababba", +"aababbaa#####a##a##a###a####.##########aba###abbbbba####.#.#######a###aab######aa#a#########aaa#####aaaaa#####bbceebbbba#ceedccedcegdcbcddedbcbed#######aabccdbdda##adeeb##abbaaaaacbadeddfdghdcbbbaaa###########abbbcdbbdcbbca##aa#####bd###.#.###aaaaaaaba##abbbbbbbaaaaaaaabbaaa#######aa###aaa#aaaaaabcaabb##abcbbaabcedccdcbaaccccba####a#aaababcbaaaabbccbbaaababccbaa##aa##aaabaaaaaaabaa", +"aabaaaaa#a#####a###aa##########..######aaba####aaaabb#.###############aaab##.###a#a#######aaaaaaaaa#a#aa###a##aacdceddfgfcfffgdccdeeefggdbaabbbbdcaa###aaabbcddeb##a#adfeaaaaaaaaa#bbaaccbeedhecbabbaaa#########.adccbcdbdbbcbba#######a#cda########abbaaaba##abbacbbaabaaaaabaaaaaa########aba##aaaaaaaaabcaaa#a##abca#aaabdefecbaadbbbaa##aa#aaaaaabdcbaaaaabcbaa#aaaabbbaaaaaaaaaaaaaaaaaaaaa", +"aaabbaaa#########a##aaa###########.##.##aaaa#####aa#cba################abcb.####aaaaaa##aaaabbabaabbbaaa##aaaaaccgghggecdfihhg#a####a#a#abbccccacdcabbbbbacccdfeba#####aaaaaaa###a#ababbccadcgedccbaaa############ccbabccbcacabaa#####a#bacd###.####aaaaaaa###aaabbccaaaaaabbabbaaaa###.##..#bbb###aaaa#aaaaaaa########a#aabccceecbbdbbbbaa#aaaaaabbaadccbaabaabba#####aaaabaabaaa##aaba#aaa#aaa", +"aaaa#aa##############bba##########..#.############aaaaaa#####.##########abca..####abaaaaabbbcccbbccddbbabbbbbcdefebdfd##a#.bedaa#########aabbbcbcddddcbbbcdeffd#########aaaaaaaa#aa#baaabcbacegedbbaaa##########bcdbaabbcccbbbaaaaa#####abbcca####.##aaa####aaabbcccdbaaaaaaabaaaaaaaa####.###abba##aaaa#aa##a############aaaa##cfebdcabcb###a##aaaabbabacbaaaaaba#a####aaa#aaaaaaa####aaaaaaaaa", +"abbaaaa####a##########aa###################aaa####abaa#a################aabc#.#####aaaabbbcdddcdfffefgffeddfgdcdcb####aaaa###bb#######a##aabacdcddbdccacdefecc#a##a#####aaaaaaaaaa##aaaaabbbabfgdcbaa########aaacbbbbabbbbcdaba##a#####a#abccda####aaaaa#aaa#abaaaccbbbaaaababbaa##aaa#########bbba##abaa#####aa#a##aaa#a###aaa##defdcabbbaa##aa#aaaabbbaaccaaaaab######aaba#aaaaab####abaaaaaaa", +"aaabaaa#################abba###############aaaaa##aaaaa#a###############aacaca.#####aabbbbccddfda#adeca#####b###aa#aa#aaaa##aaba#a####aa#aabccdccedebaacccb####aaaa###a###abaaabaaaaa#aaaaaababdgdbb##########cabbdbbbaaaaaccaaaaaaa##aaa##acdc#.#aaaaa##a##aabaa#ccaaabaabbaaacbb##abaa######..abca##aaaa#####aa#aaaaaa######abaabdggcaaa#aaaaaaaaaaacba##bbaaaabba#aa#aaaaa##aaaba###aa#aaaaa#", +"#########.#################aaaa#.#.##aaa###aaa##aaa##a##aa###############abbbba#.##.#aabbbbcefc####...#####aa#####aa###aa####aa#######a#aaacbacbbdddbbccdfecbcc###aa####aa#aaaaaa###aaaaaaa##aaacfdaaa#####aaaabbabbbbaaabbabbaaa###aaaaaaa#abce..##ababc####aaaaabdaabbbbbbaaabbbaaa#a##.#######abaa#aaaba##aaaaa#a##aaa###aaa##ababehcaaaa##aaaaaaaadc####abaaaaaba###aaaaaaa###aaaaa#aaa#####", +"####a######################aab#....##aacaaa#aabbaaaaa#####a##############aabbbcb##.###abbcceca###################aaaaaa#a#aa##a#aaaaaabaabbbbbacaaabbabaafddcbcb###aaa#aab##aaaa######a#######a##cfeaaa#####abcbbbbaaaaaabbabba###aaaaa#aaaabaaee#.##ddaaa####aaaaacaaabdcbbbbaabaaba#aa##.#######aaaa#aaabaaaaaaa##aaa#a##a#aaaaaaabbcgebbba#aaaaabaabbaba###aaaaabbaaaaaaaa#aaa##aa#a##baa#a##", +"####a##aa##################aabda#.#####bcaa#abaabaaaaaa###################aaabcdb.####bbbdea##########.###########aaaaa##aaaaa##aaabbbbcbccbbaaaaaaaabbbaaaacdcbbbaaaaaaaabaa#aaa################abecaa####aadcabcaaaaaaabbaab#####aab#aaaaabaaade#..#ca.#a####abcbbb#abbccaaabbbabbbb#a############aa#aaaaaaaaaacaa##aaa##a#aaaaaacabccfebbbbaaaaabbbbaaba####ababacbaaabaaaa##a#aaaaaa##aaa###", +"#####aaaa###.#a######a#######aab##..####abbbbbbbbaaa#aaa####aaaaa##########aabddea.###abda#################a#########a#####aaa###aaabbcdcbdbbaaaaaaaaabbbaaaaacddcbaaaa###abaa######..############abeda###ababbbccbaa#aaaaaabaa##a###ab#aa#aaaaaacec##ab.########babbaaaabbababababbcda###############a#aa###aaabcbbaaaaa###aaaa#ababbcdcdecaabaaababbaaa#######aaabbbbaaaaaabaaaa######a#aaaaa#", +"a#######aa#a######aa#a#aaa###aaac#########abddccbbaaaaaaa####aa#aa########.abehghhc##abca##aaa##################################a#aabccb#aabaaaaaabbbaaaaaabaaabbbdba#aa###aaa##################aa#abefccaabbbcbabbaaaa#aaaaaaaa#aa###abaa##aaaabbcfdaba.#a######bacc##aaaabaababaabcbca##.#####a#####a#aaa#####aaaaab##aa##aaaa#aaaabccebbffbaaaaaabcaa###a#####bbbbbbbaaaaabaa#aa######aa#aa#a", +"#baa#aaaaa###a#a#aaaaaaa####b#aaba#########aacbdcccaaa##a###aaa#aa##########bbfikjicacc###aa#aaaa#############a###################aaabccca##aaaaaabbaaaaabbbbaa#aabcbbaa####a#################a#aabaabdfbdcccbbbbbbbbaaaaaaaabbaaaaa#a#aaa#aaaaaabbcfdbb#######a#aaac##a#ababaaaabbcdaaaa##########a#aaaa#a#aa##a#aaaaaa#aaaaaaaaaaabbccdcaaegcbaaaaacaa#####a####bbbbbbbaaaabba##a###aaaaaa####", +"####aa#aaaa##a#aaaaaaaaa##a#####aba##########aadcbbba####a####a#aa##########abcdfhiigc#a##aaaaaaaa#aa#####################a#######aadccccaba##aa#abaaaabbbcaabaaba#aaaaaa####a###a#a###.#####acbbcbaabcehfdccccbbbbbbbaaaaaaabaaaaaabaaaa###a#aaaabbcddca####.#####aa##aaacbabbbbaabcba#bc############aaa##aa##aaaaa#baaaaaa#aaaaaaaabccdeba#cgfbaaabca#a###aa#a###bcbbbbbbaabbba##b###aaaa#a###", +"###a#aaaaa#aa######aaaaaaaa######aaaa#######a##aaaa####.###aaaaa#a###########abacdhiiga##abbaaaaaaaa##############a########a##a##abbcabc#abbaaaaaaaaaaaaaacaaabaa###a###aa###a###aaa########bbbbcbbbbddceihebbcbbbbbabbaaaaaaaa#aaaaaab#a#####aaaabbcccfb#.########aa##abaaaaaaabbaaaabbcbc#####a######ba##aaa###aa###aa##abbaa#aaaabbbdcccbbabdhebcbaaaaa####a#####accbbbbcbaacba#aa###a#aaa###", +"#a####a#aaaaa#aaaaaaaaaaaaaa#######aba#######a####ab########aaaa##a#a##.#..#####aehhjihb#abacba#aaaaaa############a#a########aa#aabdcc####abaa##a##aaaaaa#ababa#a##aaaa#######a#aaaaaaaa##aacaabcccbcbabbcghgdbbabbbccba##aaaaaaaaaaaabaaa####aaaabcbcdccaa#########.##aaaaaaaaabababbabaa#######a#a##abbba#a######a###aa#aaaaaabbaabbcdbbbbabbadffbbaaaaaa#a##a####aabcbbbccabbabaaaba##baaaa##", +"##aa###a#aaa#a##aaabbaaaaaaaaa##aa###a#############bba#.###aa#aaaaaa#######.####adfehjif###aaaaaaaabbaaa#a########aaa###a######abbbbcca.###a###########a###aa###a#############aaabbbbbaaceb#aaabbbccbaaabbbdggdcbbabbbbaa###aaaaaaaaaaba#aa#a###aabbbbcdc#####aa#######aaaabbbaaabbbbbbba#aa#######a##aabbaa#######aa###aa#aaaaaabbbbbccaaccbbbccdfgedaaaaaaaaaaaa##aaaccbcccbbccba##aa##abaaa##", +"########a#aaaaa#aaaaaaaaaaaaa#aa#ba###########a####aaaaa#.##aaaaaaa##a#a########bbceeijfc####bbababaaaaaaa#########aa##a#aaaaabbadcccba####.############aaa#aa#############a##abbabbbaa##ceaaa#aaaabbbaaaaabbdgfbbbbbabba####aaaaaa#aaaaa#####a#aabbbccdccca#aaaa######aaaaababbaaabcabba##ba##a##a#aaaaaaaaa#######a#a##aaaaaaaabbbcccaabbddcaabbabdffdbbbaaa#aa####aabbccbbcbbddbaaa####acbaa#", +"#######aa#a#aabbaaaaabaaaaaaaaaa##aa#a#############abaaaa####abb###aaa#a########babcfhiiea###acbbabbaaaaaaaaa####aaba#aaaaa#aaabaccbcbaa###############aaaa###a##############aabaaaaaa####bbbabaaaabbbbaaaabbbcffbbbbbbbbaa##aa##a###aaaa####aa##aabccefcadda##aaaabb#aaaaaaaaaabbbbbbbba##abb######aaaabbba###############aa#aabbcccbabbaabdccccaabacfggccbaaaaaa##a#aabccbbcaabdbacba####bbaaa", +"aaa####aaaaaaaaaaaaababaaaaaaaaaaa#aa##############abbbbaaaaa##bbbaaaaaaa######ab#bccehiic###abcaabbbaaaa#aaaaaaaa#aaaaaaaaabcbccacba########.##########aa###############a#aaa#aa#a##a#####acbddcbaaabbbbbaaaabbefcbbbabaaaaaaaa######aaa###aa#####abcdghedcbbbbbcccdcbbaaaaaaaabbbbbbabaa#.acca#a###aaaaaaa########a##a###aaabbcdcaaaaaabbaccddaaaaacaadggfdbaaaaa#aaaaaabccbbaacbaababaaaabbaa", +"aaa#a#####aaaaaabaaaabbbaaa#aaaaaaa###aa#######.#a###abbbaabbbbaaaaaaaaaaaa####a##ababchie###aabbbaaaaaa#aaaaa#aaaaaaaaaaaabccccbccb####a#############aa######.###########aa###aa#aaaa#a###abcccdbbbbaaaabbaaaabbceebbaabbaaaaa#########aaa##aa#####acdfdefebcddcbbdffdcbaabbaabbbbbcdbbaaa##abca#####aaaa#a##a#aa####a#a##aabbdedaaaaaa#aaccbeda#aabbaaaacefgfdbaaaa#aaaaabcccbccabaaabbaaaacc#", +"##a##aa###aaabbbaaaaabcbaaa#aaaaaaa#a##########a#####aabbaaabaabaaaaaabcccca########aaacfhc##aaabccba#aaaaaabbaaa##abbababbcccbeecba#####a########a####a#a#####.##########b######a##a##aa###aababaaabbaaaaabaaaaaabdfcababbaaaa##############.#######bddcbdeffcbbba##dihdcbaaaaacaabbbdcaaabaa#aba#####aaa######aa##a###aa#abcdccdb#aa###aaaccdcbaaaaaaabbaaabehhebaaaaaaabaccbcbbbaaaaaaaaaaacb", +"a##aa#####aaaabbbaaaaaababaaa#abaaa#############.###aaaabcaabaaaabbbbacdedaaaa######a##bccdccaaaaaacdcaaababbbaababbbccbcbbcdcceedc####a##a###########a#aaa######..####.####.###aa######abbaaaabaaaaaaaaaaaaaaaaaaaacfeedbbaa############.######aaaa#abbaaaaccbabaaa###igdccbbbaaaaaaabcbabcbcb##a######a####a#aaaaa####aaaacb#abdcaaa#a###a#acddcbaabaaaaaaaaadfhhedaaabbabbcccbbaaaaaaaaaaaaaa", +"ba##a##a#aaaaa#aaabaaaaaaacaabcbaaaa#aa#########.#########aaaaaa##ababdefcab#aa########aabdfgbaaaaaacdcaaabaaaaabbbbabbcbbbcccddaaaa####aa#aa########a#aa#########..##.##..###.###aaba###aaaaa#abaaaaaaa#aa#aaaaaa#aaaegdcbbbaa###########.######aaa##aaaaab#abaaaaaa#.febaaabcccbcbbcbbaaadbcecbaa#####a#aaaaa###aaa#aaaaabaaaabccaaaaaa#aa###adbbbcbbaaaabaaaabbchifbabcccabbccaacbaaa##a#aaba", +"#ba########a###aaaaaaa#a#aaa#abaaaaabaa##a#aa###############aab####aaaaabccaaa##a#.#####abcdfb#aaaaaaaaabaabbbcbbbbbababbcdddfedcb#a##aaa#aaaaa###aaaa##aaa##.######.###.###########a#########aaaabbaaaaaaa###aaa##a###bfedcbbaaa############a####a######a#aaabcbbbaaa#gdaaa###bcddcecccca#addefgfddca###a##aaaaaaa##aabaacb####bbdcaaaaaa#aa###ccbbbccbaaaaaaaaabaadhieabaabbccdcbabbaa#####aaa", +"#aab####aa###aaaaaaaaaaaaaaaa#aaaaaaa#####aaa#a##.############aa#abaaaaaaabaaaaa########abccdfcaaaaaaabbbaa#abbcbbaacabbbbcddecdcc####aaa#aaaaa#aaaaaaa##aaaa###..######.#####a########aaa#a####aaaaa#aaaaa########aa####dedbbbaaa##############a###a#####ababccbaaaaa#gcaaaa####bdebbbbbca#bddcbaabccaa##a##aa#aaaaaaabbaca####abdbaaaaaaaaaa#a#ccbbbbbbbaaabbaabba#adhgcbaccccccdccba######aaa", +"a##aa#a###aaaaaaaaaaaaaaaaaaaaaaaaa#aa###aaaaa###.#############a##abababbaaaaaba######aaabbcddhcaaab##baaababaabaaabbabbbbcdddffeeb###aaabcaaaaaaaa###aaa#aa####.######a#######b#####aaacb#######ababaa#aaa##aa########a#aaeecbbbaa##################a##a##bbaabb#aaaa#cd#aaaaaaaace.aaa#bdccdcaaabcacbaba###aaaaaaaabaabccaa#aaabbd#aaaaaaaaaaa#bcccbbbcbbaaaaaaabbaabbhidbbcccbdeddaaa#aa#aa#a", +"aaaa#aaaa##aaaaaaaaaa#aaaaaaaaaaa######aa#aaa####..#########.###aaabbbcbbbaaaaaaba#####aabbcccegcbaaaaaaaacbaabbaaabaaaabcccdeeffddaaaaabcbbbcfffecdcba#abb#############aa#a##acbbcba#bbaa########aabba###a##########aa#aaa#eedccbaaa#####a#a###########aaa#aaa#bcaaaaaafaaaaaaaaacfa##a#aaaba#abaaccbcbbccbaaaaaaabbbbbbaaaa#a#abccc#aaaaabaaaaaadcbbbcbcabbbbaaaaabaaccfjgbccbcccccaa##aabaa#a", +"#a#aa#aabbaa#aaaaaa##abaaaaaaaaa##aaabaa##aa#a###.#.##############aabbbcacbaca#aaca#####aabbccdeedbaabbaaaabbabababaaaabbccdddffedffb###bbccefebccbdeda#aaabbaaa#######aaaaa###aabcca#adaaa#####aba#aaaa##aa################.cedcbbbbaaaaaaaaa##a######aa####aa#bbaaaaaadc#aaaaaabbee####abaaa#aa##abaaabbabdcccdcbbaccbcb##aaaaabbcdbaaaaababaaaacbccbbccbaaabbbbaabababadjiedccccbbbaaaa#aa#a#", +"aaaaa###aaaa##aaaaa####abaa#aaa#a###aaaa######aa#################a##abbbcccbbbaaabba##.#aabbbbddedd#aacb#aaaaaaaaaaaaabbbccdddggffghecbbaabbbddabaa#aaaabaaa#bbbaaaaa##a##aba###aaabb##bbaa####aaaa###########a########.#####aaeecbaabbaaaaaaaaaaaaaa###aaa##a##aa###aaabeabaaaaaabchca###a#aa#a###a##aa####bca#abdecbcdbaaba#aaabbdcaaaaaaaabbaaaaccbbbccdbabaaabbbabbbabacjkjgfdccbaaaabbaaa##", +"#a#aaaa###caa#####aaadb#aaa#aaaa#aaa##aaa###aaaa#a####a##a######a#a##aabbbbabba##aabaa##aaaabacdececaaaba#aaaabaaaa#aaaaccdeeefgeeefbcbbbcbbbcbaaaaaaabaaaaaa##abba##a#####aaa###aaaa##.#ba##.###aa############.##.#############dedcbaabbaaaaaaabaa###a###aa##aa#aaaaaaa#dbbbbbbbaacgg#b####a####a##aaabaaabbcaa#abacdcaaaabaaaaabbccaaaaaaaabbbbcbabcacccccbabbaabbbabcbbaaejklhfcbcbbaaaa#aaaa", +"####aaaaa##aaaaabaaaaabbaaa##aaaa###aabbaa###aa#aaaa###aa#######aa#a##bcccaaabbaa#acaa###aaaabbcdcdcbaabaaaaaabaa##aaaabbccdfffghffdaabbaabccddbabaaaaaaaaaaaaaaaaa##a#######a####aaa###.aba######a#################a############bfedbaabbbbbaaaaabaa##a#########abbbba##dcbabbbaaabcgdc#####aabaa###a#bbbbbbbbbbaaabbcbbabbbaaaabbbdebaabbbaabcbbbbacbabbabbbbabbbaababbbbbghillgcbbbbbaabbaaa#", +"###aaaaaaccdcaaaaaaba##aaaaa##aabaabaaab########aaaba####a###a##aaaaaabccbba##bbba#bca###aaaaabdcddcda#abaaabaaaaccaaabbbccefgfghffaaaabbaaabefbcbaaaaaaaaaaaabaaaa##aa#########a########aaa###a##############.##.#.############a#abdebabcdcbbcbaabba############acdea#abecbaabbbaabbdfc##aaaa#a#aaa##abbbcaba#adebaecabbaccdcbbabbcbdddbabbbabccccbbacbbbbbabccbbbbbaaaabcbcfijjkjfddcbabdebaaa", +"db#bdccbbcb##aabbbbaa###aaabbbbaccaaaabca####.#####baba##a#aaaaa#aba#accbbbbaaaaaaaacbaaaaaaaaacccdccc##abaabbaaabdbabbcccdffffhggbaaaaabdbaaaababbaaaaa#a#a#aaaaba#a#a################aabaaaaa###########.#####...#####.##.####aaaa#bedcccaaaaabbaaaaa##a#####aaaaddaabdebabbbbbabbbbgcaa#a#aaaa###aaabdaddabaadcfdfgdacbaabcbbbcccbdcdffdacdcedccbbbacbbbbcccccbbbbabacabbdgigbbgjjedcbbbccaaa", +"#bbbaaaaaabaaabbbea#aaa#abbbbabaaaaaaaaba#############b####aaaaaabaa###abbbbbaaaaaaaacbaaaaaaabbcccccdd##cbcbcaaaaaaabcdeffgggiigabbbbbaabcaaaaaaaaaaaaaa#aaa##aaaaaaa################aaba###baaaa#######.#####....#########.#a##aa##a#adfca###abbaaaaaaa#####a####bdbacfdaaaaaabbaacedfa#aa#########abefeddcccdebccfggfedaaccbacddecdccdeddccefddcccccccabaabbabaabbaabacbbhijgdbacfkjeedcba#a#", +"###aaaaa#abbaaaaaaa#a####bcaaaba###a#aaaa######a####aa######aaababaaaa##aabbaaaaaaaaabcaabbaaaaabcbccccbcbaaaaababbcccdefgfgghkgbaabbcbccbaaaaaabaaaaaaaa#aaaa#aaaaaaaaa####a########aaabba#aaaa#####a#.###.######.#####.####.##a#abaaa#aaddaaabbaaaaaaaa#########aabgggfbaaaaaabbbabbcfea#a#####aa##afghhfggghhgccddffhfffcccbccdfgeeeceec#aabcddcdddccebaaabaaabaaacbbbb#ejhjgbbceceikibbceba#", +"aaa##a#aabbabbaaaaaaab####bc#aaaa#aaaaaa#ab##aaaa##a#aa######aa#baaaaaaaaaaaaaaaa#aaaaacbaabaaaabbcccccdbaaaabbbbccddeeefeegjheb#a#aabaccdcaaaaaaabbabaa#aa##aaaaaaaaaaaa#######a###aaaabba#abaa####..###.###.####..#####.#######aa##ba#####bcbaaabbaaaaaa########abdfggebabaaaaaabbbbbchfaaa######abbfegggefgghgffeecefggfhheecdddeeefdcefcabaabccbaabcbcbaaaaaaabbabbbbbbfghggdbcbcbbgkjfbbecb", +"#aa#a###aababbbaaaaaaac###.acaaaba#aba####ac#aba###aaaaaaa#aa##a#a########aaaaa#aaaaabbbbbaabbaaabbbccccebaaaabbccddddedegggfhbaaa##aaabcccaaa#aaabbbbcbaaa#####aaaaaa#aaaaa#####a###aaaaaabbdaaa########...##.###..########.#####aa#aba###a#accbaaaaaaa#######aaaaabccdeeccbbaabaabbbbegfgeca#####adefffefgggfghggfeeccegihijigedbccfeceddfeaaabcacbbaaabbaaabaaaabbbbbcbchgghfgdabbaa#bgkjgcdd", +"d#a#a####aaaabbbabaaaaaa####abaabaaaaaaa###acdbaa#a###aaaaaaaa###########aa#a####aaa#abbbbbaabaaaaaabcbccdaaaaabccddeefefhgefgbaaaaaaabaabbaa##ababbaaabcca#aa#aaaaaa##aabaaa####a####aacba#bcb#aa#.####.#...##.##..################a########a#adbaaaabaa#aa##aaaaabbbcdeddddcbabebbcbbffeefdec##adeeefeffefghgghghhgfedfheabfghhfdcegecbbbbccaaaabcaaaaaabaaabaabbbbabbcdfffgffffabbbbbcabgkjec", +"cdaa##aa#aaababbbaabbaaaa####bbabcaaaaaaa##.acaaaaaaaa#aaaaa#ba###########aaa#a###aaaababbaabaaaaaaaabcccdgbbbccccddeffefgfeffbaa###a#aaaaaa#aaaaaaabbbccaaabaaaaa##a###aaabfd#####aaaabbaba#aa########.###.##.###############################bacedcbbbbabaaaaaaaaabcccccddedddbbdeecdefeededdeeffdegffeddefgfgggggcb##abbca###bbefeefeddcdcbeeaaaaab#a###babbbbbababcbccfgfeeefegcbaaabbca#afkh", +"gdcbaaaaaabbbaaabaaabbbbaaa###bbcbaa#aaaa#####a###aaaaaa#aaa#aaaaa##a#####a#aa#aa#a#aaaabbaaacaaabaaaabccdfgddddddccdfhhffddfbaaa####aaaaaaa##a#aaaaaabbdb#aaaaba#a#######aacegdbaa#aaabaabbb########.#.##.##..#...####.#######################babedededcbaaaaaaaaabccddeedefecfffeeffddddddeddeeeddeggfddeeffbaaaaaaaabdb#baa#a##cbdfeaaabbcdfbaaaaa####a##abbbbaabbbbdcgfgeeedeefabba#aaaaaabg", +"gjgccbaaaaabbbbbbbbaacbaaaaa###aaaaaaaaaaa####aaa#####aaa##aaa#a#a#######aaaaaa##aaaaaaaabba#acaacbaaa#acccfgdefefcdecfhhddbcaaa#a#####aaa#aa###aaaaaaabbeebaaaaaaa####.###aaacdcbaaaa#aaabba#############.#.#.#...###########..###############aacddeeededceeedccefggfgggfedggghfdfecdddccccddeeeeefddfffddddbabbbaaaaabefcdb#aa##aaabcaaaaa#bdgb#abaa#######ba#bbaabaaeegfgfeeeecfcaaa#aa#aaaa#", +"#bgifcbaaabbbcbbbbaabbbaba#a#aa##aaaaaaaa######aaaa##a#aabaaaaaaaaabaaaba##aaba###aaaaaaaaabbabbabaa#a#abcceffeecb#cddeeggcdb##a##aa##aa#########aaaaaaa#bedaaaaaa##########abaa#aaaaaa#aaabaa#####a####################..######.#a##.#########aabcccbcda##afgggffdbbbabdhheghifedddeecbccdcdefffeeffdfggfdbaaaaa#aababbacdddb#bb#aaa#a####ababbdebbbaaa####a#babbaaacddfgffeefeeddcbabbaaaa#aaa", +"a##ehiecbbbccdccbbbbaabbaaa#aaa##aabaaaaaaa####aaaa#####aaba#aabcbbbaabbba##abaaa######aa#abbacbaaaaaaaaabcccdfcaa##bbbbceabaa######aa##a##aa####aaaaaaaa#abaaaaaa###a######abbbaba##aaa#a####aaa###a############.########################a####aa#dcddcdb#a#dedeedcaa#baacgegiifedddddddcdddefeffggfgeedbba#aaaabbaabaaaaabceebbdaaaaa######aaaaabdddb#aaaaaabacbbbaabdfffgfgfeeeeddgcbaaaaa####", +"#b##adiifdbcefedccccbaabaaaa#aaaaaaaaaaaaaaaa##abaa######aabbaabbcbbaaaaaaa#abaaa#######aaaaabcca#aaa##aaaabbccc#########a###aa##a###aa########aaa##aaa#aaa#aa#aba##a#######aabbabcaa#ababbca##aa####a#####a.#########################a###a##acba.ddeecccba#cfeeedcaaaaabccbaigfeeeddddcbcdcddfeffggeedaabaaaabaaabbabaaaaa##cffedeaa#a#aaa#aaaaaa#abfebabaaaaaacadcaaffecffffgfffeeggaaabaa####", +"#caaa#.ahjgffefgggffecbbbabaaaaaaaa#aaaaaaaaababaa#aa#a#aaaabaaaacccaaaaaa#a#aaabaa######aaababaaaaaaaaa#aaaabccb####aaa##ab###aa#####a#a####.#aabaaaa########a##aba########acbbaaaaaaaaaabbbaaa################a###a####aa############aaccb#adcbbdddccbcdebdedccba#a#aabdcbaggeeddedcbbbccdeeffffhggfcbaaaabbbcaabaaaba####a#debceea#aaabaaaaaba#aaa#cfgcaa##aabcbcbdffedfeeeefefeedhcaaaa#a###", +"####aa##.behhgfeeeddefedbbbbaaabaaaaabaaaaaaaabaaaa#aaaa#a#abbaaabbcbbaaaaaaaaaaaba####aa#aaabaaaa##a#aa#a#aaabbcc.##ab##aabca##aaaa############aabaaaaa#a#a#####aaa#bb#.####bccbaa##aaaa###aaaaa######a#######bbabba####bb###a#a###a###bcccccdcdccddcbbabcdcddccba####bdddb#bdcecdedcbbbbbcceeeeehhcdaaaababcbcaaaaabaaa#####ab#aabb###bb##abcaa###a##adfeba###aabaaefefffedddeedefefhbaaa###.#", +"#####aaaa###chikjiigedcegcccbabbaaaaaabbaaaaabaa#aaa#a#a##aaaaaaaaabaa#aaaaaaabbbaa######aaaaabaaaaaa##aaba##aaabab.###aaaaaabaa#aa#a#############a###aaba########aa#cbb####abcbaaa##aaa#a######a#.####aa###bbccbbdccbaaabb###a#aaaaa###cbbbaccccbbcccaaaabbccccbbaaa#accdcb##bacgeeedccccbccdeeefggebdaaaaabbbbbbaaabaa#####a#a#aa#####aaaa##ca#####a####beeca#b#abadgefffedeedfdcffeff#a#a###.", +"..######a#aaadd#acdhihecdgecbcaa#aa####ba#aaa##aa##aaa###aaaaaaa##ababaaa#aaaaabbbaa######aaaaaaaabaaaa##baa##a#a#b######aaaaaaaaa#################a#aa#bcb#####aba##a######bbbcbaabcaa#################a#abcdbdefededcbcbaa##aaa#a###bcbababbccbbbbbcaaaaabcccbaabaaaabcdbba###bhhfhgeddccbccddfhhhfbbaaaaaabbbccaaaabaa####aa#a#####b####aa#aa#ab###a##aaabefd#a#abbfgfeeeeeedeeddefggbaaa####", +"##.######aaba#abaaaabeiiebceddcbaaaaa###aaba#########a##aaaaaaaa###aaaaaaaaabaabbbbaaa###aaaaabbbaaabbaaaaa###a###bb#####aa###########a######a#####aa#baaaba##abcedcbaa##a##bcccbaaaddccaa##############a##bbceffgfededdedcbaa#a#aaa#bcabaaabbbccbbbbbbaaaabbcbbbbaaaaabbcda#a##ehgfeeeeecddbcddfhhgcbbbbbbaaaabcbbbaaaaa###.#a#a#a####aaa###aa##a########aabbbedbacfegggfeeefeddccddgihdaaa####", +"##.###a####aaaa#bacbaa#chidccdfdbbabaaa#ababaaa###a###aa#aaaaaaaaaba#aaaabccccbcccccabb###aabaabbbcbaabaa########aaab.####aaa##################a####b##aaaabb#aacdddcbb#######bccaaaabdbba#####aa#a#########abccccccddcffhigcbaaa#aa#acaabaabbbbaaabbbbbaaaabbbbaaaaaabcccdda#a#higheddefedeecdffffeeaaabbbbaaabcbaabaaaa#########a####aaaa######a#######aaabdcbadgfdeddegfgfeedcccccehigaaa####", +"###########aa#####aacdb##ejgcbbfedcaaaaaacbabaa#####aaaa#aaaaaaaaaaa##abbbbbbaaabbcddddbccdcccbababaaaaaab#########aba..####aa###################aa########aa##aaaabbbba##a####ccaababdaa#aa#####aa##########aaaaabbccdfgjjihdcaa#aaaacbaabbababbaabbbabaabbbbbbbbbbbbbcccddebadhggfffeeffffeeeffdccddaaaabaaabbabbbbaaaa######..######aaaaaa#a###a#aaa###aaaccc#ceggedddcffffedcbabccdfgebaa###", +"#########aabaaa####a#aabbachjgbacdedcccbabaaaaaaa#####aa#######aaaaaa#aaaaaaabaaaabbccdccddcbbbabaaaaaabbaa########aabb.#######a##################aaa##########aa##abaaaaa######bbaaaaba#a#a#.##.#a#aa###aa###aaaaaabcddgijijjigeba#abdcbbcdcabbbbaabbabaaabbbbaaabbbbbcacddee#dfeeeffeccdghhfffebccccaaaaababbbbaaabba#a########.###a##aaaa##aa##aaaaa####aababbddceggfedcdffedcbaabcdeeffaaaa#", +"#######a#aaaaaa#a#####aaaabcdiibaaacecddcbaaaaaaaaaa##aaa########a#aa###aaaaaaaaaaaaabcccbbaaaaaaaaabaabbaaa######aaaaca.###.##a#a####a########aaaaaaa##...###a###a##a#aaaa#####bdaaaaaa########a########a##a##aaaaabbbbegfeedeghgeccddeeefgcbbaaaabbbbaaaabbbaababbbbcccbceeebegdddeffedbdeiihecbcbdbaabaaababcbbaaabaaa#a#.############aaaa##b#a##aaaaa##aabbbbccdceghgeddefedcaaaaccdedfaaaa#", +"########bcaaaaa##########aaaa#gidaaabedcccbbbaabdbaa####aba#a#############aaaa###aaaaaaacbbaaaaabbabbbbbcbbabaa######aabb..##.####aa#aaa######aaaaaaa####a#.####aa##ba#aaaba#####dbaaaaa######aaa#aa######aa###aaa#aaabccebabaabbdfhhhgfghggdbaaabbcaaabbaaabaaaaaaabccccccedchigdcdddcedccabghdbaaabcaaabaaaaabbbbcbbaa##a########a##.#aaaaaaaaa#aaaaaaaca#acbbbbbcccdefeddeecdcbaababcfdfeaa##", +"########baaaaba#aaaa#####a####aciib#aacdddbabbaabbb#aa#####aa#############aaaa##aaaabaaaabaa##aabababbbbccbbbcb#######aaaa#...##.#####aa########aaaaa######a############a#aaaab##abbaaaa#######cb############aa#aa#aaaaabaaa#######bfhigihhfbaabaaaaaabaaaabbaaaabaaaccbccdcchiihhdbcddcddccbbeeaaaabbbaaaababaabbbeeeaa#####.###.aaaa#aaaaaa#aaa#aaaaaa#bbadccbbbbccccbcddddcbcccbaaaaddddge###", +"########a##abbaaa#########a#aaabcfjhaaabcdecaabaaaaaaa#######a########a#aa#abaa#####aaabaabaa##ba#abbccbaccaaca########abcb..######################aa###ceb#######aaa#####a#aaa###acaa#aa#######b############a#a##aaaaaabaa########abacfhhfcbbaaaabaaabaaaaccaaaaaaaacbcbbcffgfgcegeddeddcdccbcd#aaababbbaaababcaabaaccba########a#abaa##aaaa##aaaaaaaaaababcbbbaccbbcbccdddcbbbcbbcbbadcdeehd##", +"########bb####aaba#########a####aabfjfbbcbcfdbabaaaaaaba######aa######aaaaaaaaa##a#####aaa######aaaabacbbaaabaa#########aadc...#######.##########aaaaaa#ddeb#a####aaaabeb######a###bbaaaa##b####aa#.##########a#a#a#aaaabaaa##b###.adbaabeecbaaaaaababaaaaabcabaaaabbbbbcdcfgeddgbbggeedddcccccc####aabaaaaabbaabaaa#acda############aaaaaa#aaabaaaaaaaaaabcbabbbabcbbbbcddccbcbbbabbbbccdfggf#a", +"aaaa####bc##a#aaaaaaa###.#####.####aciiecccbceebaabbabbb######a#a####a##aaaaaaa########aaa#######aaabcbbabbaaaaa#########acfc..####.#.###.###aa###a#a#aaabcaaaa###aaaa##########a##bdcaaaa#ba###baa##########aaa####aaa#bbababdcbaacbbbaaaabbaaa##aaaaaaa#aabbbaaabbbbbbcdcccddcdec#adfedddcccbe#####aaaaaaaaaabbbaaa#bdb##.#######.####aaaaa###aaaaa##aaabccbbbaababbbbbcdccccbcbbbcbbbdcefghc#", +"########a#####aa#bbaaaba######...####adhifegfddfdcabccbaa###aaaaaaa######aaaa##aa##a###b##########aa#aaaaaabaaa######a###abdfb..#######.##.#####aaa#a###baaa####aaa#########a####a#bddcbaaaa####aaaa####ad##aaaaaa#######abadddccccdcba##a#ababa###aaaaaaaaabaaabbbbbcbbcbbccdccbaba##afedddccbfa######a#aaaaaabbabaaaaab#####.##..#..a###aaaaa#aabbaaaaaabcccbbbabbbbbbbbddccbbcbbbcbbcfdeeffha", +"##############aababaaaa##########.##.#..chjjhjifffdeccdbaa#aaa###aa#####.##aa#######.#######a#########aaaaaaaaaac########acchc.....#..###########aa##aa#abaaa##aba##a######aaaa##a##bdcbaaaa#####a#aa###bd###aaaa#aa##a####adgdcbbcddbb###aaa#a#####aaa##aaa##abbaabbbbcbbbcccddeccc#a#bhggfedaec##########aa#aaababaaaaaa#####.##.##.####aaaaaaaaaaaaaaaabdcbbbababbabbbabddcbbbbbbccbbdifdefge", +"a###a##########abb#aaab#a#######...#####.##a#acgkigfeefdcaaa##aa#aaba####..######.#a###a#aa#aa##.#######aaaaaa##ba#####aaabbeha...###.###.#######a##aaa#aaa#a#aaaa###aa#a###aa###a###cdcaaa######a#####abb####aaaaa####a####deebbbccdbba##aaa#aa####aabaa#a#aabbbaaaaabcbcbbccbcedbba###cdffffeefba###########aaaaaabcaba#####.####.#######a#aaaaaaaaaaaaacdccabbababbabbaabcccbbbbbbbccdeeedefh", +"f#######aa##a##aaa#aa#bba#########..############afkjgfgfeeeba#aaa##a#######.####.#.#####abbbaa##########aaaa##a#a#######abbcdhe#...######.##a####aa#a###aa#a#aaaaa######aaa###########bdbbaaa####a######aa##.##aaab####aabdecdcbaabbbaba##aaa#########abaaa##abbbaaaaabbbcdbaccbcebaa####adghfedeeba#############aaaaabbcb##########.######aa#aaaaaaa###bcdccbbabbbacbaabbbbbbdcccbbbbbcccccddeh", +"hc#####aa######aa####aaaa#####a###.......##aa##a###gijhhhggeb##baaaa####...#####.#..a###acccaaa##########aa#####aaa####aacdddhf#..###.#..####aaaaaaaaaa###a#aa#aaaaa#####aabb##########cecaaa####a##############aabb##aabacddbcbbabbbaaaaaaaa##a#######baaaaa#abbaaa#abbbabcbbbcdgd####a##adcgfecdeb######a########aaaa#baaba########.######aaaaabbbbbbcbccbbbbbbbbbaaaaabbbbbbccbcbbbbcccccdeed", +"egb##baaaaa####a##aa#aaa#a#######.#..###.###########adfilkhfca#abaaa#####..##....#....###bbccaa##a##aa####aaaaa##a##a##abbcfhjfb#..#####.######aaaaaaa######aa##a#abbbba###aba#aa#######cecaaaa###a#.#######aa##aa#aa###aaabcbcbbcbbaaabb##aaaaa#######abaaaaaabbaaa#abbbbbabbabdfeaaaa##a#ca#eecccfcaaaaaaaaa#a#a######aaaaabca########a####aaaabababbbbbbbbbbbbbbbaaaaaaabababccccbcccdccbdffd", +"cfhd#acaaaa##a#######a#a##a###a##.....######.##########bddjkidca#########..###....######acaacbbb#a###ab##aaaaaaaaaaaaa#aabcfgejfa#.###a######a##aaaa#aaa#a###aa##a#abbcba#####aa####a###aeedbaaa##aa####...#aaaa#bcaccbaaaabcdccabcbbbaaca#aaaaa#########aaaaaaabaaaaabbbbbbbaaabbecbbcaaaaaa#adecccedcaaaaaaaaa##a###########abaa######a####aaaabdbbbbbbbaabbbbbabbaaaaaaaabbaabccbccbccdccdefg", +"fedfea#a####a##a#a#######a####a#.##..#.####...########aaaaaeikhea#####################aaacbabbdfdbbaa#aaabbcbbaabaaaaaaabcdfbbeica..#a########aabaaaaaba#a###aa#######aaa#####aaa#.aa###adffdbaaa##ca####.#########abbcdeeeefcdcbabbbbbaacbbaaaaaa##a##a##baa##aa###aaaabbabbaabaadfb#bbbbbaa###feccbeecbbabaabaaaaaaa#aa###a####a########a##aaaaabbbbbbcbabbaaaaaabbbaaaaaaabbbabccccccddddeeee", +"fggehdaaa######a##########aaaaa#.##.####..#..##.#######aabbaadjljgda.#################aaaccbccddcccccccccccccdcbbccbcbaabbcfdcbgf#...#aa######abcbaaaaabaaaaa############.##aa##a########dffedcbaa#cc##########a####bbbbcdffeedaaabbbbbcbabbaaaaaaa#######abaaaaaaaaaaaabbabbaa#a#bdcbbbaaaaa###cfeeehhecabbbbbbaaaaaa##aaa##a###a########aa#aaaa#bbcbbbabbbbaaaaabbbbbabaaaaaaaabbbbbcccddddeee", +"edehhg#aaa######a#a#####a##abbaa###.###################aaabbcaacjllkhbaa#######a######bbaefddddcbbbaaaababefeedddccffdccdfgeeeefec#...#ab#.####abccbbba#aaaaaa###########..###a##########bfdfdccaaacfb.######aababaaaccccbdffebbbbcbbaacccbabbabaaaa######aaaaaaaaab#aaabaaaabaaaabbeffcaaaa####aeeeefiihfcabbbbbbabaaaaaaaa##a######aaaa####abbabbabcbaaaaccbbbbbbbbcbcaaaaaaaaaaaacbbcdddddede", +"eefgghcaa#######a##aa######abbbcc#.############.###a#aaaaaaaaccbafjllkjecbaaaaaaaa##aabcccgefeecccbba#aaaa.acffffffcacdccbbbfffefda#.##########aabcedba##aa#a#####a#####..#####aa###.####bceecccbaabdfa##aabbbaabbbbdcbbccdcceebabbbaaabcdcbbbbbaaaa######a##aaaaaaacaaaaabbaba###acdeegcbbb#####aeffgfgijkgcbbbbbbbbabbaaaaa##a#aaa#abaaaa##aacdbabbccbaaa#bbbbaabaabccbaaaabbaaaaabbbccdeedddd", +"deeffdfd#####a######a#######aaaca#a############bdca###aca##aaaceddfijjnligdcbbcbaaaaabcddchgedddbccaaa#aaaaa##accfbbbaa####bdhfedhd#.###########bbcccdba###aaa#####a##a#.#####a####.####.#abedebdcbbcfe#####adcbcddbbdbaaacbcbccbbbaaa#bbcbbbbbbaba#a############aaaaaaaaaabaaaaaaabdfcccbbba#####aceffgiijihedccbbbbbabbaaaaaaaaaaaaaaaaa#####aabaaabbbaaaaaabbaabbbbbcabaaaaaaaaabbbbcccdddddd", +"ddddecbdca###a###a##baa#aa##abaaba#a###.#####.#aabaaa#aaa##aa#acdhilmklmlmkheegecbbbbccbcefgedcdcbbbbaaaaa#aba#a#cdabcbaaa#achihggfa############abdb#bcaa##aaa#########a###.######..########beddecbcdffc###.#acdfffdabcca#aabacbbbbbaa#abbbbbbbbbaa#############a#aaa#baaaaaba###aaadfd#babacababbbcegfhhiihgfdddcccbbbaabbaaaaaaaaaaba#aaa###a#aaaaaaaaaaaabbabbaabaaabcbbbaaaaaaababbccdddddcd", +"deddddcacaba###a####aaaaaa#aaaa#aaa###aa#########a##aa#aaa##aba#.cfehhjkjllmllihfedcccbbdefgdcccecbbbccbaaaaaaaaabdbbbcbaaaabhjjhggea#.####a##a#accaa#cdaa#aaa#.#############a##a##.###a####.cedccccefbbaa#####deffeaacdaaaa#aabbbbbaaaaaabbaaabbaba#####a.###a###a#a#aaaaaaa#a##aaacdecaaaabaa#aa#bdgfeeefhhfdccccddcbbaaababaaa##aaaaaaaaa###aaaaaaaaaaaaaaaabbaaababbbbabbbaaaaaabbbbcdcdccdd", +"dddcccdbbbcba#bb#aa###aa##a##a####a##.####aaa##a#aa##a#a#ba######.fffkjlhkkljmmmlieeddccefaeeeccdedbcdccbcbaaaaaabaccbccaaaabeijjigieba.#######aacbaa#accaaaaa##########a#a###aaa#############decabdeeeaba###..adeddcaabcbba##aabbbaaaaaaaaaaaaaaaaa#####a###########aa#abaaaa##a#abbcdeba#b#aa#####cefedcbbdeedcccdddcbbbaabbaaaaaaaaaaabaaa###aaaa#aaaaa###aaaaaaaaaabbbaabbcbaaaaaabcccccccdd", +"ddccbcccbcedaddaaaaaaaaaa#aa#a######...###########aaaaaaaaaa####..cfhjjkmlmklkklmnjfeedeefebdeddegheeedddccbbbaaabbccbcbbaabbbgjkjjhifda.#######aaaaa###abaaaa####aaa###########aa##########..adccaddcecbabbaa##dedddcbabcbca#aaaabbaaaaaaaaaaaaaaaaaa###############aabaa##a####aacbcddebaaa########cffecdcbceeefdddddcbbbaabbbaaaabaaaaaaaaaa###aaa#a#aaaaaaaaaaaaaaaabbbaaaacbbaaabbbbcdcdccb", +"cdcccccbbcdbaacbbbbbbaaa#aa#aaaa#####..#..##.#####a#aaa####aa######eigfcfgijjjlmmmmnlhfhiggdddeefgegfgffdeddcdcbaaccccbcbaaabbcfjkkkijgfb#######a#aa######a#############a###aaaaaba############abcc#ddcccbdecdcaddddddecbbbccaa###aabaaabaaaaaa#aaa#########.####a##a##a#aa#a######abccdgbb#ba#a######cffgfdefffehgdddeccccbaabbbaaabbabaaaaaaaaa###aa##aaaaaaaaaaaaaaaaaaaaaaaabbba#aabbacddccc", +"cddcccbbcccaabbabaacbaaaaa#aa#aa#.#...#...#..###a###a#########aa##adeaaa#abedefijlkmnnlkkjdddfdcebb#degfaefgfeddcbdcddbacbbbbbbdjjklkkihgc#aa#####aa################aaa##a#aaabaaaaa###########aabdbedcabdddeeddddedcccddccbbbca###aaaaabba#a#####a#a###aaa###.###a#######aaaaa###aabbbbcdaaabaa##a####aeghhhggghhhfedddcccccbbbbbbbbbbbbbbaaaaaa####aaba#aca#aaaaaaaaaaaaaaaaaaaaabaaaaabbbcddd", +"dddcccbbdedaabdaaaabbabbbbaaaaaa#.##.##.#.#####################aaaddbbaa#aa##a##aceejnllkkhfhfccfbbaaaabafabdeffgfcdddcabbbbabacgjkkllkhjhbaa#####aa############a##aaaa###aaa#aa#a#####.####a##aa#deedcabdeeeedeeddeedbccdcccdcb####aaabbbaaa#####a##a##a####################aa####aabbbcdea##a########aaabehiiiiiihfedfdccccccbacbbabbbcbbbbaaaaaaaa##ab##bbaaaaaaaaaabaaaaaaaabbbaaaaaabbbbbdd", +"ddccdbcbedcaabbbbaaaaaabbababbaa#################a##########a###a#ecbaababaaaa#####abkllllljgbaaccbababbabaaaa#cedfheedcabbbbbbbchkkkklkhggeba###aba####.####a####a##aa##aaaaaaa##aa####.####a####dfdcba#bdeeeeeefedddcbbcdbbadcba###abaaacaaa###a##a###aa#####.####a######.##a####abbbbccbbc#ab##a#aa#ca###cfggihhihffffedcccccbbabccccdccbbbaaaaaaa#aa#aa#aaababaaabbaaaaaaaaaaaaaa#aa#abbcccc", +"dedcccbcecaaacbababbbaabbbbbcbaaa#..###.#########a##############.cdabbbbbbbba###aabcddilmmljeaaabcbbbbbbbbbbbabaabcefgfecbbbbbbcdfjjkkkmkhfgecbaaabb########a######aaaaa####aaa###################befcbaabbadfeeeeffededcbbccabccccaa#aaa#abaa#######a########...###########.##..###abbbbcbbf#aa###abaa#a#####acfgffgfggefddcccccbbabcecbbbcbbaaaaaaaa##aa#aaaaababbbabbbbbcbbabaaaaa##aaaaabbcc", +"cddecccccdcaaaaaabbbbaaaabbbbaaaa########.####################..aaababaaacbba#abddbcdfeejmllf#aabbbaabbbbbbaaaaaaa#afffdedcbbbddffjfijjkkkhgfed####aba#######a####aaaa#aa#####a######a############adffddcaa#befefedeeddccccbcbaacbaabbaa###aba####a###############.###########.######aabcddcefbb###bbaaaaaabba#cffffghhgfffedccccccbcbbebbbbbbbaaaaaaaa####aaba#aaaabbbbbbcbaaaaabbcbaaaaaaaabcc", +"dddddfebdfeba##aaaaaaabbbbabaaaa####.#########################.abbaaaaaaaaabbaaabba##aceeilmme#aaaaaaaabbbbaaaaabbbbbefgeddcddddegiighiiggjggfdba##aaaa##############ba#b###aaaa#######a##a#aaa####dfgffgcaabefeeededccccdddcbbbbbaaacbab###aaaaaa########a#a########.#########..####aaabdcdecbdc#aa###aabbcccaacegggfgghggfeeeddddcccbccbbbbaaaaaaaaaaba#aaaabaaaaaaaaaaaaaaaaaaabbaaaaabbabbbc", +"bcdeeeeedeeda##aaaaaaaccbbaaaaaaa####..##.#########a##########aaaaaaaaaaaaababba#aa####abbdhkmgbbbaaaaabbabaaaaababbbaehfcdeeeegghkkjjigdeehfeccaaaabcba########a####aaa#####aa####a####aa###baba##adfgfffdeeffdcddddddbcccdccbbbbbbb##bdb###aadb#a##############.##.######.##########abcdcedecegdb#a#aaabbcddaa#adfghfghgffefeefeeddcccccbbcbaaaaaaaaaaa#aa###aaaaaa#aaaab##aaaabbbabaaaabaaabb", +"cbceeeefffffd#aaaaaaaaaddbaaaaaaaa#############.#############cbbaabaaaaaaabaaaaaaaaa###aaa#achlkigdaabbabbbbaabcaacaababccdbbdedcdfehkkjgeceheccda#aabbba###.######a#aaa#####aa######.#a#aa##aa#aa##adgggfeeggffdcccddcccbbcbccbbbaaa####ca##abcba#aa##########.#####a######.#.#######abbcbddbdfhgeaaa##abbcdcaaa##aaceghdfgffffffeeddddcccbbbaaaaaaaaaaaa##aa#aaaaaaaaaaab##a#baabbabbbaaaababb", +"ccddefgfefffd#a##aaaaaabccbabaabaaa##########...############acbaabaabaaaaaaa#aaa#aabaaaa#aaaabgkjiifbabbabbaaaabaaabbabaaaaaaabcc#####cgkmjgfhfcbcaaaabcbaa########a#aa###a###########.####a######aa##bghfefgeddeccbbbccccccbcdcaaa#a##a#aa#a#aaaacbaa##.############aa########.#######bbbccddddggfbaa###abbcbaaaa#aaabeeeeggghgggffeedcccbbbbbcbaaaaaaaaaa###aaaba#aaaabbaa#a#abbbbbbabdbbaaaab", +"bcceddefhgfcbaa#a#aaa###aaabbbaaaaa#######################aababaaaaa#aaaaaaaaaaa#aaaaaaaa#aa###cefllgabaaaaabbbaaaaabaaabbabaaa#ba######bfjljhghcac##aaacaa########a###############aa#.##a#############afgfgfedcccccbbccccccddcccaa##a####aa#aaaaaabaa#################a#a##.#########aaabccccddeegfbaa###abbaaa#aaaaaabdfceghhhhhhgfedddcbbbbbbbbaaaaaaaaaa###a##aaaaaaabbbaaacbbabbbbbcccdaaaa", +"bbcccdefhiea###a##aaa######aaaa#aacb##############a####aaabcbbabbaaaaabaaaaaaaaa##a#aaabaaaaaaaaabekljbaaabbaabaabaaaaaaaabbaaaa#a#aa#####aekkhhiba###aabbbb#####a.#########a#a#####a#######aa####.#aba##gggfeedccbbbbbbcbaabccbcbaa##a###aa##abaaa#aa###..###########.###a##.#######aaaabbbcdddcefgaaaaa##abaabaaaabbaabdeffghighhgfffeeccbababbbbbaaaaa#aaaa#a####aaaaaabbaabbbbbbbcccbcccdbaa", +"bcccccdefgeaaaaaaaaa#a#a#a##aaa#a#aba#######a#.###aa######bcaaaaaaaaaaabaaaaaaaa###aaaaaabbaa#aaabbchkkc#aaaaaaaaaaaaaaaaaaaaa#a#aaa#a#######dkklibca#aaabcdca#a#aa#################a######aaaa######aab#cghhgfddcbbbbaabaaaaabbca##a##abaaa##abaaba#a#aa############...##.###.#..####aaacbbcdccdcdedbaaa#a#acbaaa#aaaaaaabcffffghhhfggfeddbcbbbaaaabbaaaaaaaaaaa#aa#aa#aaabbbcccbbbbbbbbbbcdccb", +"bbbccccdfcec##aaaaaa####a####aa#aa#aca##a####baa#######a##bbbaaaaaaaabbbbbaaaa#aaaa##aaaaabbba#aaaaaadijgaabaabbaaaaaa###aaaaaaaaaaaaaa#######behlidcdbaaabbcecaa######a###aaa###########a####a#######aaacghihgfedcbaaaaaaaaaababbbaa###aaa####a#aba##a#a#####..######......#...#.#.####aaccbcccdcdehhdaa####bcba###aaaaaaabaaadfeeegihgecdedcbcbaaaabbaaabaaaaaaa##aaaa#aaabcbbbccbbbbbbbbbcbbb", +"babbcdddddde######aaa###########aaaabda##a####abaaa#####abbaaaaaaaaaaaaaaabbbaaa#aa##aaaaaaaaabaaaaaabcdkib#aaaabbaaaaaa####aaaaa#aaaaaa##a##a##acgjhfgefcbbacccbaa####a######aaaa########a#############bfffhjigedddbaaaaaabaabbbbccaa####aa###a##aa#################a##.....#..#########aabbbbcccddfheaaa####bba####abba#aaaa##bca.#bghfedecbccbbbaaaaaabaaaaaaaaa#a#aaaaabbbbbbbbbbbbbbbbbbaba", +"bbabbdcdddcec#####aaaa#a####a###abaaaaaa##bda##aaa######aaaaa#######aabbbaaaaaa##a##aa#a#aaaaaaaabaabacbdjjbaaaaaabaaaaaa##########a#aa##aaa##a#a##cfhhededabbdcbcca##########aaaaa############a######a##dffgjiiheedcbaa###bbaabbbddba#########aaa####################a###..###..##..###aaaabbbbcbcfffebaaaa#aabaa##a#aaaaaaa#####aa#.bdegfeccbbaabbaaaaaaaaaaaaaa#aaaaaaaababccbcbaabbbbbbcbbab", +"dbbbbcdcdcdcea###a####a#aab#aaaa##aaaaaaa##a####aaa###.##aa###########aaaabaa#aaaaaaaaaaaaa#aaaaaaabbaabbbhkfcaaaaabbaaaaa##########aaa###aaba######.ekjgddbabbaabccbba########aaa####.#######aa##aaa#####dgfgghgggedcbbaaa#aabbbcbedba#######aaa#a####################aa#.......##..####aabbbbcbcdefeebb#aaa#aaa##ab###aaa#######a###.##cgefdccbbabbbaaaaaaa#aaaa#a#aaaabbccbbcbbbaabbbbcbccbbb", +"bcabbcceffabbc########aaa#aaaaaaba#aaaaaaaa########.#####aa######aa####aabbbaaaaaaa##aaaaaa###aa#aa#aaaaabbfkjhdaaaabaaa#aa##aa#####aa#a#a#aaaa######aikjjhbaaabbaacbaaa###############.###################bfhggggggfedcabaaaaabbcdeccaa########aa##########aa######a#a##a##..#.#...#####aabbbbbcccecdgccb##a####a##a############aaa######agfedccccbbaaaababaaaaaaa####aabbaaaaabbababbbccccbbcb", +"ababbccdffdbbbba###aa#aaaaaaa#baaaaaaaaaaaa#########.####ab###########aaaaaaabcbbbaa###aaaa#ba###aaa###abbbbflljeaaaaaaaaa###########aa##aaaaa#######.afikkiba#abbaaba##########a############################ehffgggfeedcccbaabababcccbaa######aa##aa###.###aa####...#########...########abbbbcbbbcdecfgdaa#######################aa##a####bfeeddccbbbbbaaaaaabaaa#abaaaaaaaaabaaaabbbbbbccccccc", +"adbbbbcdddecbaba#a#######a#a##aaaaaaaaa#aa##########.###aac##########a##aa#aaaabcbbaaaa##aaa####aa#aaba#abbbbdillhcaaaaa####aa####aa#aaaa##aa#########.#chkli#aaaaabbaaa########a#aa###a###############.###aa#fggffgffedeecbbbaaabbbbcbaaa#####aa###a############################.######aababbcbbbccedcfccaaaaaaaa###############.####a#####bffeddccbbaaaaaaaabaaa###aabaaaaaaaaaaababbbbbbbcccc", +"ccbbccddeeeccaaca##a####aaaaaa##aaaaa#a#aaaa#########.###ab####.#a###aaa##aaa#aaaabbaaaaaaaaaaba#abaaaaaaaaaaachkklfbaaaa##########a##abaaa############..#bimiaaaaaabaaba##########aa#babaa##############.##a##aegfcbdeedfedbbbabbabbcbbbaa#####a#####aa######################.#########aabbbbbcbbacddddccaaa#aaaaaa###a#####################afgeecdccbaaaaaaa#abccbaaaaaaa#aaaaaaaaaaaabbbccbcc", +"ccedcdddeeeccbbbcba#a###aaa#a#a#aaa#####aa#a#############ab#####.#####aa#a#aabaaaabbbbabbba##aa###acb#aaaaaaaaacfihkida##a#a###.####aaaaaaaa##a###aa######.ahljc#abaaaaaaa###.####a######abaaa############.#####.bababeedegdcbccbcbabaaabba#a##aa####aba#aba#a###################.####a##ababbbcbbbcdddedea#aaa#a####aa#######.###.######a##a##fgfedddbbaaaa#bcdccbbba####aaaaaaaabbabbbbbbbcbbc", +"cddeddddeefddcbbcc#a#aa#aaaaaaa#aaaa####aaa######aa######ab#a########aa#a#aaaaaaaaaaabbaabba#aab###abb######aaabbcfheihc######a#####aa#aaaaaaa####aaaaaa###.aikjcaaaaaaaa#################aaccbaa#a################aaaaaaabdddcbccbaaaaaaaaaaa##b####abbcccb##.###a#############..###aaaaaabbbbbccbbccccddecaaa#aaaa###a########################effedccaabbaccbbaaaacc####a#aaaa#aabbbbbbbbbbbcc", +"dcdcdcdeddfecdcbcdaa#aaa##a###a###aa##############aaaa###aba#############aaaabaaabaaaabbabbaaa#aba####a##a###aaabccefadhhb##aaa#####aaaaa#aa#a##aaa#aaa#####.aflkcaaaabaa####################ddcbaaa#################a#aaa#bdddbbcbaaaabaaaaaaa#a####a#baa####a###a###aa#############aaaabccccbcccbbcdcdedefb##a###aa##aa###############a##aa####efddcbcecbccabbaa#aacc###a##aa#aaaabbababbbbccc", +"ccdddcbcfhfddcdcbbc#####a#aaa##a########a#a#aaa#####aaa##abaaa##.#######aabbaabbaaaaaaaababbaaa#aaaaa###a#a#a#aaabccdha#diga##aba#####ca##aa####aaaaa#a#######acildaababbaa###########a#######abccbaa#########.#########a###cdedbbdcbbabba#aaa###a####aaaa#aab###a##a#aa######aaa######aabbccccccccccddddeddfca#aa##aaa#aaa#####a####.###aa#a##a#cfeddedacaaabcaa###aacc###########aaaaaabbbbbcc", +"ccccddccdeffdcccdccb########aa##########a#aaabaa#####aa##ab#aa###########aaaaaaababaaaaaaaabaabcabba############aaabcffb.afjfa#aba####a#a########a#a########aa#abhjb#aaaba#a##########a#######aabcccbb####.#..###aba#########abddbcecbbcbba#aaa########aaaa#a#a###aaa########aaaaa#####aabccdcddccccccccddedcec###ba#a####a#a##########.######aa#adedcbbaabaaabbaa###aabca##aaa#a##aaaaaaabbbbbc", +"cccccdcedcddfebbdcbdb#######################abcbba#######bbaa######.######aaaaaabbabaaaa##aaabababaaaaa########aaaabbcfiea#bgjeaaa######aa#a#############a####a#acgigaaabb##########.##a#######aaa#adcba##########ba#a#a#####a#adfcddbcccbaa#aaa######aaaaaa##aa#aabbab#aa####aaaa#####aaabbccdddcdcbbbbcccddegd##baaaaa#########a################abbcccbbbbabbbba#####abca##aaa####aa#aaabbbbbb", +"bbbccddcdcddefdbcdadcaaa#####################aabbbba#a#aabba#aa##########aaaaaabbaaaaaaaaa#a#aaabbbbbaaaa###a#aaaaaaaabfifa##ejgbaaa########a##################acbcfigba#aa###########a#########a#aaabbbba#######.#a#a#######aaaaffddccbccba##aaa##########a######aabaaa#.####aa######aaabbbccdeeefggecdedcdfedcbaacbaaaa##a#a####a############a##aa#accdcbcbbbbbba#####aaca#aaaaaaa###a#aaabaab", +"bbbbcccccddddfecbccbdc#a############a###aaaa#aaa#aa##aabcccc###########aa#aaaaaabaaaaaaaaaa#aaa#aaabbbbbbaa###a#aabaaabbbhie#.bfhfbaaaa###aaaaaaaaa#######a####aaabdhifbaa########aabaa###a######aa#####bccaa#####.#####a########afgeddccdcba###aa########a#a#######aa######.##########aabcbcccdffghihgdcddcbacbbeabaaaaaa#a###################a##aaaa#bcddcdcbbbab##a##aaaba#aabcaa####a#aaaaba", +"bbbbbbcccccdefedbbcacdc####aa##a#.##a#.##abb######a##aabbccc###########aa#aaaabbbbaaabaaaaaaaaaaaaaaabbbccbaa##aaabaabba##diic##adhebaaaa#aaa#aa##aa##########aabaaagjjf#a######a#aaaaaaa#a#######aa#a###bdddaa#a###.#a###########adcdddddcba#aaaaa#a###a##a##ba#b###aa####.###aa#####a#abcdcbbcdghihhgdcaaaaaabcfdccaaaaa#aa###################a##a#a##acbcdcbbcba#a#####aaba##abaaaa###aaaaaaa", +"aaaaabbbbbcddeedccebaccb###a####a####a#..aba##########aaaaccb.############aaaabbaabbaabbaaaaaaaaaa#baaaccbbaaaa#aaaaaaaa####fjfb###egebaabcb##aaa##############aaa#achkjbaa######aaaaaba#a#aa###a###########abba###################abaceddcbaaaaaaaa#####a#####a####a##a######.###a##abaaccddedeeffdghfaaaaaaaabbdfcabbaaaaa###############.#########a###bccbedcbdaa######a#abaaaba########a#aaa", +"#a#aaaabbbbbbcdedcccbabbb##aa######.######ba#############abcc##############aaaaababaaaaabbaaaaaaaaaaaaabbcbbccba#aaaaaaaaaaa#beihb##afgdbbcba#aaaaa######a######aa#abcilheba#####aaaaabaaaaaa#########a####a##a#aaa###############a#aaadedbbaaaaaaaaa##aa##a#######a##aab######.##aaaababceefcddcb#.#gfaaa#aaaaabcfgcaaaaaba########.#####################aabddcbcabaa##a##aaabaaaa######a######", +"##a#aaaabbaabbccdcbcbbbacb###a###########.aba#######aa###aacf#######.#######aaaaaabcaaa#acaabbaaaaaaaaabababbbcdcbaabba#abaaaaabfje#a#aehdaaaaaaaaba#####ab#a####aabaabijiebaa##aaaaaabaaaba##aa#####a#a###########a###a###########aaaaaabbbaaaaaabaaa#aaaaa#####a##abaaaaaa########abbabcdgeba##.##.bdaaa#a#aaaacfgcaaaaaa########.a########.#######a#aa###abccbbbaaaa#aa#abbab#abaa####aa#####", +"#####aaabbaaaabcbccccbbbcca###a############a#########aa##aaacb###.#.########aaaaaaaaabcbaaabaaaaaaaabaaaaaaaaaabcaaaaabaaaaabaabaejhbaa#aggcaaaaaaaaa####abb#a###aa##aabhigddbababba#acbabaaa###aa####a#c#a#############a#a########aaaaaaaabbaaaaaaaaaa#aa##a#####aaaaaa###aaa######aabbabege##b#######aa#a##aaaaaceecbaaa############################aaaa##aaacbbbaaa##aaa#aaaaa##aa#####a#####", +"####aaaaaaaabbabbdcbcdccbbba#aa####a##a####a######..##aaaaabab###.###########aaaaaaabbbbbbaaaaa#aaaabcbaabaaabbaaaaaaabbaaabbabab#bghcaba#dhfaabaaaaaa#aa###aa##aaaaaaaabeegbccbaaabcbbbaababa######aa#aaaaa##aa#.######aaa#########b#aaaaaabaaaaaaaaaaa#a##aa#aaa#aaabbab##a####ab#aabbbbcfhaaca##############abbabddbbaa####################.###a##a#aaaaa#aabbbbbaaaaaa###aaaaaaaa#######a###", +"#####aaaaaabbbbbccdbccdcbcca##########a#####aa##a######a#aaaabc###############aaacaabbabbbbbaaaaaaabccbbaaaaaaababcaa#bbaaaaaaaa#ba#eiebabaafhb#aaa###a#a####aaabbaa#baabbbigcebaaabcbbcdbbbcca#a##a###acbbaa#ab##########aaaa########aababbbaaaaabaaaaa##a###a#aa###aaaca##a#aa.bc#abbdccbdga#####.###########abbbbcdebaa##a##a##########a####.###a#aa###aaa##aabbabbba#a#####aaaaaa########aa#", +"#####bbbabbbabbcddddcccbbbcca#a##aa###a#################aaaaabb#a####.########aaaacaaaaaacaaaaabcaaabbcdcbbbcbabbbabbaaaaaaaaa####aa#cijdbababhfa#aa###aa##a##a#aaaaa#aabbbflggfaabacbaabbbaacbba##aa#abccbbaa###aaa#####a#aaaba###a#aaaaabbacbaaaaaaaaaaaa###aaaaaaaaaacaaaa#bbab#abbcccccbdc#################aabdceedebaa#########################b#####aa#####bbbabbaa#a####a#aa##ba########a", +"aa##aaabbbbccbbcccddcdccabbdfa####a###########aa######a#a#aacc#######.#########aaabababbaaaabbaaaaaaaabbbbaaaaaaabaabbbaaabaaaaacba#a#beijbaaaaehfa###########aa#abaaaabbbbdhjghffedccaaabaabaabbaaaacbcbcccbaa#aaaaaaaa#aaaaaaaa####aaaabbaadebbaaaaaaaaaaa###aaabaa#a#aaaaabbbbbbbabcdcccefe####.##.#######.##a#aacccccaa#aa#####.###############aaa###.#a###a##bbbbbaa#a########aaaaa##a#####", +"###ab#ababbccbcbccdddccccbbbeda##aaa######aa###abaa####a###abdb#a###.######aaa#aaabbbaaaaaa#abbbaa#aaaaabdaabbcbabb#aaaaaaaabaaacbcba####ejdbbbacgjd##aa#aa#####aaabbaabaabbejiiiihhggfbaabbbaabcba#bcdcdddddcaabbbbcbaaaaabaaaaaaa##aaabbbbcdedbcbaaaaabbaa#aa#aabbaaaaaaabccbbbbbcdccddffebb####################aabccccca###########.#########a####aaa####a##aa#abbaaaaaa########aaa####a#####", +"#aaaaabbbabbcccccdedccccedccdebabaa#aa###########baa##.##aaa#aca#######.#####aaa#aaabaaaaaabaaaacbaaaaaaabaaaabcbaabaa##aaabaaaaabaaaa###.cjgcbbbadiib##aaaaa####aaabbaaaaabdhlijjiiihfefcbaabbbbbbababdedfddedccbccdccbccdccccbaa#aaaaababcccdddcccbaaabbaaba#aaaabbaabbaccdddcdefffedeeed..################.######abcbdfbab#a###########################a#a#####aaaaaaaa##aaaa######a##.#a####", +"###aaaaabcbabccccdcddcccccbbccebaaaa##############a#a####aaa##abb##############aabaaababaaabaaaabbaaaaaaaaaaaaaabbcbabbaabaaaaaaaaaaaa####.afhdbbaabfihb.#aa###aa###aaba#aaacclljjiijigddecbaabccbabbbdbadcbeffffeffgghhhighgfhgffcaaababdbbbbcfddddcbbbbbccabaaaaaaababddehggfegjiedaaaa#a####a##############.######bcdcddbaaa##a###################a#a#####aa####aaaa#aaa#a########a#######aaa", +"aa##aaaabaaabbbdddccdbcddcccccdd##a#aa##aa########a######aaba###ab##############abaaaaacbaaaabaaaaaaaaaaaaaabbaabbaccbaaaaaaaaaaaaaa#########bfgbaabbdije.######aa#abbaaaaaaabellkkkkllkiiigfdcdcbabbcbcdcbcgijkjhhhhijjic#dcbcbddghffeeeihiggfgddedcccbcdcdcbcbcbabadeeffghhhebegdddb#########a#a####################babbbcbbb##a##################aa##a####aa#a###aa#a#aaa##a#######aaaaa##aa#", +"a#aaaaabaaaaaabcdcceccefcadgeceebba###a#aaa########a#####aabaa#aabda########a####aaaaaaabbaaaabaaaaaabbaaaabbbbaaaaaabbcbaaaabaaaaaaa#aa######.eiebbbbcfihc#.###abaaa#aa##aaaabellkjlkjklmnnmlkgfccbbdddeefghjijkkllkhd#cfeabcbbcbbdgjjhgecccehieeededccceeedddddefcdffcedbacdec#bbaba#########aaaba#########.#######aaaacccdbbaa####################aa##a####aaaaa#aaaaa#a####aa######aa#aa##aa", +"a#aaaabaaaaaaaabcccdddggedbdfccecaaa###aaba#a#######aa#.##aabba#aabc###########aaaaabcbaaaabaabaabbbabaaaaaabbcccaaaabbbbbbaaabaaaaaa#aa#aba###.bigbbbccdilid.##aaaaaa####aabbbcekmljgdfiijikmlmnkgdeefeeegieeddgdcghgdbabcfdebcccceffggfcbbbbbcefgedddcceeefdedcbccefgb####babedcaa##aa#######aabcda##.#############aaaaabcdcdbaa#########a########a###a###aabbbbaa#aa#aaaaa##aa######aaa##aaa#", +"##aaaaabbaaaaaaabcdceeffedccfgedcaaa##aaaa###a#a#####aa..##abaaaabbd#########aaaaa#a#bbbbbbaaaaaaabbbbbaaaaaabccbbaaabaabbbbab#aaaaaaaaa#aaaaa###ahibbcdccgjkg####a#aa####aabbcddegkhddgihhghiibdilmljjjjiiihfaaa##aeeedcbbdghfdbbdfedfedccbbbbdbffhfededeefhhfc#####cea#####aaabdfda.a######.##abdfb##########.###a##aaaabadefecb#a##########aaa####a##aa####acbbbaa##aaaaaaaaaaa#####a######a#", +"a##aaaaaabaaaaaabacddeddfdccefffd#aaaaabbaa#a#####a#.aaa###aaaa#abbdb########aaaaba#aaaaababbaabbbbbbbbbaaaaaaa#abcbaaababbbbcb#aa#abaaa###########fhdcccdcehihb###aa######a#bccdefggiglkjjhiihba#cglkjhiihgebcaaaaaa#aacdbbdefhfdbbeedbccbbbabdcbgjifefedeggfgfa#aa#a.aa######aaaacffba####.###abdeca######a###########aabbegffgedaaa##########aa####a##aaa#####aaaab#aaa##aaa#aa######a#######", +"##aaaaa#aaaaaaaaabbcdddceddeeecdfbaaaaabbbaa#####ab#########aaaaaabbc########aababbaaaaaaaabbbaaaabcbbabbaaabaaaaaaabbbbaaabaabbbcaaaaaaa##########.bhfcccdddefigc#abaa#aaaaaacccdegeiihkihhjhbbaa#.#a##a#..##aaaaaaaaaaaacaabaacefedefbbedcbaccdbcfgiihhfdec.addb#ba###aa######aaaaadgeca#######aceaaa#################aaabdgeeghffb########a######aa####abaa#####a#aaaaaaa#aa###a#.######aaaa#", +"a##a####aa#aaaaaaabccbccdedefebbef#baaaaaabaa#####a#aaa####aaa##aaaada########aaabbbaaaaabbaaaaccbbcabbbbaaaabaaaaaaaabbbbabbbbaabcb#a##a#########a##bifdccdddefgjeaaabaaaa##accbbcddfhehijhdb#aaaaa#a####a#abaa#aa##aa#aaaaaabbbaabefigffefdbcccdcbaacbbdhhfeaacbabb##a##########aaaaadhgb#####aabecaa########a###########baegfefgfeca##a#######a##aaaaa#aaaaa####aa#aabbaa#aaa###a#.#####a#aaa", +"#aa#####a#a#aaaaaaacccbbccdcdedbcfcaaabbbaaaaa####a###a###abdb####aaeda######a#aa#aabbbabbaaaaacddbaaaaabaaaaaaabcbaabbbaabbbbbbababa####aa###aaa#####dihecccdedeejgaabcbaaaaabcbbbcdeheggeabaaa####aa########aa###aaaaaaaaaaaaaaccbaabdegedddddddccbbbba#abaabcbbaaaa##a##.#.#####a#a#abefb#####abdfaaa#####aaaa#a########aaadfeeffffc#######a######aa#aaaaaaa#aa##aa#aaabaaaaaa#######.###a#aa", +"aaaaaa#aaaaaabaaaaabbcbbabbbcceedffdbaabcaaaa##abaa##aa###acefa####abdaa###.####a##aabbbcbcbaaaaabba##aaabaaaabaabbbaabbbaabbbbabbcbba#a##aa###aaa#####bhjgccdddefdhheabbaaababcbbabcdehfcaaaaaaaaa#aaaa#######aa###a##aaaaaabcdaabbbbabbbefedeccddcbbbaababbbcccca#a####aa#############aaceda###aabfebaa####aaaaa##########aaadefedegca########aaa##aaa#aaaaaaa##aaa##aaaaaaa#bcba#########aa##", +"#aaa#aaa#aaaababcbbbbccbaaabbbbdgffgbaabbbaaaa#aaa####a##abbgea##aa##bca#########a#a#bcbabbbbaaaaaaaa##aabaababbbaabaabbbbbbbbbaaaabbaa##a#####aaa######adhidddddfhdfigbcba#aaaaaaaacbcfdabaaaaaa#aaaaaaa#######bb#####aaa##aabccaaabdcaaaeeefeddefcbbbbaaaabcbbbcdba#####a####..#######a##abdb#aabcefdaa####a#aaaaa#######aaaaaabacefc#########a###aaaaaa##aaaaaaaaaaaaabaaaa##aaaa###.#####aa#", +"#############aabaaaabcbbaaaabbcceeeeeaaabbaa##a###ab#####abddb#####a##cb#######aa#a##aabbbbbbbaaaaabaaa##bbabbbaaabaabbbacbcbbbcbbbbaaa###a######aa##a#baaagkecdeegfeehfcbba##aaaaaaaaccdcbaccbaaaa#aaa##aaa#########a##a###aaabcaaaadeddbbdcdeigfdbcccbaa##cbabcbcdaaa####aaa######.######aa#debaacfdcaa#####aaaabaa########a##aabccdd#############aaaaaaa###aaaaaaaaaaaaaa###aaaaaa#########aa", +"#############aabbbcbbccbaaaabbccddeedca#abaaa#aa###a##.##aaaa#######aaaca############aaaaaabaabaaaaaa##a#aaaaabbaaaaabbbabbbcbbccbccbaba##########a##aaabaabejfddddehddhgdbbba##aaaaabbbcccaabaaaaa#a#a##a#aaa###############aabcaaaaaegeddcecacdghfdccbaaa#cbabcbac#######bba#################bcdcbeebaaa###aaaa#aa#a###a####abaabdcdcba#a##a####aa###aaaaa##aaaa#aaaaaaaaaaa#aaa##aa#########a", +"aca##########a#aaabdbcccbaaaabbccddeedbaaaaaa#aa#########abca#######a#aca############aaaaaaaaaaaaaaaaaaaaaaaaabbabaabbbbbabbbcbbbbcabbbba##########aa###aabbbeidbbccehefhhcbbaaa#aaabbaaabbcaaa#abcaaaaaaaaaaaaa#####.########aaabaacbedfdbbbdccccfhebaabaaa##a#acaba######daa###.######a####aa##acfdfdaa####aaaaaaaa###aca#aaaabaabccdeaaa###aa#aaaa##a#aaaaaa#abaaaaaaaabaaa##############.aab", +"aa#bb#####.######aaabcccbbaaaabbbcddeebaaaa########.#####abca##########abaa####a#####aaaaaaaaaaaaaa#aaaaaaaaabcbbaaaaaaaabbbbbbbbbccabbaa#a#########a#####aaaachdbccdefehgiebbbaaaaabaaabccacbaaaacbaaaaaaa#aaaaaa#############a#baaaaceddbaabcbebbefdcaaaaa###ba#baa#####.aba##############a#a##aacfghdcaaaa#abaaaaaa######acbababbbdbaa###aaa#aaaa#a#aa#aa#aa##abaaaaaaabaaaaa##############ba", +"a#aa#a#####.###a#aaabbcccbbbaabbbccccge#aa#######.#######abbba#######aaabbaa####bba###aaaaaaaaaaaaa#######aaaaabbbbabaabbaabbbbcbbbcbabbbaaa#a##a##########aaaabeccccddfgefhgaccaa#abbabbbbabbbba#aa#aaaaaaaaaaaaa#######a#####aaaaaabacdccabbbcecaacdfecbbaaaa#aaabaaa#####aa########aaab####a###aabeggbaaaaaaaaaaaaa#a##a###aaaabcccccaa###aaaaaaa#aa#aaaaaaaa#abaaaabaaaaaaa#a###########a#aa", +"###aaaa###a######aaaacccbbbbbbbabccccehb#a########..#####abbca#######aaaacaa####cca###aaaaaaaaaaaaa#######aaaabaaaacdbaaabbbbbbbaabbbbcbccaa############a#aaaaabaccbdccegeccffbbaa######.#abaabbbaaaaaaaa#aaa#aaaaaaa#a##########aaaabbcc#abbabaabaddcbceebbba#aaaaaba######a############aba###a##aaaccggbaaaaaaabaaaaabaaaaa#a#bbabbccdb#aa###aa#aa#aaa#a#aaabaaaaab###abbabaaa###a#a########aa", +"###aa#a######.######aacccbbbbbabbbccccfheaaaa#############bbcaa#######aaabcaa#####aa####aaaaaabaaaaa#aaa##aaabaaaaaacdcbaabcbbcbbbabbaabbbbca#a######aaa##a##a#aaacabccdeggacge.#aa####a#baaaabbabaaaaababbaaaaaaaaaaaa#########aaaaaaabda#aaabbbacbcdbbcdeca#a#aaaaa#a#aa#aa#############aa#####a#aaabcfgcabaaaaabaaaa#aaa#####babbbcccc##aa#a#aa#aaaa###aa#aaaaaaaaaaa#aabbaaaa###a#a#####abba", +"###aa##aa##########a#acbcccbbbbbbbbbcceffebaa#############accbaaa######a#bdcaaa####aa##aaaaaaaaabaaaaaaaa#abbbaaaababcddccbcccccbaabaaabbbbbca####a######aaaaa##a##bbabcbdgefeed########a#a###ab#aabbbaaaaaaaaaaabaaabba#####a#.#a##aaaabca##abbbaccbbdcbcdedb#aaaaabaaa###aaa#########aa#aaaaaaaaaaaaabceecc##aaaaaa#a#aa########abbacccc##aaa#aa##aaaa###aabaaaaabaaaaaaabaaaa####aa#####a#a#a", +"b###aaaaa#######.##a##abbdcbaabbbbaabccdegea########a#####abcbba###aa####acccaa######a#####aaaacbbbabbccbbaaccaaaaabbbcccbcbccbbaaaababaaaaabc###a#aa#####a#aa#a#aabdaaacbbafhgbfa.#####aaaaaaaaa#aabaaaaaaaaaaaabbbaaba###a###########baba##aaaabacaabccbccdeeaaaa#aaab####.########.##aabbbaaaaaaaaaaabccaccba##abbaa###a##a###a#aabbccca#aaa#a#abaaaaaaaaacaaaa#aaaabbaaaaa#aaaa#a#######a##a", +"baabaa#######aaa#####aabbccbbaaabbaaabccdfeba#######aaa###abcabbaa##aaa####ddbaa######a###aaaaaaaaaabbcbbbbbccaaaaaabbbbbcccccbbbaaaaaaaaaa#abca##a#aaaaaa##aaaaaaabcaaaabaabgicce##.#a##aa#a#aaaaabaccbaabaaaaaaaaabbbaaa#aabb##########aa#aaaaaaaaaaabccccddfebaaaaabbaa################bbbbbbaaaaaaaabbbc##acbbaaaaaa####a#####aabbbcccb###aaaaaabbaaaa#a##aa####aba#bbaaaaaaabaaa#######a##a", +"baaaaa#######aa#######aabccbabaabbbaabbbcdgdb#a########a##abdbbaaaa##aaa##abdcbaa#############aaaabbbbbbbbbabccaaaaaaaacbbbcccbccccbbaaaaaaaabbca#aaa#a#aaaaaacbabaa#aaaaaccbbjgabc###bb######abaaabbcccbabbbaaaaaaaaaaaaa##aaaaaa#######aa###aabcbaaaabbbccdeeefebaccbbbbb#.####a####.###abaabbbbbcbaa#aaabca.##acccbaaaa########aaababbcba##abaaaaaaaaaaaaaaaa#aaa#baaababa#bbaaaaaaa#######aa", +"aa##aaa###############a#abcbabbaaaabaabbbcffcaa##aa##aaaa#abbbbaaaaaaa##a##abdbaa##############aaaaabbaacbabbbcaaaaaaaabbbaaabacbccbbbaaa#aaa#aabb#aaaaaaaaaaabbbbaaaa##aabbbadiabbc.##c#######aaaaaabbccbbabbaaababaaaaaaaaaa##aa#######a#####aabbaaaabcbbbcddcefhgceeaabba##############abbbbbbcbaa###.###aca####aacdba#a#a######aaaabbcbbaa##aaaaaaaaaaaa#aaaaaaaaaaaaaa#bababaaaabaaaaaaa#ab", +"cb####aa################abcbbbaaaaabbaabbbdgdb##a#aa#aaaaa#abaabaaa#bba####aaddba#######a#########a#abbaaccccccbaaaaabaabccbbabaabcbbbbaaa#aa###acda####aaaabaaabbcbbaaaaa#bcbcebbccd#.aba######aaa#a#acbaaabbbbbaaabbdbbca##ba###abc.#.####.##a#bbaaaaaaccccdecdefghgfccccb#.####.#...###aaaabbabddba###...##bb#####a#bcba##########aaabbccaa###aaaaaaaaaaaaa##a#aa#aaaaaaaa##ababbaabaaaaaaaab", +"ec##########a##aa#.#####abbcbbaaa#aa#ababccfffcaaa#aabaaaaaabbaaaaa#aba###aabbfdaa###.#############a#aaabbccbbccaabbaabbbbbbbbabaaabbbbbaaa#a###aacdba##aa#abbacbbcbbbaabaaabbceabccde.#c#aa######aaa#aaa#aaababbabaabbdefecd#aaaaaaec#.#########aaaaaa#aacdcbdbabdfegddffdba##.#.###.###aabbbbabbccbba###.#.##bc#######abbba########aaabbbddcaa##aaa##aaaaaaaaaa#aaa#aaaa#aaaaaababaabbaaaa##ab", +"bca######.#####aa#######abbbbac#a##aa##abcdcehfaaaabbbaa#abcbbbaaa#aaba#####acegdaa####.############aaaaabbbbccccbabababcbbbbbaabbcbbabaa##aaa###aacebba###bffcdbcbbcbbcaaaabbbhbabbcee.##aa##aaa#acaabbaaaaaaabccaaaaaabdefge##aaaacea###########a######abdfdabaaaaababaceeb###.#...#.##aaabbbabbbaabaaa###..##bea###a##a#aca#a#a#####aaababb####aaaa##aaaaaaaaaaaabaaaaa#aaaaaababaaaaaaa###ab", +".#a###########.b########aacaaaacaaaaaaa##acdffgbaaabaaa##aaehdbaaaa#aaaa#####acfgbaa#########.########aaaabbabcdecbaabbabbbbbbbaaababaaaa######a##aaddbaaaaab##a##abccccccbbaabfhaababgd.######aa#aaaaaaaaaaaaabacdddbaaaaaaddeda#aa#ba######..##a########abdcaaaaababcabbbcddb#a###..#.##aaabccbbaaaaa#########abed#########cb#a#a####a#aaaaacb###a#aaa##aaaaaaaaaaaabaa#aaaaabaaaababaaa######", +"#########aaa###a########abbaaaaaaa#a#aaaaaacdegeaabaaccbaa#acefcaa###aabba###aadfdbbaa####.#############ababaaabcccaaaaabbbbbbbabaaabbbbaaa#####aaaabdeaabbba########aabdedcbabbffaababhd########a#aaaaaaaaaaaaaaacedbabaaba#bfggcaaa#########..#.########aabcb#aaaaaabaababccddba#..##.####aaabbaaaaaa##...#####acecb########abba#aa#a#aaaaabbca##aa#aa#aabbaaaaaaaaaaaaaaaaaaabaaaaaabaaa#aa##", +"##########aa###a#####aaaaaaa##aaaacc#a###aabbcefbabbcfcddddbabgfa#a#aaaadbaa##abdedcaaaaaa#############a#aaaabbbbaacbbabbaabbaaababbaabababa##a##aaaaaccbbbb########.###abbacdcccgbabbbcida####aa#a#baaaaaaaa##aaabccaaaaaacbbabggb#a#####aa##..##aa######aabbcbaaaaaaaba#aabbcccca#.########aaaaaaaaa###...#######abdec########abb#aaaaaaaaaaabcbaaa#####aabbbb#aaaaaa#abba#aaaaaabaaaaaaaaabb#", +"###########aaaaba###aaaaaa####aaabdebca###aabbcfgfbacdccdeheaadgea###a##dcabaaaabdedcbaa##################aaaaabbbccbaabcbaabbbbabbabbbaaabaa#####aa#abddbcb##a########a##.##accdeedbcccejcbaa####aaaaaa#a#aaaa###aabbbbaa#bdbb#chfa####a########.###########babbaaaaaabaa#aaaaabbcdc#..######aa#aaaaaa###.#..#####a#abdeba#######bbbbaaa#aaaaaabcca#aaaa#aaaabbbaabaaaaaaaba#aa#bbaabbaaaa#####", +"######a##a###a#aaaaa#aabaaa##aaacddbbcaa##aaaabdifdadeeddfffaabdddbaaaaabd#aaaaaacfedcaa#################aa###aaaacccbbabbbbaaabbbbbbbbbaaaaa######a#aaacdddaaa#########a######aabbicceedghcbb##aa#aaaaaa#aaa#a####aaabbaa#adffbafgd####aa###################aaaaaaaaaaaaa#ababaaabbbcb#.####aaaa#a#a#a##..########a#aabbcdd#.###a##bbaaaaaaaaabbbbba######aaaacbb#abaaabaa#a#aaaabaabbbabaa####", +"######aaaaa####aaaaba#abaaa###a#bddccaaa######abcfgghhhfdfffcacbabdecca#bca#aba##aeffeba##############.########aaaaccbbbabcbbbaaaababbbbbbbaaaa######aaaabeeaa#aaa######a###a#aaaabfgdbbddhhccb###aaaaaabaaa###aa##aaaaaaaa#bffgd#cda##a#a######a#a###########aaaa#aaaaabb#abaaaa#aaaabbca####aa#aaaa####.#############aaabcdc#####a#abba###aaabababc#aaa##aaabcaaaaabaaaaaaacaaaabaabbbbbaaa###", +"a######aaaa##a#aabbaaaaacba##a##acccddbaa#a##aaaaacccdefefefdacaaaacgebcdb#a##aacbbegfdba#aba##############aa###aaabcdbccbbabcbbbbbbbaabbabaaa###a###aaaabcdb#baa#a###########aaabddgcdcbbcfidbcb#aaaaabaaa#a#a#abaa###a#aa##dfffeaa#####a#####aa##b.######.###aaaaaaaaaacbacaabaaaa#aaaacccaa####################a########abceca###aa#abaa#aaabaaaacda#aa###aacaaaaaabaaa#aaabaaaacbbbbacaaaaaa", +"aa##a###aaaa#a##aaaaabbbbbbba####bbbacbaaaa##aaaaaabccbdedcefaccaaa#accccaa##aaabcddfgefeeffea################aaaaaabbcbcbbcbabbbaabbaacaaaa#a#######a#aaaacfcaaa##a############aacdee#a####eifccc#aaa#ccaa###aaa#ba###a###a#befffd######aaab###aa############aaaaaaaaaabbcbcdbbaa###abbaaabccdca...#######aa#a####a######aaaabcdc######aaaaaaaaaaabbcdbaaa##aababaa##aabaaaaaabaa#abbbbaaba#aaa", +"#aaaaa##a#.###a#aaaaaceccbbbab##aaaaaaaaaba#aaaa#aaabccbcdddgfdaaaa######aa##a#aaaeggihgeefeddeca###############aaaaababcbbbbaabaaaaabacbaaa##a#####ba#aaabadgeaa#a##a####a##a##aabbeeaa#####bhibaca##aadbaaaaaca###########aadfddfda###abaabb#aaba#####a######baa#aaaa#abdc#bccbaaaa###ba#aaabdfeec#########aa#aaaa####aa#aaaaabde###a###aaaaba#aaaabbccbaaaaaaaaaa#a#aaabaaabbaaaababbbbaabaaa", +"##aa####a#####aaaaabcccbbbcbbaa##aaaaaaaaabb#baa##aaabbcccdefgiecbaaa##aabba###a#affghihfccdddddeca################aaabaaaabaaaaaaaaa#aaaabaa########aaaabaabcgcaaaadda#aa#######aacdde#######aegbbdbaa#adbbaabcaa#aa#########acfeeecaaaaaaaabbaaaba###########aaaaaaaaabddfbaaababaaaaaaa##aba#acefgca###aa#####abb######aaaaaaabcfa##a###aaaabdaaaabbbbdb###aa#aaaaaaaaaabcbbbbbbabaabbbbbbaa#", +"####aaaa#a#####aaabccccbaabcbcca##aaababbabbabaaaaaabcccbacddefffdccabccdedaaaabdeeffgggeccddccdcdca#a##############aaacaaaabaabaaaaaaaaaaaaaaaa###aa###aaaaacdgcaaabaaa#######a##abdchaa######.cfcbcb#a.bffcbbbab###aaaa###a###ceedddabcbaaaabbabbaaaa##..#####aa##aaaa#acecbbcbaaaaabaaaa##aba#aecbccdcabaaa##abbaa#a##aaaa##aaaabdd##aa##aaa#aaababbbbbdb#a##aabaaaaaaaaaaaaabbbbbbcbbbbcbbaa", +"aaabaaaa####aaaacccbbcbbbaaaabdaaaaabcaabcbbbbbaa##abcddcbcdefedffedbdccdeec#aafffdddeffcccbcdcccccccaa#############aaaab##aacaaaaaaaaaaaaaaaaaaa###aba#aaababdefaaaaaaa##a###aaaaabccgcaa#######bgcdeca##bhgbabaac##a#aaa##a###befddfdddbddbaacabbbbaa####.#######a#aaaaaacbaabbbaa##ababa##aa##acaaaabbcb#aa#a#aaa##aa#####a#a#aaaabeca#aaaaaaaaabaabbbbbdb#aaa#abaaaaaaaaaaaaaaaaaabcbaababaa", +"aaaaaa#aa#####abbbcbbabcccbbaaabbccccdbabccbbbbbaaabbcddcbceeeddeggddfbcdeec###dffedddeddcccedccccbbcdb#################aa#aaabaaaa#baabaaa#aaa######aaaaaaaabbcdfaaaaaaa#a####a#aaaabge##########bhcbccaabdeeaaaa###a###aaaaaabceedefeeedeeccabbabcbbaaaaa##.#.#######aaaabbb#aaaaaaaaaabaa##a##aaa#acbcabca###aa####aa#########a##aaaedb#abaaaaaaabbabababccb#aaaaba#aaaaaaaaaaaaaaaaabbbbbaaa", +"aaabaaaaaa###aaabbbbbaaaacbbbbbcccddefdaabbbbccbbbbabbccbcdddddeeeffefcedffedbabeeecddcbcccbdbbbabbbabba#aaaaa##a######aa#a##aaaaa#a##aaaaaaaaa###aa##aa###aaabbdedaaaaab#a####aaaaabbgha#a########becaccdfgddda#aa#aaaabaaa#a#addeecdcdfeeeddcacbbbcbbaaaaaa###########aabacbaaaaabaaba#baba#aa##bbbdbacaabcb##aaaaaaaaaa#########a#aaabddbaaaaababbbbbaaabcccbabaaaabaaaaaaaaaabaaabaaaabbbbaa", +"abbabbaaaaaaaaaaaabbabaaaaabbcbbcdedfggccbaaabbbbccccbccddeddccdddcddecddeffddecddccacbaacbbbbaabaabaaaaaaaaaaaaaba####a###ba#ba#aa#####aa#aaaaa############aabbcdebbbaaaa########ababdhf#a#########afecfffebceaa###aaa#aaaaa##abeeddddeegffdcfdbbabcccbaaaaba###########aaaabaaaabbaaabbbaabbaaaaacdcaacaaaabca##aaa#aa#aa#aa#######aaaaacee#bbaababbbbbbbbbccdcaaaabbaaaabbbaaaaaaaaaabaaaaaab", +"babbaaabaaa#aaa#aaaaaaaaaaaabbbbcdbadccdbbbaabbbbbcbbccdeeedeabcccccccccdeedfddcccdbcbaaaaaaabbbaaaaaaaaaccaaa#aa##aaaabbaab#a####aa####aa##aaa###############abcdedbcba#####aaaa#aabbdhie.#####a#####fgffececeda###aaa#aaaaaa#cddecddcddefeegefeccbccccbaa##aaa#.#####.##aaaabaa#aaaaa#aab#bcccbbccbbaab#aaaabcbbaa#aaaa#a#a######aaa##aaabdfdbbbbabbbbbbbbbbccccaaaaaaaaaaabbbbbaaaaaaaaaaba#b", +"bbaaabbaaaaaaaaaaabaabbbaaaabbabcedcbbabccaaaaabbbaabbceffcccbbcbbbbbbbbddcdddbbbabbbbaa####aaabaaaaa##aacfeaa######a##aaabbbaaa##aa#a#####bcca#a##aab##aaa#aaaacccgdbbb#######aaaaabbbdhhb###########aeifddbbceda#aaa##aaabaabefffcdddccdeeeedeffefeddccbaa##aaa###.###..aa##aba##aaa#aaabaaabccddcccaabaababaabcca###aa#aaaaa####aa#####aaacffbbbbbbbbbbbbbbbbcdcaaaabbaaaaaabbaacbaaaaaabbbab", +"babbbabbaaaaaaaaaaaaabbbaaaaabbbceddcbaaabbbbbaaaaaaabcdffdcabbccbbaaaabbbbbbbbaaaaaabaaa#a##aaaaaaa####aadd######a########abbaaaa##a#####a#aa########aaaaaa#aabbbbdgcaaa###aa##aaaaabadfgb######aa###aadidcdbaceca#aaaaaa#abcdeeeccdeddccddeadeefffffffecbaba#######.###.##aa#abaaaaaaaaabcaaabaabcbd#abaabbbbaaabdba#a#a##a###aaaa#########aacefdbbbbbbbbbbbbcbcccaaaabaaabbaabaaccaaabbaabbaa", +"baababbbbabaaaa#a##aaabbbaaaaabccehdbaaaaaaabbaaaa##aabdgieccccbcbaaaaabaaaaaaaaaabaaaaaaaaabaaaaa###a###aaa################aaaaaacba######a#a##########aaaa#abbbbbcdhb##a####aaaaaaaacbfe.##aaaaa#####aadhcbbaaefbdb##aaccddfgedbddccccbbcdedceceggfeefefdcbaaaa#####.###.###aaaaaaaaa##aba#aaaaababdb#aa#aaabaa###bcbaa#######aa#############abdffcabbbabbcbbcbcbcdcbbaaabbbbbbbaacabaaaaaaaaa", +"bbbbabbbbbbbaaaaabdcabdcaaaaaabbcdffcbaabaaabbbaaaaa##bcgjfbbbcdddcbbbbbbbbbaaabaabbbaaaaaaaaaaaba#########a#a###############aaaaaabaa#######a######aa#a##aaaabcbabbcceda#aaaaaaaaaaabbbec.a#aaaaaaa####aadhcabbbeecbaaadefggfeddcddcccccbccdccdddeghggeeeddcbaaaaa############abbaabaa#aaaaaaaaba#ba#aaaa#abaaaaa##aabbb###aa#a#a##a##########abbcffdcabbcbbbcccbbccccbaaaaaabbbbaabbabaaaaabba", +"bbbbbbbbbbbbbbaaabfdcccbcbaaaaacdceebaa####aaabbbbaa##bdghfcbaaacdddccccccccccbbababbbaaaaaaabbbaa#a##aa#a#b##a#aa###a#######abaa###aaaa##a################aaaaabbbcbbcffaaa#cbaaaaaaaacec.#####aadea##a#aabgdababdfda#adfggeddccccbbbaccbbcbcddddgghigffffbabbaaaa##########ab#aaaaaaaaaaaaa####aaaabaaaaaaaaaa####a##aaca##a######a#########acbbbbcdefdabbaabccbbbbccccbcbaaabbbaaaababaaaabcc", +"bcbbbbbbbbbcbbbbbcecccbaccedaaabddcaaa#######aabcbbbaabdfhfdcaa###acdcabdfeeedcccccbbcbbaaaaaaacbaa###aaaa#aaa#####a#aa##aa###ba###aaaaaaaba############aa#aaaaaaaaaabbbfgaa#adbaaa#aaaaehaa###aa#adea#a#aaabgbabacefdb#dfffedccbbaaaaaaccbbcdecdggihihhfdffcbbaaaa###aa###..#aa####baaabaaaaaa#####aaaaaaaa#aba#a###abaa#cbaa##.##aa####aa##aa#baaaacccefdbbabbcccbbbdccdbaabbbbbbbaaabbaaaaabc", +"cabaabbbbbbcbcccccddb##abaccbabbdbcaa#a##a####aabdcdbbcdddghcbaaa####bcacigggecbbbcbcbbabcaaaaaabaaa#a##abb#########a##aaaaaaaaaa###aaaaaaa########aa##aaaa#####aaaaa#acegfaaa#aac##aaaachfc###aa###aabb###a#bbabccddefdceffedbcaaaaa#aaabbbbcdegihhhhgggdcffecabaaaa##a##.###abca#aaa##aaaaaaaa######a###b###baa####aaaaaaaaabca###############aaaabbbbbbdfebbabcccbcdcbbdcbbaababbabaabaaaabbb", +"febaaaabbbbcdcccccb#####abbabbcccbbaaa####aa#a#abdeccbddeeehgcaa#a#aa#addhifdddbbccbcccbbbbaaaaaababaaa#aaba####a##a#a##aaaa#aaaaa#a##baaaaaaa#####b###aaaaaa##a##aaaabcefihefc##aaaaaabbdha####aaaa#ab######aaaabbccdefegffdcccaa#a##aaaaaabbehhhhffffcddbdcdbbba#ac######..###bb###a#abaaaaaabba#####aaa######a#aa#####a#####bbca###########a##aaabbbaaaabdfdbaccbccbcbbccdcbbbbaaaabaaaaaaabb", +"dedbbbbbbccbcdccddb#####bbbaacccacbaaaa###aaaaaaacfdcbcdegghigbaa#aaaaaadfhgedcccccbbbbbbbbbbbbbbbbaaaaaabbba########aa#aaaa#abaaa####aaaaaa############aaaaaaa###aaaabcfghgihfbcb#abaaabbge####aaaaab######a#aaaaaaccdeeddfdbcbaaa##a##aabaafhgggfedccccdccbaaabaaaaaa#########a#####a##aabaabcaa#aaa#a#####.####a###########a#aaaba##a####a#aba#aaaabbaaaaabdeecccbbcbbccccdcbabaaabbbaaaabbba", +"bccdcbbbcccccbcdfda#####acbabcbaabaaa#a###aa#aabbbefedcdffiihhcaaaaaaaabacfffefedcbbbbbaaaabbbbbbbbcaaaaaabaaa####a###a##aaaaaaaaba#####aabaa###########a#a####a###baabccghfhiieaa##aaaaabdga##a#a#aaaa######aabbaaabbbcddegdcbbaa##aaaaaaabbfedfddecbbbbbbaabbabbaaaaaaaaaa####aa####a#a#aaaabcbaaaaaaaa##############.######a#a#aabbba#a####a#aaaabaaabaaabbabcfedcbbbcbccccccbabbabaaaaabbccb", +"bbccccbbcccccdddeca####aabbccca##aaaa##a#####abbbbeeffeeccfjjifbaabaaabbbcdecdeffdbcbbbaabbbccccbbdcbaaaaa###########a#a#aaaaaba#a######aaabcaaabaa###aa#aaa######acedbcdfihfhifba####aaaadhc###aaa###########a#bbaaabbccccfecaaacca##aaaaaccffdfccedbbab#a#aaaabbaaabababaa###########aaa###bbaa#aaa#abaa##########.########aa####a#aabba#a###a###aaaaabaabaaabbbcdfedbcccbcccccabbbbbbabbbbbbc", +"bcdcbbcccccddddddba####abbbbdca#a###a###aa####aaabcededcbbgiijjhcabbaaaaaccddddcceedddddddeeefedbbcbcccbbbbaaa#a###aaaaa###aaaacaaa##a###a##acca############acaaaaa#abbccdghccggfcaba#aaaacggdaaa###############abbbaabbdeefedbaaaadda##aabbchedeefedbaaab#####aabbaabacbabaaaa########aa#a###aa####aaabba##a##.#############a#a####aaa##abdba#########aabbaabbabbaabdeddcbbbcccccbbbbaabbbccbba", +"bbddccbccdccdcebcbb#####abccbcd######aa##a######abcddcdddeggiihhhdaaaabcccceedccbbcbbccbccdeeeggfeddccdeccbbaaaaaaa#a##aaa###aaaba#a##aa######a#####a######aaaaaaabaaababcehb#adcbdbba#aaabdceaa#################abbbbbacgeeecca###bedcaa#adfhccdffbbbba###a####aaaaabbbbaaaba###aaaa##########aa#.##aaaaa#aa#b######a#######aaaa##aaaa###abcdb######a#aabcbaabaabbaaabcdedbbbcddcbbbbcabbbccbbb", +"bcdfdddcccdddcecbb####a#aabccabaa#####aaaaa#####abbccdedeedcijfggfabaabbbbccddccbbbabaaaaaaaaabbbgihihffedccbbbbbbbba#a#aa####aaaaaaa##aa#######a###aaaa########abaabbbbaccega#cdaaabaaaaabbfea#a#################abbbbbaeedddcbaaabacceccefihdccedcbaa##########aaaaaaabbbaaaa#####aaa##a############aa####aaaa######a#####aa##a##aaa###aaa#a#abc#aa###aabcaaaabbbbbbbbbbcddcbccddcbbbbabcccdcc", +"ccbcffhfdddddccadbaa#####aabbaaba##########a##aaabbaacdddfeehjifgha#aabcbacddccbbbbbabbaaa#aabcccefgdddeffeecdedbbbbcba###aa####a##aaaaa##a###aa###aba#aa######a#aaabbba#abbfcbcccccbaaa#abbfjg#aa###########aaabbaaabbcbdedcdbbaaabbbcceghhiiedcedbbaa######a###aaaa#abaaaaaaaa##aaa##a##############aa####aaaaa#####ab#####aa##a###aa#aa#a#####aaaa##aaaaabbbbabbbbbbbbbbbbdddccddccbcbbbcccdd", +"eecbdggfdddedcacda####a###abbaaca######aa##aaa#aabcababcdeeedgigdfgbbcbbbbbcccbbbbbaaaaaaaaaccddddefdecccbbcbbddcbccddedcaaa#a#aa##########a########adbaa#########aabbbcbcabbdcdcbbbcbaa##abbfiaaa##############baaabbbbccedcccbaa#abbbbbefgihfdcccbaaaa###a######aaba#abaaaaaabaa#aaaaaa######...#a#.#####aa#aaaa########a##aaa###a###aa#aa#aaaa#aabbabaaaaabcbbbbbbbbbbbbbbbccdeddcccbdccccdde", +"eedfhhfcba#abb##a#####a#aabcaaccbc#####a#aa#aa###ccbbbabcdfffhgifehfebbbabbcccbbbbbbbbaaaa#ccdcddfghfeccccbbbbabcddegcbccdcaaaaaa###a###a######a#a##accba#########aaaabbccbbcbcehb###cbba##bdehe###############aa##aabbbccdcbccba##aacccbcceffedcbbaaa#####a######aaba##aaaa#ababcbbbbcbaa########.#.##a####a####aa######aaa###aa####a###a##a#aaa####aaadbbaaacccbbbbbbccbcbcccbcceeeeededcdbccd", +"dgghigdb##a#a########baaa#abbcbdbbb#####aa#aaaaaaabaababcdegiihdggffdcbaabbbbabbbbbabaaaaa#ccdccdegedccbbbbbbcbbbbaadbabaacdb###aa###############aaaab#aa##a#######aaaaababbbabbfieaaaa#aaa#chke.#########..#aaaaaaaaababbccbbcbaa#aabbcbabcdeedcba###a#####a#a##.###baabbaaaaaaaabbaaba#########....#.#######ab#a#######a######a#########a##aabba###aaabbbbbbacdcbbbbcbcccccbdddeededegeddddcdc", +"dhghhfa##a######a######aabaacccedaaa#######aaaaaaaababbbccdghgfedgfgcabaaaaaaabababaabaaaaabdcceeeecdbbbababbbbccbbbbbabdbabcba#a############aa##aaaaab#aa###########aababcbbaabeggh######aaagj##############aa#####abbaabbbbbabbbabcabbaaaabcddccba#######.###########ccaaa###aa##aaaa###a###..##....#.aa##a############aaa#####a#####a###aaa#aaaa#aaacaabbbbbbeccccbbccddccdegghhgfeegd#bddccc", +"ffhhhe###########a#####b#bcadddcbaaaa#####abcca#aaaaaaaaabdhihgddfgfgcaaaaaaabbbabbbaabaaaabedcefecbbbbbbabbbaaabbacdca#aaa#bbdb#aaa#########aa####aa#a###a#####.###aaaaadbbaabaddcggbaaaa#bbdia#a##########aaa###aaabaaaabbbbbbaacefebaa#aaaabcccbaaaa###########.#.##ad#####.##aaa#aa#aa#####...#...###ab#ba######a###a##ab#####a###aaa##aa#aaaaaaaabbbbbbbbbbceddeeccbccccddfhijjhggghb#bba##", +"#afhgcaa###########a#a##aabcddca###aa######abbbabaaaaabaaaeiiihgbbgeddaaaaaaaaabbaabbbaaaaabdcccddddccabbbbacaaaaabbbaaabaa##acdd###a######..a#a#####a#aa##a########a##aaecb#abbbcccfgaaaaaaaeia#a#a##############aabbaaaababbababdgeca####aaaaabcbbba#####a####.#######da##############aaaa#######.##.#.#ba########.#a#aa##abba##aa#aa#aa###aaaaaaaaaabbbbbcbccccefgeeccbccbbbbdfiihgggeb#aaaa#", +"##bhgd###############ab#ababcdd###aaaa####aaaaaaaaababaaaadhhigebabfddcaaaaaaaaaaaabaaaaaaabcbbbcbbcecbbbabbbaaaabbaaaaaba###abadea#########.#a##########aa#a###a###a####aabbabbaadccghbbbaaabfi#a##a###aa####a##a#aaabaaaaaaaabbacfdba##a#aaa#aaaabbb######a######.##a#######aa#a##a#a####aa#####a#.#a####aa#########aaaaa##aaa###aa#aaaaa#aaaaabaaaabcbbbbccccceeceeeefedddcbbceeffhgfebaa####", +"##.dhdb#########ab###bdababaddc######a###.#a######aabacaaaadghfdbbabecdba###aaa#aaaaccabaaacababbbbbbbcbcbbcbaaaaababaaaba####abbcfbaa#aaa###.###ab#####aaaa##a######aa#ba#aabbbabdcabefbcaababhe#a##aa##aa###a#####aabba#aaaaabbbefcba###aaaa#aaaaaaaa#########a#.##############aa#bb#aaa##a####.###########aaaaa#######aaaa###a####a##aabaabaaaaaaaaaabbbcccddebbbbdedefdcccccbceeghgfdaaba#aa", +"aa#aeea##########c####ba###aca#####aba#############abcabaa#acdefccbacdbdc##aaaaa###aabdbaaabbcccbbbbbbbccbabcabaabbabbaaaaa###addbcdba#a################a####aaaa#aaaaaaaa#aaacbabdcbbbehca#abbeh#aa######aa######aa#aacfbaaaaaabbdgdbaa###aaaa#aaaa########.###aa#a.###########aaa#bbaaaaaa####a#.##.#######aba#####a#############a#aaaaabbba#bbbbaaaaabbcddddddbaabcedccbaadfdcceeggdbaaaaaaa#", +"aa##ada#a########aaaa###a###a######abaa#########aa#abbbaaaabbcddeeebcdbabb#aaaaaa####aaaabcccbccbaabbbabccbaaaaaaaabbaaaaaaa##aabcccfeb##############a####ab#aaa##aaabbaacababaaaabcdbccffc##abeh.##aa###a#########aaaaacbabaaaccddfgdbaaa##aaaaaaa#######.##.#######.#########aaabaab########a#a##.#########aaa#####aa##a#aa###bdaaba#aa#aabaaaabbbabbbbcddefecbcbaabbdcbaabcecccefgcaaaaaaaaa#", +"aaa#aaaa#aaaaa#####aaaaaa###########a#####a##ab#a##aacabaaabcccbdhedfdbbabc#aaaaaaaba##aaaeheaaaaaaabbbacddbbaaabbbaaaaaaabc#aa#a###cfgb#a#########aa###aaaccaaaaaaaacbabcdaacbaaabcddcccgfcaabeg.#a#aa#a###aaaa####aaaaabaaaaaaceefhfdbaa###aaaaaa########.####.###.####.####aa#abcbaaa####aaa#############aaaaaaaa#aaaa#ba#babffb#acb#aaaabaaabbccabbcccfgdaa##bcbbaaacbcbacebbbcddbbaaa#a####", +"accccedaa#aa#aaa##a#aabda#################a#a#a##aaaabbbabbcccdcccfcfecbaaceca#aacdbcccba#ahgabaaaaababbbccccbaabbbbbbbaaabcb###aca#aabcc##a##########a###a#abaaa#aaabbddddbbbcbaaaaabcdddhecccg######ba#a##.#a###aaceca#cbaaaaacdefhgfcaaa#aaaabba#########..#####...#.#######aaabccbaaa####aa########.####abb##aa#aaa#a#ba#abbefba##bbbaaaaaabbccc#ccddeffcaaaa#baaaaabebbbbcbbbbcbbbbbaa##a##", +"#abeeebaaa###aa###aa###aaa###################aa###a#aabbbbcddddccefegfcca#adhbaacccaaabcbcdecaaa##aaacabdabdcbaabbabbaaababbcb#aabb#aa##dea##aa#######aaa##a##aabaaaacacdfebbbbbbabccccfeddfgfed...#a##aa###########acdbabbb#aa#acddegfecbaaaaaaabaa#########...#####.#########a#abbbabba##aa#####.##....#####a##aaaaaaaa#baaaceeebaaaaeedbbbabbbccb#cedddcccbaaaaaaabaa#bebbbbbbbbbbbbbaaaa####", +"##aadba#aa##a#######abbda################a#######aaaa#ababccdeeddffhhgccbaabefdbbaaa#aabcbbabca#aaaababbbbcccbaaacaabaaabaaaabbaaaab#aaaaefaaaaaaa#.###a#a#a######bbbaabccabbdcbabbcbcdbbaaaefeiiffa####a#######a##aaaaabbcba#baabdddefffdcaaaaaaaaaa##########...##############aabbbbbdabaaa###.....########aaaaaaaaaaaaabcccbdfebaaaaaacfdccbcddc##baabcbabaaaaaaaaabaaaedbcbcccccbbccbaaaaaaa", +"a##aba#a####.######a##bgb#######a########aa#######aaa##aabbcceedddeghiebaaabccebaaaaaaaabaabaaabbaaabbaaabbbbbaaabbaaaaaaaaabbccbbcba#####cfebbabbbacaaaaaa#aaaa###acbbbbbbbbcbaabbbccbaaab#.aceffdfghfa#a####aa#aa##acbacbbbaaaaabcedcddedbaaabaaaaaa#######..#.################aabccccdbbb####.#..#..#.#..########aa#aaa#aaabdddbcababbbdeddedeeb####aaaaaa#ba#aababcbbbaeccbcbcbcbbbbaaaa###a", +"ba#a#####a#############cb#########aa##a###a####ab#aabaaaabbbbedcdccehihcbbbbbbccaaa#a#aaaaabbaaaabbbcbbaaabbbccaaabbaaaaaaaaaabbbbacda####aaedbaaabddba#aaab###aa####aaddcceebabbbcbcdca#aaba#aaabaabfmka##aabaaaaaa#abbabbbbaaa#acccdddccedbbbbaaaaaaaa##a####.#.###############aabddcbbcaaa####.#......aa###aa####aaaa#aa##aacccccbbbabbcdedddea####a##aa#a#bccbccbcbbaaaadddccbbbbbbaa#aa####", +"ab##aaaa######a##########aa###b##aaaaa##a#a#####ababbbaababbbccccdcdgjifbbabbcccca#aaaaaaaaacaaaaabcccbaaa#bbbcaaaaaaaaaaaaaaaaccbaabbaa#a#a#bcbbaa##a###aaba######aaaaaaddfhgccddddacacaaaaa#aaaaaaabhnk.aabbb##aa####aa#acaabb#aabccddeecccbbbabaa##aa###aa#######.######a###aaaabdddcdedda#########...#####aaaaaaaaa##a###aabcbbccbbbbcddeeefc##a####aaaaaacdccbbaababaaabccdccccbbbbaa#a####", +"#####a#aaaaa###aaa######ba###aa#bba#aa#abca##bb#abaabbbbbbaabbbbdccceihgecbcdccbcd#ababa##aaabaaaaaabccbaabbddbbaa#aaaaaaaaaaaaaccbaaa#a######aabdcb##aaa##a#a#####aaaa##aabffebccddcb#aa#######aaaaaadlnd#aabbabaaaaa##aaaa####aaaabccdeedbb#aa##a###############.##..#.#####aaaaabccdeecdaa#####.########.###aaa#aa###aaaa#aaabcbccccbbccddeef##aaaaa####aaaccbaabaaaaaaaaba#bcddcbbbbbb#aaa#a", +"abaa###aaaaa##a#a##a#############a#a#ababda#aaaaaaaabbaabbbbcbbbddbddgifhedbcccbbcc##aabbaa#aaaaaaabaabbbccccdebaa##aa#aaaaaaaaaabedaaaa##########becaaaaa#a#########aaa##abceffdccb##aa########a#abbabilk#a#a######ab#aa#aa#####aaabbcddedbaa#a######a#####################a#aaaaaabdddfgfc##########...a#a###aaa#a#aa##a###aaaabbbbbcbbbcceghfaaaaaaaabbabccbbbaaaaaaaa#abba#aacedcccbaaaaa#aa", +"bbaa##aa#aaaa#aaaaaaaaa#aaa##########abaaaa#baaaaabbbbbabbbbccccddbddggghhfdbbcaabbbbbaabbaaaa#aaabbaaabbb#bbbaaa#####a#aaaaaaaaaabb##aa##########aabdcbabaaaa####aa###aa#abbcdhhcaba#baaa#######aaaaabhlmc#a#####aaaaa#a##abba#aabaaabcdgfbb################################aabbaabbccdhigca#########.########aaa########aa#a##aaabbbbccbccdgfha#caaa.##fedbbcbaaaaaaaaa#aaa###aaadecccbbaaaaaa", +"#aa###aaa#a#aaabbbbbcbaa##a#######aaabaababaa#aaaaabbbbbaaababccdecdfhhiihgfdbccbbcbabaaaaaadca##abbaaaaaaa#bb##aaa####aa#aaa#aaaabbda.##########aaaabddcbbaa#a##aa#aaa##aaabbdecca#a#aa#a########aaaaaeili##a######abaa###aaaaaacfeaabddcdbaa##############################aaabbbbbbcdfgjieba####.#####aa#aa############aaaaa###aaabcbbcbbcefggcbbfeedbedbcbabbaaaaaaaaaaaaaaa#aaa#cdcddcbbaaaa", +"aa#a###aa#a##a#aaaabbccaa#aaa########bacbaaaaaaaaaaaabcbbbbbbcedcdccfhfhkhggfdbbccbbabaabaabdda###aaa#aaaaaaacb#########aaaaaa#aaaabec##########aaaaaaabddcbaaaaaaaaaaaa##aabacbaaaba#####a##a######aaabgklbaaa#####aaaaaaaaaaabbbfdaacddeddcbaaa#########aaab##########a##aaaabbcbbbbeffhjifdcb#####.##acbb#aaaa###########aaaa#aaacbcbbcbcegfaccgghgffdcbbaabbbaaa#aaaaaaaaaba#aaaabeecccbaaaa", +"aaaa########aaaabbabbbbcbbbaaaa#####.##aaaaaaaaaaaaabbbbaaaaadedcdccegijkifddebccbbccaabaaa##aa######aaaaaaba#aa#########aaaaaaaaa#bccda#######aaaaabbaaabddcba#aaaaaaaaaaaaabcdaaaaa##abaaa#a#a#a##aaaafhlg.aa#a#a###ba##b#acaabcdfaaaccdccedba##########adcbca#########a#aaabbcddccbdefggiigecb########aaaa#abba###########aaaaaa#bdbccbccef#abdeddeeddccba#bbbbbaaaaaaaaaaabcaaaaaa#eedccbbba", +"aa#aaaaa###aaaaaaaaabbbbbbbbaaaa#######aabaaaaaaaaaabbaaaaabbbfeccccdfiljigcdeccccbccbccbbaaaa#######a#aa##aaa#####..#..#aaabaaaaaaabacb######aaaaaaabbaaaacddcbaaa##cbabaaaaabcbaaaaa###a##a####a##aababchl#.###a#####aaaaaa#aabbdeaaacbbbbdfdccbabb####a#ddbbbba##########abbbccdcccddefghhfcaaa######aab#abaaddaa########ab###aaaacccccdefd#dbgebcccdcaabbbaaaaaaababbbaaabacaaaaaba#eeddcbba", +"aa#aaaaba#a#a##aaababbccbabbbbba########aa#a#aaaaaaaababbaaaaadcccaddfhkjigdcdecccbbcdcecbaaaa######aca####aa#####a#####.#aaaaa#aabababb######aaaaaabbabaaaaabcdcbaaaaaaaaaabbbcaaaa#a####aa####a#aaaaaababjh.####a#####aaa##aaaabdabaaaabbabdeeeddddcb#.##debaaabaaaba####aaabbccdcccddeffgfgcaa##aa###aaaaaccaddca########a#a###aaaccbbceffbaacgeaabbbbabaaaaaaaaaaabaaaabbcaaabaaaabbbccdedcb", +"ba#a#aaaaa####aaaaaaaaaaccbcbbaa#######aaaa###aa##aaaaaaaabbbabbcbbefffhjihfcbfcbcbbbcfhgcaaa#####a#deaa##aaaa###############a##a###aaaaa###aaaabbaaaababbbbbbbbedcbaa#abbbbbcccaa##a######aa##aaa##abaa#aabja##.#######a#a###aaabecaaaaaaacccbcaaaabbdddefedcbaa###aaaa#aaaabbbcccccccddfggghdba####aababababcbbddba###a###a#aaa##aabbcccegfbaabcaaaaaaabbaaaaabbaabaacaabbbabbadbaaaaabba#aefc", +"ba#a#aa#######aaaaaaabaabbebdbbb######aa####a###a####aaaabbaabcabcccddffjhfdbaefcdbbbbdjkjebaa#####bccb##baba#####aa######a###a#a####aaaaa##a##aabaaaaaaabbbbbbabefdbbcbbbcbbbcbaa####aa#######aaaaadaaaaabbdg###a#a####a#aa#aabccccaaaaaabcdbccaaaaabbdeeedcdcba###aa#aabaaabbbcbcccddddeffffdbaa####abccbb#bbccdbccaa###a#aaaa#a#aabbdcdfgdaaaccaaaaaa#aaaaababbaaabbbbbabbbbbcbcbaaaabaa###be", +"fcb#############aa#aaaaaaadegdacbaa###aa####aaa#a####aaaabbaaabaabddccehieabaabecccbbbbbikkgca####acbb###baba#####aa####aaaaaaaa######aa###aaaaaaabaaaaaaaacbbbbbbeffedccbcddddbaaa##aaaa###a##aaa#adba#aaabbie.#.#aa##aaaaaaacecaaaba###a##aabdb#a#aaccccccccbbba###aaa###aaabbbbcccdddedegcddcbbaaaabbabbabbaabbaaddbaa#####aa##aaabbddefgcabagbaaaaaaaaaaaabbaaacabaaaaabbbbabbaaaaaaaaaaaa#a", +"bdeba#########aaaaa###aaaaacfebbbbaa###aa#####aa########aaababaacbdeccehhbaaaaaddcbbbbbcgijhea####acb########a##aa#a##a#aaaaabaaaa####aaab###aaaaaaaaaababbccbbbbacbedffedcdeeaaaab#aaa#aa##a##aa#a###aa#aabackc.#.##aaaaaabdefb#a#aaaaa#a####abc####abcbbeecbbaaabb#aaaaaaaabbbbcbcdededdefdcaccbca##aaaa###aaaaabaaeccaaa###aaa#aaabcccdffbbacfc#a#a#aaaaaaabbaaaaeabcbbabbbbcbbabb#aaaaaaa#aa", +"##aba######aaaaaaaa##a#aaa#fdaabbccb###################a#aaaabbabccccdehibabbbbcfdcbbbabgihc#a####abbaa##a###aa##a#aaaa##aaa##aaaaba###daaa###abcaaabaaabbbbbccbcbcdcdddggfedbcbaaaaa##a#####aaaa#aa#####abbbbdjb.a##aaaaabeecabba##aabda######aa####aaabbdcdcbaa#bcbbaaaaaaaabbbcccddedefffdcbccbab####a#####a#aaabaabeeba######aaacbcddegebbacccba##a#aaaaaaaaaaaaccbbbbbabaaa#aaabbaaaaaaaaaa", +"aa##baa####aaabaaaaa#####aacaababbccbaa##################aaaaaaaabbccbegifaaaabbcecbbbbaadgb#####aeeabc#.######aa##aaaaa#aaaaa###abaa##edaaaa##aabbaaaabbbbbbbccbbdccccdddehhdabbaaaaaa##a###aaaabb######cebcbcgj#aa##abdfggcbbbaaaabdfea####aaaaa##aa###aaa#aaaa#aaabbaaaaaaaabbccddeeddeffeeeefcabaa#aa#####aa#aabbbacccbaaaaaaaabcccdegfbbbceaacb#####aaaaaaaaaaaacccabaaaaa#a#abbccaabbaaaa#", +"#aaa#daaaaaaaabbbaaaa####abbaabaabcbbbbb##aa################aaaaabbbddehecacbaaaabecbbbbabaa#####adcca#########a#a##daaaaacaaaaaa###aa#aca#aa##aaaabbbaabccbbbbcddaccdeddecfhgcabaaa#ab#a####a####aaa#aaaabbbcbcijdchihgighedbcbbcdfdabbbbccaaaaaa###caa#aaaa#a#a##aaaaaaaaaaaaabcccdddddeeedeeeffbaaaaaa##aa###aaabbbabcdeabaaaabbbbcdegibabbfaabca####a#acca#aaaaaaababbbaaaa##aaababbaaabaaaa", +"#####adcbbbaabbbaaaa#a#a#####aaaabbaaabcbaa#################aa#aaaaabddgeadbcaaaaabccbbbbba#####a#a##aaaaa###aa#aa#bccaabaac#aaa#####a#..#####aaaaaabcbaaabbbbcdccdcddedceefgfccbaaaaaa#aa###aa##accaaaaaaaabbbbdjkfdfgjjhgfeeeeeedcaabaabaaaaa#####ab#a#aaaa###a####aaaaaaaaaaabbccddccccdccdeeegfbcbcaaa#aaba#aaabdcbbbababbbaabbcccdghg#aadbaabbaa###a##acdaaa#a#aa#baaaaaaaaa#a#aaaccbaabaaa", +"a##a#aaedbbcbabaaaa##a##aa####aaaababbaabacaaa###a#######a####aaaaaaaccehbbbbcbaaaaacdbbbcb#a#a#a#.####aaa##a#aaaaaaabaaaaab##aaaaaaaa#####aaa##aa##abbaaabbbccbccbcdcdcddeffcaabaaaabba#aa####a##bcbaaaabababbbbejib#abccdcbbccba##a##aaaa##a######a##aaaaa#a###a#####aaaaaaaaabbccccccccccccdeegfcdabbaaaaaaa#aaaabccbbbaccbabbbcddefedea#cd##a#aaab#aaa##bcb###aaa##abaaaa#####aaaaabbcbaabbb", +"aa##aa#bhgccbbccbbaaaaa########aaaaabcbaaaabbaaaa###aa#####a#a#aaaabbbbcega##acbabababecccdabaa##########aaaaaaaaaaaaaabaaa####aaaaaaaa##.##abaaa#aaaaabbbbbbbbcdbbccddcdcegeaaaab#aaaaaaaaa####aabbabbcbbbcaaabbcegiaaaaaa##abbcbca##.###aaaaa####aaa##abbaa#aaaaa####aaaabbaaabbbbccccbcccdddedfddcaaaaaaaaaaaaabbccdbbbcecbbccdefged#a###fa######aaaaaaaabaa#######aab#aaaa#aa#aaaaaabcccabaa", +"aa##aadafhhfeccbbbaa#aaa##a####a#aaaaaaaaaaaaaaaaabaaaabaa#aa###aaaaaabbcfd#a#acbaaaaabeecdcc#############abbaaaaaaaababbba###aaaaaaa#a#####aa#aaaaaa#aaaabbbabcccehgeecdegebaaaaaaaaa#aaa#aa###aaaaababccbbaa#aabceggaaaaaa#aaaabcb####a###aaba######a#a#####aaaaba#####aabbaaaabcbbbbcbbacceeddeebabdbabbaaaaaababcdccdccdcbbccefecb#####cc#########aaaaaaaaaa##ba#aaaaabbbbaaa#aaaaaabcccdgdb", +"##aaacdggggghgdbbbbbaaaaa#aa###a###aa##aaaaaaaaaaaaabcbbaaaaaa#aaaaaaabbbdfd#aaacdaaaaaadgefc#######a#a###abb##a#aaabaaaaaa#######aaa#a########aaaaa##aabbbbbbbbccefhfeeegfbbba#aaaaaaaaaaaa####aa##abbcdacbaa##aabcehfaaaa###aaababa##.##a#aaaca#a#aaaaaa#aaaa#aabcc#####aaaabbbbbadcabbbbbbceedefcaabcecaaabaaababccdcdddccbbcceda#####baeaa#aaa#####ab##aaaaa##aaa##abbbbbbbbaaaaaaaaabbbagig", +"f#aaaehhfffeffhfbccbbaaaaaaa####a#aaaaa###aaa#a#abaabccabcbabbbbabbaabbbbcehdaaaaaaaaaab#dgeaa##a###########aa####aaaaaaa######a####aaaa###a###aaaaa###aabbbbbacccdedddfgebcbaaaaabbbaabaaba#########abcbdabaaa#aabcdeibaaa######aaaca######aabbb####aaaaaaaaaaa##bbdb####aabbbbaaaacdcaabbbbcceddeccccaba#aaabaaaabccddddddceddeec#aca#aabebaaa#######aaaba#######aaaaabbbabbbbbaaaaaaaaaba#dii", +"hd#aaejiedefeeddedccbaaaaaa########aaa#######a#a#aaaabbaacbbababccbbabbbbbceidbaaaaaaaacbcgeca#############aaaaaaaaaaaba######.a############a##aaaaaaaaaaaacbbbccccedbcfcbbbbaaabbbbaaaaaaababaaa#baaaabababbabaaaaabdfhaaaaa#aa##b#bbaa#####abb##a##aaaabbba#aaaaaacda#####abbbbaa####a#abaabccbdecdbbaaaaaaaaaaaabccceeedcdfgffeba#aa#aa#bcaaa##########aa##a####aaaaa#aaabbbbaaaaabbbcbbbeefh", +"ggecdhjkiefeeddcdefdababaaa########aa##a########abaabaabcdabbcdccbcbabbbbccchiecaa#abbbaaaadeca#####a#######aabaaaaaabba###a##.#############a##aaaaaaaaaaabbbccdddbbeccdbbcbbbabbbbbbcbbaaaabccaaaabaabcabbabaaaabaabcefeabaaaaa####aaccb####aaa###a###aabbab#a#aaa##aaa#####acbba#a######aaaabbbbfefdaaaacaaaaaaaabbbcefffeefbed########a##dbaaa#######a#############a########aaaaaaaaaccfgfhdf", +"efddegijmkfeeeddccdgdbcccbaaa####a#aaa#####a####a###aabbcbabacccdccbbbbbcbbdfijhbaaaaabb###cedbaa###aaa#####aabbccbaaaaa###accb###a##########aaaaaaaaaaaabcbbccddddcddaaaabbbabbbbbbcbaabbbbbaaaabbaaaaabbbbaaa#ccaabbddheabaaaaa####abca#####ba##a####abcaaaaaaaaaa#aaaa#####bbaaa##aaaa##aaabbaaadfdbaabcbaaaaaaabbacehhhhcaaaa#####a#ab##ccaa########aa#############ba#a#aaaa#aaabdaaeffghgff", +"eddcbcdefijgeedcccbbdeccccbaaaaaaaaaa#a#########aaa##a#abcaacccccccbcbbccccdefikibaaaaaaaabbdddca#a#a#aa####aaabbbaaaa##a##aaaba##aa##a######aaaaaaaaaaabbbbbccccddddaabbaabcdbbbccbacbabcbbccbaa#aaaa###baaaaa#a#aaabcdfjb#aaaaaa####abaa.####a##aa####bcbbaaaaaaaa#####aa##abaaa#a##aaaaaaaaaaaaabecbaababaaaaabbbcbcehhcaaa##aaa#######b#.cbabaa#####aa##a#####a#########aa#a#aaabdefffggfefe", +"ddcaaabdefhihecdbbbbacdecccbbaaaaaaaa############aa##aa#ababbcbcbbbababccdceeegijgaaaaaba###bfcdc##aaaaa######aaaaaaaaa#aaaaaacba#aaa#a#ba#aa#aaaaaaaababcbbbbbcedabbaabbaaabbbabbdccbbbaabbbbbaaa#aaaaa##aaaaaa#####abcehka##aaa#####aaaa###..a#aba#####abcaaaaaaa#a##a##a###ba########aaaa####aa#deaaa#aaaaaaabbbbbccefcbaba##abaaaa.#a#ba##dc#a#a####abaabb#a##aa##a###a###aaaaabaceecddhhedd", +"cccbabbcdfffhheccbbbbbcdfccbbbbaaaaaa###############a##aaaabacbbbbaaaacccddcdefhjjhbaaaabaa##dfbbc###aa#aa######aabaabaabbbbbabdb#aa#a###bba#a##aaaabbabbbbbcbbcedbaaaaaaaaabbbbbcbccbcebbbbaaaaaaaaaa#####aaa####aa#aabdegj.############a##a##a#aba####a##baaaaaa#a###aa#aa########a##a#aaaa####a#eeaa###aaaaaaaaabbcdgfdbaa####aabbcb#aabc###cda#aa##aababcbb#a#aa###a##aab#aaaaababdecbcdheed", +"cbbaccbcddeffeedcbbbbbbccffdbbcbabbaaa#aa########a###ca#abaabbbabaaaaabcccddcdgiikjgbaaaaba##afcacba###aa########abbbbaabbbbbbbcbbbb#aa#a###aa##aaaaababbbbcbccdca#a##aaaaabaaabcccbbcbcbaabba##aaaaaba#####aa####aabbbddcdjd.#########.#..#######aba######aaaaaba########aa#######aaa#aba#aaa###aacaaaa##aabaaaaaaabbcefcbbaaaaa##aaacabaaaa###bca#####aaaaacaa#a###a##a#aaa#a#aabbbbcddcccegdd", +"cbbabbbbccddeedddcbbbbbbbbdfheccccbaaaa###########aa#bd##baaaabaaaaaababcddcccggijjjbaaabbaa##bcbabba##aa#######aaaaaaabbbbbbbbbcccaaaa##a##aaa##aaaabbbdbcbbcdfbaaa#aaabbbbbbbbbcccbccdedaaa#aaaabbaaaa#a#aa####a#abcccdccfi###########....#######aa##aaaaaaaaaaa##########a###a##aa#aa#aaa#####aaa#aaaa##abbbaaaaabcdefbbaaaaabaa####aa####a#a#dba#####bb##b###########aaaaa#aaabbaabbbccddede", +"baabbbbbccccdeedcccbbccbcbbcdiheccbbbaaaaa#aab##aa###aa###aaaacbaaaaaababccccdfhjjjl#abbbaaba#abeaabb######a#####bbaa#aaaabbbcbbabbaa###aa####a###aaaabacdcccdceaaaaaaaaaababbbbbbbcbbbcbdba###aabbbaaa#aa##########aabbabccgb.###.#########.########a#aaaa#abaa#########a##aa#####bcaabaaba###aaaaaaaa#####aaaaaabbbdhidabaaaaaaaa###########a###ebbb###aaa####a###aa#aabcaabbaaababaaabbbbbdcb", +"abcbbbbbbbccbbcddbcbbbbbbbbbcfeghfccbbabaaaaabaaaa####a#b##aaaabbaa#aaaaabccbceefhegdedaaaaaaa#abdaaba#aa##a#####aaaabaaaaaaabbbaacc###aa#aa####a#aaaaaaabcccddfbba#aaaaaabbbbabbccccccbcbdaa#####ac#####a##########aa#aabcbdh..#########.#####.####aaa#aaa###abb###########accaa###a##aaabbbba#a##a#abba####aaaaaccegcbbaaaaaaa#aa###.##a########aeaaaa###a#a######aaa##aaaaaaaabbaabbaacaacced", +"cadbbbbbbcbccbbacbbbbbbbbabccdeehgffccbcbaaabaaaaaa###a####aaa#aaaaaaaaaaabccbdeeffeehgcaabaaa##adb#aca##aaa#####aaabaaaaaaaaaabaacdb##aaaaaaa#abbaaabbbabbdecffbaaaaaaaaaaaaaabbaccbcbcccdcaa#############aabb######aaaaabbbehd..###d#.#.######.####adbaaaa##abba########aaaaaaaaaaaaa#aaaaaaa#a#aa#abaaa####aaacdeheaaaaaaaaa##aa#aa#####a####a#.cdaa######a##a###########aa##aabb#aabaaabbadf", +"cabdabbbabcccdccbccbbbbbbaabdcdefdcfgccbbbbaabcbaaa###aa##aca####aaa##aabbbccccddffhihhfbaba#c###bdaaagaaa#a######aabaabaaaaaaaa#a#aa####aaaa#aabbaaaabbbbbcddfeca###aaaaabbaabbabbcbccbbbccdada###aa######aaba####a###abaabcafjlf..defe##...#########bbaaa###aab#a#######aaabcb#aaaaaca##aaaa####a##aab###a##aabdfiida###aaaaa##ca#aa#####a####a###ecaaa########a##a#####a####a###aaaaaaaaaabab", +"ccbbbbabbaaabccdcbbbbbbaaaabcdbbbeeadgeccbbbbabbbaaa##aa#abedbaa####a####bbbcbccddehhhfdaa###da#a#ddaabhaa###########a#abaabbaa######a####aaaaaaaaaabbbbbbcbdeefcb###aaaaaaaaaabbbbccccbbaabbcaaa############aacbaabaaaaaaabccbdejkbd..bgccdcba########aa######aaa#a#######aaaccaba#bcaaba#a##aaa#####abba#aa#aabdgkjkihgdb#.cedcbb#.###dc########b##ebaaaa#########################aaa#aaaaaaba", +"abeecbbaababbbabbdbabbbbbaaabcccbdcb#ehedccbbaabbbaaa#abaaaedba###########acbbbcceeeggdaaa#bacaa#aadabbdf#######.#######aaaaaa######bca###aaaaaaaaaabbbbbbbccfffbaaaa#aaaaa#aaaabbccabbcccbbbbaaaaa#######a#aa#acaaaaaaaaaaaabccceglh.#....#baacca..####ab########aaa####a##ababbbba#ceaaaaaa###a######aa##acbbbbchgcddfgjihddigefegfffba#affeecbbaaabda#aa######a#a################aaaa#aaaaaab", +"babfdcbcbabaabababbbaaaaaaaabcccdbaaaacifddcbbbbbbbabaabaacecabaaaaa######aaabbcdeeedifba#adcbaaba#bcabbfe#aa####aaa###a#abaaaa######aaaac#aaaaaaaabbbdbbbbcceebbba##aaaaaaa#aaabbbbbbcccdcabaaaaab##a#aaaaaaa######abaaaaa#abbbbddei#####a####.#ee######aa######aaaba######abaaaa#a##bc##aa#a####a###a#aaaabcbbbceecbbcbdeffgfdccccdefeefgffedcefeb##cdbcba########a###########a###aaaabaaaaaaa" +}; +SIMPLE = T BITPIX = 8 NAXIS = 2 NAXIS1 = 384 NAXIS2 = 384 HISTORY Written by XV 3.10a END 3"3wUD3D3"3""3"3"333""""""""3DDDU3""""DªwUUD3333333"3""3""DfD"3""""""""33DUfffUªw3""UD3""3"3D"33wf"""""""3""""""""D""""""""333U3333DDff333"""""""""""333333DDDUD"3"""""3"""""""""3""""""3333UUfª" diff --git a/tests/simple.c b/tests/simple.c new file mode 100644 index 0000000000..47893772f7 --- /dev/null +++ b/tests/simple.c @@ -0,0 +1,39 @@ +#include <gtk/gtk.h> +#include <gdk/gdkprivate.h> + + +void +hello () +{ + g_print ("hello world\n"); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *button; + + gdk_progclass = g_strdup ("XTerm"); + gtk_init (&argc, &argv); + + window = gtk_widget_new (gtk_window_get_type (), + "GtkObject::user_data", NULL, + "GtkWindow::type", GTK_WINDOW_TOPLEVEL, + "GtkWindow::title", "hello world", + "GtkWindow::allow_grow", FALSE, + "GtkWindow::allow_shrink", FALSE, + "GtkContainer::border_width", 10, + NULL); + button = gtk_widget_new (gtk_button_get_type (), + "GtkButton::label", "hello world", + "GtkObject::signal::clicked", hello, NULL, + "GtkWidget::parent", window, + "GtkWidget::visible", TRUE, + NULL); + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/tests/test.xpm b/tests/test.xpm new file mode 100644 index 0000000000..9b0d2efdb2 --- /dev/null +++ b/tests/test.xpm @@ -0,0 +1,92 @@ +/* XPM */ +static char *openfile[] = { +/* width height num_colors chars_per_pixel */ +" 20 19 66 2", +/* colors */ +".. c None", +".# c #000000", +".a c #dfdfdf", +".b c #7f7f7f", +".c c #006f6f", +".d c #00efef", +".e c #009f9f", +".f c #004040", +".g c #00bfbf", +".h c #ff0000", +".i c #ffffff", +".j c #7f0000", +".k c #007070", +".l c #00ffff", +".m c #00a0a0", +".n c #004f4f", +".o c #00cfcf", +".p c #8f8f8f", +".q c #6f6f6f", +".r c #a0a0a0", +".s c #7f7f00", +".t c #007f7f", +".u c #5f5f5f", +".v c #707070", +".w c #00f0f0", +".x c #009090", +".y c #ffff00", +".z c #0000ff", +".A c #00afaf", +".B c #00d0d0", +".C c #00dfdf", +".D c #005f5f", +".E c #00b0b0", +".F c #001010", +".G c #00c0c0", +".H c #000f0f", +".I c #00007f", +".J c #005050", +".K c #002f2f", +".L c #dfcfcf", +".M c #dfd0d0", +".N c #006060", +".O c #00e0e0", +".P c #00ff00", +".Q c #002020", +".R c #dfc0c0", +".S c #008080", +".T c #001f1f", +".U c #003f3f", +".V c #007f00", +".W c #00000f", +".X c #000010", +".Y c #00001f", +".Z c #000020", +".0 c #00002f", +".1 c #000030", +".2 c #00003f", +".3 c #000040", +".4 c #00004f", +".5 c #000050", +".6 c #00005f", +".7 c #000060", +".8 c #00006f", +".9 c #000070", +"#. c #7f7f80", +"## c #9f9f9f", +/* pixels */ +"........................................", +"........................................", +"........................................", +".......................#.#.#............", +".....................#.......#...#......", +"...............................#.#......", +".......#.#.#.................#.#.#......", +".....#.y.i.y.#.#.#.#.#.#.#..............", +".....#.i.y.i.y.i.y.i.y.i.#..............", +".....#.y.i.y.i.y.i.y.i.y.#..............", +".....#.i.y.i.y.#.#.#.#.#.#.#.#.#.#.#....", +".....#.y.i.y.#.s.s.s.s.s.s.s.s.s.#......", +".....#.i.y.#.s.s.s.s.s.s.s.s.s.#........", +".....#.y.#.s.s.s.s.s.s.s.s.s.#..........", +".....#.#.s.s.s.s.s.s.s.s.s.#............", +".....#.#.#.#.#.#.#.#.#.#.#..............", +"........................................", +"........................................", +"........................................" +}; diff --git a/tests/testgtk.c b/tests/testgtk.c new file mode 100644 index 0000000000..b1d698a083 --- /dev/null +++ b/tests/testgtk.c @@ -0,0 +1,3110 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 <stdio.h> +#include <stdlib.h> +#include "gtk.h" +#include "../gdk/gdk.h" +#include "../gdk/gdkx.h" + + +void +destroy_window (GtkWidget *widget, + GtkWidget **window) +{ + *window = NULL; +} + +void +button_window (GtkWidget *widget, + GtkWidget *button) +{ + if (!GTK_WIDGET_VISIBLE (button)) + gtk_widget_show (button); + else + gtk_widget_hide (button); +} + +void +create_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *table; + GtkWidget *button[10]; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + table = gtk_table_new (3, 3, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_border_width (GTK_CONTAINER (table), 10); + gtk_box_pack_start (GTK_BOX (box1), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + + button[0] = gtk_button_new_with_label ("button1"); + button[1] = gtk_button_new_with_label ("button2"); + button[2] = gtk_button_new_with_label ("button3"); + button[3] = gtk_button_new_with_label ("button4"); + button[4] = gtk_button_new_with_label ("button5"); + button[5] = gtk_button_new_with_label ("button6"); + button[6] = gtk_button_new_with_label ("button7"); + button[7] = gtk_button_new_with_label ("button8"); + button[8] = gtk_button_new_with_label ("button9"); + + gtk_signal_connect (GTK_OBJECT (button[0]), "clicked", + (GtkSignalFunc) button_window, + button[1]); + + gtk_table_attach (GTK_TABLE (table), button[0], 0, 1, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[0]); + + gtk_signal_connect (GTK_OBJECT (button[1]), "clicked", + (GtkSignalFunc) button_window, + button[2]); + + gtk_table_attach (GTK_TABLE (table), button[1], 1, 2, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[1]); + + gtk_signal_connect (GTK_OBJECT (button[2]), "clicked", + (GtkSignalFunc) button_window, + button[3]); + gtk_table_attach (GTK_TABLE (table), button[2], 2, 3, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[2]); + + gtk_signal_connect (GTK_OBJECT (button[3]), "clicked", + (GtkSignalFunc) button_window, + button[4]); + gtk_table_attach (GTK_TABLE (table), button[3], 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[3]); + + gtk_signal_connect (GTK_OBJECT (button[4]), "clicked", + (GtkSignalFunc) button_window, + button[5]); + gtk_table_attach (GTK_TABLE (table), button[4], 2, 3, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[4]); + + gtk_signal_connect (GTK_OBJECT (button[5]), "clicked", + (GtkSignalFunc) button_window, + button[6]); + gtk_table_attach (GTK_TABLE (table), button[5], 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[5]); + + gtk_signal_connect (GTK_OBJECT (button[6]), "clicked", + (GtkSignalFunc) button_window, + button[7]); + gtk_table_attach (GTK_TABLE (table), button[6], 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[6]); + + gtk_signal_connect (GTK_OBJECT (button[7]), "clicked", + (GtkSignalFunc) button_window, + button[8]); + gtk_table_attach (GTK_TABLE (table), button[7], 2, 3, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[7]); + + gtk_signal_connect (GTK_OBJECT (button[8]), "clicked", + (GtkSignalFunc) button_window, + button[0]); + gtk_table_attach (GTK_TABLE (table), button[8], 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[8]); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button[9] = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button[9]), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button[9], TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button[9], GTK_CAN_DEFAULT); + gtk_widget_grab_default (button[9]); + gtk_widget_show (button[9]); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_toggle_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "toggle buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_toggle_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_toggle_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_toggle_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_check_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "check buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_check_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_check_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_check_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_radio_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "radio buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_radio_button_new_with_label (NULL, "button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_radio_button_new_with_label ( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + "button2"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_radio_button_new_with_label ( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + "button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +bbox_widget_destroy (GtkWidget* widget, GtkWidget* todestroy) +{ +} + +void +create_bbox_window (gint horizontal, + char* title, + gint pos, + gint spacing, + gint child_w, + gint child_h, + gint layout) +{ + GtkWidget* window; + GtkWidget* box1; + GtkWidget* bbox; + GtkWidget* button; + + /* create a new window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), title); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) bbox_widget_destroy, window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) bbox_widget_destroy, window); + + if (horizontal) + { + gtk_widget_set_usize (window, 550, 60); + gtk_widget_set_uposition (window, 150, pos); + box1 = gtk_vbox_new (FALSE, 0); + } + else + { + gtk_widget_set_usize (window, 150, 400); + gtk_widget_set_uposition (window, pos, 200); + box1 = gtk_vbox_new (FALSE, 0); + } + + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + if (horizontal) + bbox = gtk_hbutton_box_new(); + else + bbox = gtk_vbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing); + gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h); + gtk_widget_show (bbox); + + gtk_container_border_width (GTK_CONTAINER(box1), 25); + gtk_box_pack_start (GTK_BOX (box1), bbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_container_add (GTK_CONTAINER(bbox), button); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) bbox_widget_destroy, window); + + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Cancel"); + gtk_container_add (GTK_CONTAINER(bbox), button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Help"); + gtk_container_add (GTK_CONTAINER(bbox), button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +void +test_hbbox () +{ + create_bbox_window (TRUE, "Spread", 50, 40, 85, 28, GTK_BUTTONBOX_SPREAD); + create_bbox_window (TRUE, "Edge", 200, 40, 85, 25, GTK_BUTTONBOX_EDGE); + create_bbox_window (TRUE, "Start", 350, 40, 85, 25, GTK_BUTTONBOX_START); + create_bbox_window (TRUE, "End", 500, 15, 30, 25, GTK_BUTTONBOX_END); +} + +void +test_vbbox () +{ + create_bbox_window (FALSE, "Spread", 50, 40, 85, 25, GTK_BUTTONBOX_SPREAD); + create_bbox_window (FALSE, "Edge", 250, 40, 85, 28, GTK_BUTTONBOX_EDGE); + create_bbox_window (FALSE, "Start", 450, 40, 85, 25, GTK_BUTTONBOX_START); + create_bbox_window (FALSE, "End", 650, 15, 30, 25, GTK_BUTTONBOX_END); +} + +void +create_button_box () +{ + static GtkWidget* window = NULL; + GtkWidget* bbox; + GtkWidget* button; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), + "Button Box Test"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, &window); + + gtk_container_border_width (GTK_CONTAINER (window), 20); + + /* + *these 15 lines are a nice and easy example for GtkHButtonBox + */ + bbox = gtk_hbutton_box_new (); + gtk_container_add (GTK_CONTAINER (window), bbox); + gtk_widget_show (bbox); + + button = gtk_button_new_with_label ("Horizontal"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) test_hbbox, 0); + gtk_container_add (GTK_CONTAINER (bbox), button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Vertical"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) test_vbbox, 0); + gtk_container_add (GTK_CONTAINER (bbox), button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +void +reparent_label (GtkWidget *widget, + GtkWidget *new_parent) +{ + GtkWidget *label; + + label = gtk_object_get_user_data (GTK_OBJECT (widget)); + + gtk_widget_reparent (label, new_parent); +} + +void +create_reparent () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *frame; + GtkWidget *button; + GtkWidget *label; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + label = gtk_label_new ("Hello World"); + + frame = gtk_frame_new ("Frame 1"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + button = gtk_button_new_with_label ("switch"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) reparent_label, + box3); + gtk_object_set_user_data (GTK_OBJECT (button), label); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + gtk_box_pack_start (GTK_BOX (box3), label, FALSE, TRUE, 0); + gtk_widget_show (label); + + + frame = gtk_frame_new ("Frame 2"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + button = gtk_button_new_with_label ("switch"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) reparent_label, + box3); + gtk_object_set_user_data (GTK_OBJECT (button), label); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_pixmap () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *button; + GtkWidget *label; + GtkWidget *separator; + GtkWidget *pixmapwid; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "pixmap"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + gtk_widget_realize(window); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new (); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 0); + gtk_widget_show (button); + + style=gtk_widget_get_style(button); + + pixmap = gdk_pixmap_create_from_xpm (window->window, &mask, + &style->bg[GTK_STATE_NORMAL], + "test.xpm"); + pixmapwid = gtk_pixmap_new (pixmap, mask); + + label = gtk_label_new ("Pixmap\ntest"); + box3 = gtk_hbox_new (FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (box3), 2); + gtk_container_add (GTK_CONTAINER (box3), pixmapwid); + gtk_container_add (GTK_CONTAINER (box3), label); + gtk_container_add (GTK_CONTAINER (button), box3); + gtk_widget_show (pixmapwid); + gtk_widget_show (label); + gtk_widget_show (box3); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_tooltips () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkTooltips *tooltips; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "tooltips"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + tooltips=gtk_tooltips_new(); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_toggle_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips(tooltips,button,"This is button 1"); + + button = gtk_toggle_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips(tooltips,button,"This is button 2"); + + button = gtk_toggle_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips (tooltips, button, "This is button 3. This is also a really long tooltip which probably won't fit on a single line and will therefore need to be wrapped. Hopefully the wrapping will work correctly."); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_tooltips_set_tips (tooltips, button, "Push this button to close window"); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +GtkWidget* +create_menu (int depth) +{ + GtkWidget *menu; + GtkWidget *submenu; + GtkWidget *menuitem; + GSList *group; + char buf[32]; + int i, j; + + if (depth < 1) + return NULL; + + menu = gtk_menu_new (); + submenu = NULL; + group = NULL; + + for (i = 0, j = 1; i < 5; i++, j++) + { + sprintf (buf, "item %2d - %d", depth, j); + menuitem = gtk_radio_menu_item_new_with_label (group, buf); + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem)); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_widget_show (menuitem); + + if (depth > 0) + { + if (!submenu) + submenu = create_menu (depth - 1); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); + } + } + + return menu; +} + +void +create_menus () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *menu; + GtkWidget *menubar; + GtkWidget *menuitem; + GtkWidget *optionmenu; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "menus"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + menubar = gtk_menu_bar_new (); + gtk_box_pack_start (GTK_BOX (box1), menubar, FALSE, TRUE, 0); + gtk_widget_show (menubar); + + menu = create_menu (2); + + menuitem = gtk_menu_item_new_with_label ("test\nline2"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_label ("foo"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_label ("bar"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_item_right_justify (GTK_MENU_ITEM (menuitem)); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + optionmenu = gtk_option_menu_new (); + gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), create_menu (1)); + gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), 4); + gtk_box_pack_start (GTK_BOX (box2), optionmenu, TRUE, TRUE, 0); + gtk_widget_show (optionmenu); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_scrolled_windows () +{ + static GtkWidget *window; + GtkWidget *scrolled_window; + GtkWidget *table; + GtkWidget *button; + char buffer[32]; + int i, j; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + scrolled_window, TRUE, TRUE, 0); + gtk_widget_show (scrolled_window); + + table = gtk_table_new (20, 20, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 10); + gtk_table_set_col_spacings (GTK_TABLE (table), 10); + gtk_container_add (GTK_CONTAINER (scrolled_window), table); + gtk_widget_show (table); + + for (i = 0; i < 20; i++) + for (j = 0; j < 20; j++) + { + sprintf (buffer, "button (%d,%d)\n", i, j); + button = gtk_toggle_button_new_with_label (buffer); + gtk_table_attach_defaults (GTK_TABLE (table), button, + i, i+1, j, j+1); + gtk_widget_show (button); + } + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_entry () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *entry; + GtkWidget *button; + GtkWidget *separator; + + /* if (!window) */ + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "entry"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + entry = gtk_entry_new (); + /* gtk_widget_set_usize (entry, 0, 25); */ + gtk_entry_set_text (GTK_ENTRY (entry), "hello world"); + gtk_box_pack_start (GTK_BOX (box2), entry, TRUE, TRUE, 0); + gtk_widget_show (entry); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + /* else + gtk_widget_destroy (window); */ +} + +void +list_add (GtkWidget *widget, + GtkWidget *list) +{ + static int i = 1; + gchar buffer[64]; + GtkWidget *list_item; + + sprintf (buffer, "added item %d", i++); + list_item = gtk_list_item_new_with_label (buffer); + gtk_widget_show (list_item); + gtk_container_add (GTK_CONTAINER (list), list_item); +} + +void +list_remove (GtkWidget *widget, + GtkWidget *list) +{ + GList *tmp_list; + GList *clear_list; + + tmp_list = GTK_LIST (list)->selection; + clear_list = NULL; + + while (tmp_list) + { + clear_list = g_list_prepend (clear_list, tmp_list->data); + tmp_list = tmp_list->next; + } + + clear_list = g_list_reverse (clear_list); + + gtk_list_remove_items (GTK_LIST (list), clear_list); + + tmp_list = clear_list; + + while (tmp_list) + { + gtk_widget_destroy (GTK_WIDGET (tmp_list->data)); + tmp_list = tmp_list->next; + } + + g_list_free (clear_list); +} + +void +create_list () +{ + static GtkWidget *window = NULL; + static char *list_items[] = + { + "hello", + "world", + "blah", + "foo", + "bar", + "argh", + "spencer", + "is a", + "wussy", + "programmer", + }; + static int nlist_items = sizeof (list_items) / sizeof (list_items[0]); + + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *scrolled_win; + GtkWidget *list; + GtkWidget *list_item; + GtkWidget *button; + GtkWidget *separator; + int i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "list"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (box2), scrolled_win, TRUE, TRUE, 0); + gtk_widget_show (scrolled_win); + + list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_MULTIPLE); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE); + gtk_container_add (GTK_CONTAINER (scrolled_win), list); + gtk_widget_show (list); + + for (i = 0; i < nlist_items; i++) + { + list_item = gtk_list_item_new_with_label (list_items[i]); + gtk_container_add (GTK_CONTAINER (list), list_item); + gtk_widget_show (list_item); + } + + button = gtk_button_new_with_label ("add"); + GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) list_add, + list); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("remove"); + GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) list_remove, + list); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +color_selection_ok (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + gdouble color[4]; + + colorsel=GTK_COLOR_SELECTION(cs->colorsel); + + gtk_color_selection_get_color(colorsel,color); + gtk_color_selection_set_color(colorsel,color); +} + +void +color_selection_changed (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + gdouble color[4]; + + colorsel=GTK_COLOR_SELECTION(cs->colorsel); + gtk_color_selection_get_color(colorsel,color); +} + +void +create_color_selection () +{ + static GtkWidget *window = NULL; + + if (!window) + { + gtk_preview_set_install_cmap (TRUE); + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_color_selection_dialog_new ("color selection dialog"); + + gtk_color_selection_set_opacity ( + GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + TRUE); + + gtk_color_selection_set_update_policy( + GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + GTK_UPDATE_CONTINUOUS); + + gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_signal_connect ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + "color_changed", + (GtkSignalFunc) color_selection_changed, + window); + + gtk_signal_connect ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->ok_button), + "clicked", + (GtkSignalFunc) color_selection_ok, + window); + + gtk_signal_connect_object ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->cancel_button), + "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +void +file_selection_ok (GtkWidget *w, + GtkFileSelection *fs) +{ + g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))); +} + +void +create_file_selection () +{ + static GtkWidget *window = NULL; + + if (!window) + { + window = gtk_file_selection_new ("file selection dialog"); + gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button), + "clicked", (GtkSignalFunc) file_selection_ok, + window); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkDialog + */ +static GtkWidget *dialog_window = NULL; + +void +label_toggle (GtkWidget *widget, + GtkWidget **label) +{ + if (!(*label)) + { + *label = gtk_label_new ("Dialog Test"); + gtk_misc_set_padding (GTK_MISC (*label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->vbox), + *label, TRUE, TRUE, 0); + gtk_widget_show (*label); + } + else + { + gtk_widget_destroy (*label); + *label = NULL; + } +} + +void +create_dialog () +{ + static GtkWidget *label; + GtkWidget *button; + + if (!dialog_window) + { + dialog_window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (dialog_window), "destroy", + (GtkSignalFunc) destroy_window, + &dialog_window); + gtk_signal_connect (GTK_OBJECT (dialog_window), "delete_event", + (GtkSignalFunc) destroy_window, + &dialog_window); + + gtk_window_set_title (GTK_WINDOW (dialog_window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (dialog_window), 0); + + button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Toggle"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) label_toggle, + &label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + label = NULL; + } + + if (!GTK_WIDGET_VISIBLE (dialog_window)) + gtk_widget_show (dialog_window); + else + gtk_widget_destroy (dialog_window); +} + + +/* + * GtkRange + */ +void +create_range_controls () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *scrollbar; + GtkWidget *scale; + GtkWidget *separator; + GtkObject *adjustment; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "range controls"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + adjustment = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0); + + scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment)); + gtk_widget_set_usize (GTK_WIDGET (scale), 150, 30); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_scale_set_digits (GTK_SCALE (scale), 1); + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adjustment)); + gtk_range_set_update_policy (GTK_RANGE (scrollbar), + GTK_UPDATE_CONTINUOUS); + gtk_box_pack_start (GTK_BOX (box2), scrollbar, TRUE, TRUE, 0); + gtk_widget_show (scrollbar); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkRulers + */ +void +create_rulers () +{ + static GtkWidget *window = NULL; + GtkWidget *table; + GtkWidget *ruler; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "rulers"); + gtk_widget_set_usize (window, 300, 300); + gtk_widget_set_events (window, + GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + table = gtk_table_new (2, 2, FALSE); + gtk_container_add (GTK_CONTAINER (window), table); + gtk_widget_show (table); + + ruler = gtk_hruler_new (); + gtk_ruler_set_range (GTK_RULER (ruler), 5, 15, 0, 20); + + gtk_signal_connect_object ( + GTK_OBJECT (window), + "motion_notify_event", + (GtkSignalFunc) + GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event, + GTK_OBJECT (ruler)); + + gtk_table_attach (GTK_TABLE (table), ruler, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (ruler); + + + ruler = gtk_vruler_new (); + gtk_ruler_set_range (GTK_RULER (ruler), 5, 15, 0, 20); + + gtk_signal_connect_object ( + GTK_OBJECT (window), + "motion_notify_event", + (GtkSignalFunc) + GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event, + GTK_OBJECT (ruler)); + + gtk_table_attach (GTK_TABLE (table), ruler, 0, 1, 1, 2, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (ruler); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkText + */ +void +create_text () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkWidget *table; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *text; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "text window"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + text = gtk_text_new (NULL, NULL); + gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); + gtk_widget_show (text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + gtk_text_freeze (GTK_TEXT (text)); + + gtk_widget_realize (text); + + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "spencer blah blah blah\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "kimball\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "is\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "a\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "wuss.\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "but\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "josephine\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "(his\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "girlfriend\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "is\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "not).\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "why?\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "because\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "spencer\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "puked\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "last\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "night\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "but\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "josephine\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "did\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "not", -1); + + gtk_text_thaw (GTK_TEXT (text)); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkNotebook + */ +void +rotate_notebook (GtkButton *button, + GtkNotebook *notebook) +{ + gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos + 1) % 4); +} + +void +create_notebook () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkWidget *notebook; + GtkWidget *frame; + GtkWidget *label; + char buffer[32]; + int i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "notebook"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + notebook = gtk_notebook_new (); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + gtk_box_pack_start (GTK_BOX (box2), notebook, TRUE, TRUE, 0); + gtk_widget_show (notebook); + + + for (i = 0; i < 5; i++) + { + sprintf (buffer, "Page %d", i+1); + + frame = gtk_frame_new (buffer); + gtk_container_border_width (GTK_CONTAINER (frame), 10); + gtk_widget_set_usize (frame, 200, 150); + gtk_widget_show (frame); + + label = gtk_label_new (buffer); + gtk_container_add (GTK_CONTAINER (frame), label); + gtk_widget_show (label); + + label = gtk_label_new (buffer); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label); + } + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("next"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_next_page, + GTK_OBJECT (notebook)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("prev"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_prev_page, + GTK_OBJECT (notebook)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("rotate"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) rotate_notebook, + notebook); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkPanes + */ +void +create_panes () +{ + static GtkWidget *window = NULL; + GtkWidget *frame; + GtkWidget *hpaned; + GtkWidget *vpaned; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Panes"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + vpaned = gtk_vpaned_new (); + gtk_container_add (GTK_CONTAINER (window), vpaned); + gtk_container_border_width (GTK_CONTAINER(vpaned), 5); + gtk_widget_show (vpaned); + + hpaned = gtk_hpaned_new (); + gtk_paned_add1 (GTK_PANED (vpaned), hpaned); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 60, 60); + gtk_paned_add1 (GTK_PANED (hpaned), frame); + gtk_widget_show (frame); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 80, 60); + gtk_paned_add2 (GTK_PANED (hpaned), frame); + gtk_widget_show (frame); + + gtk_widget_show (hpaned); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 60, 80); + gtk_paned_add2 (GTK_PANED (vpaned), frame); + gtk_widget_show (frame); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Drag -N- Drop + */ +void +dnd_drop (GtkWidget *button, GdkEvent *event) +{ + g_print ("Got drop of type |%s| with data of:\n%s\n", + event->dropdataavailable.data_type, + event->dropdataavailable.data); + g_free (event->dropdataavailable.data); + g_free (event->dropdataavailable.data_type); +} + +void +dnd_drag_request (GtkWidget *button, GdkEvent *event) +{ + g_print ("Button |%s| got drag request %d\n", + gtk_widget_get_name (button), event->type); + + gtk_widget_dnd_data_set (button, event, "Hello world!!!", + strlen("Hello world!!!") + 1); +} + +void +create_dnd () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *entry; + GtkWidget *frame; + GtkWidget *button; + GtkWidget *separator; + char *foo = "testing"; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Drag -N- Drop"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + frame = gtk_frame_new ("Drag"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + /* + * FROM Button + */ + button = gtk_button_new_with_label ("From"); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + /* + * currently, the widget has to be realized to + * set dnd on it, this needs to change + */ + gtk_widget_realize (button); + gtk_signal_connect (GTK_OBJECT (button), + "drag_request_event", + (GtkSignalFunc) dnd_drag_request, + button); + + gtk_widget_dnd_drag_set (button, TRUE, &foo, 1); + + + frame = gtk_frame_new ("Drop"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + + /* + * TO Button + */ + button = gtk_button_new_with_label ("To"); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + gtk_widget_realize (button); + gtk_signal_connect (GTK_OBJECT (button), + "drop_data_available_event", + (GtkSignalFunc) dnd_drop, + button); + + gtk_widget_dnd_drop_set (button, TRUE, &foo, 1, FALSE); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +/* + * Shaped Windows + */ +static GdkWindow *root_win = NULL; +static GtkWidget *modeller = NULL; +static GtkWidget *sheets = NULL; +static GtkWidget *rings = NULL; + +typedef struct _cursoroffset {gint x,y;} CursorOffset; + +static void +shape_pressed (GtkWidget *widget) +{ + CursorOffset *p; + + p = gtk_object_get_user_data (GTK_OBJECT(widget)); + gtk_widget_get_pointer (widget, &(p->x), &(p->y)); + + gtk_grab_add (widget); + gdk_pointer_grab (widget->window, TRUE, + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK, + NULL, NULL, 0); +} + + +static void +shape_released (GtkWidget *widget) +{ + gtk_grab_remove (widget); + gdk_pointer_ungrab (0); +} + +static void +shape_motion (GtkWidget *widget, + GdkEventMotion *event) +{ + gint xp, yp; + CursorOffset * p; + GdkModifierType mask; + + p = gtk_object_get_user_data (GTK_OBJECT (widget)); + + gdk_window_get_pointer (root_win, &xp, &yp, &mask); + gtk_widget_set_uposition (widget, xp - p->x, yp - p->y); +} + +GtkWidget * +shape_create_icon (char *xpm_file, + gint x, + gint y, + gint px, + gint py, + gint window_type) +{ + GtkWidget *window; + GtkWidget *pixmap; + GtkWidget *fixed; + CursorOffset* icon_pos; + GdkGC* gc; + GdkBitmap *gdk_pixmap_mask; + GdkPixmap *gdk_pixmap; + GtkStyle *style; + + style = gtk_widget_get_default_style (); + gc = style->black_gc; + + /* + * GDK_WINDOW_TOPLEVEL works also, giving you a title border + */ + window = gtk_window_new (window_type); + + fixed = gtk_fixed_new (); + gtk_widget_set_usize (fixed, 100,100); + gtk_container_add (GTK_CONTAINER (window), fixed); + gtk_widget_show (fixed); + + gdk_pixmap = gdk_pixmap_create_from_xpm (window->window, &gdk_pixmap_mask, + &style->bg[GTK_STATE_NORMAL], + xpm_file); + + pixmap = gtk_pixmap_new (gdk_pixmap, gdk_pixmap_mask); + gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py); + gtk_widget_show (pixmap); + + gtk_widget_shape_combine_mask (window, gdk_pixmap_mask, px,py); + + gtk_widget_set_events (window, + gtk_widget_get_events (window) | + GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK); + + gtk_signal_connect (GTK_OBJECT (window), "button_press_event", + GTK_SIGNAL_FUNC (shape_pressed),NULL); + gtk_signal_connect (GTK_OBJECT (window), "button_release_event", + GTK_SIGNAL_FUNC (shape_released),NULL); + gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event", + GTK_SIGNAL_FUNC (shape_motion),NULL); + + icon_pos = g_new (CursorOffset, 1); + gtk_object_set_user_data(GTK_OBJECT(window), icon_pos); + + gtk_widget_set_uposition (window, x, y); + gtk_widget_show (window); + + return window; +} + +void +create_shapes () +{ + root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ()); + + if (!modeller) + { + modeller = shape_create_icon ("Modeller.xpm", + 440, 140, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (modeller), "destroy", + (GtkSignalFunc) destroy_window, + &modeller); + gtk_signal_connect (GTK_OBJECT (modeller), "delete_event", + (GtkSignalFunc) destroy_window, + &modeller); + } + else + gtk_widget_destroy (modeller); + + if (!sheets) + { + sheets = shape_create_icon ("FilesQueue.xpm", + 580, 170, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (sheets), "destroy", + (GtkSignalFunc) destroy_window, + &sheets); + gtk_signal_connect (GTK_OBJECT (sheets), "delete_event", + (GtkSignalFunc) destroy_window, + &sheets); + + } + else + gtk_widget_destroy (sheets); + + if (!rings) + { + rings = shape_create_icon ("3DRings.xpm", + 460, 270, 25,25, GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (rings), "destroy", + (GtkSignalFunc) destroy_window, + &rings); + gtk_signal_connect (GTK_OBJECT (rings), "delete_event", + (GtkSignalFunc) destroy_window, + &rings); + } + else + gtk_widget_destroy (rings); +} + + +/* + * Progress Bar + */ +static int progress_timer = 0; + +gint +progress_timeout (gpointer data) +{ + gfloat new_val; + + new_val = GTK_PROGRESS_BAR (data)->percentage; + if (new_val >= 1.0) + new_val = 0.0; + new_val += 0.02; + + gtk_progress_bar_update (GTK_PROGRESS_BAR (data), new_val); + + return TRUE; +} + +void +destroy_progress (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + gtk_timeout_remove (progress_timer); + progress_timer = 0; +} + +void +create_progress_bar () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *pbar; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_progress, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_progress, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (vbox), 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new ("progress..."); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_widget_show (label); + + pbar = gtk_progress_bar_new (); + gtk_widget_set_usize (pbar, 200, 20); + gtk_box_pack_start (GTK_BOX (vbox), pbar, TRUE, TRUE, 0); + gtk_widget_show (pbar); + + progress_timer = gtk_timeout_add (100, progress_timeout, pbar); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Color Preview + */ +static int color_idle = 0; + +gint +color_idle_func (GtkWidget *preview) +{ + static int count = 1; + guchar buf[768]; + int i, j, k; + + for (i = 0; i < 256; i++) + { + for (j = 0, k = 0; j < 256; j++) + { + buf[k+0] = i + count; + buf[k+1] = 0; + buf[k+2] = j + count; + k += 3; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + count += 1; + + gtk_widget_draw (preview, NULL); + + return TRUE; +} + +void +color_preview_destroy (GtkWidget *widget, + GtkWidget **window) +{ + gtk_idle_remove (color_idle); + color_idle = 0; + + destroy_window (widget, window); +} + +void +create_color_preview () +{ + static GtkWidget *window = NULL; + GtkWidget *preview; + guchar buf[768]; + int i, j, k; + + if (!window) + { + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) color_preview_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) color_preview_destroy, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + preview = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (preview), 256, 256); + gtk_container_add (GTK_CONTAINER (window), preview); + gtk_widget_show (preview); + + for (i = 0; i < 256; i++) + { + for (j = 0, k = 0; j < 256; j++) + { + buf[k+0] = i; + buf[k+1] = 0; + buf[k+2] = j; + k += 3; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + color_idle = gtk_idle_add ((GtkFunction) color_idle_func, preview); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Gray Preview + */ +static int gray_idle = 0; + +gint +gray_idle_func (GtkWidget *preview) +{ + static int count = 1; + guchar buf[256]; + int i, j; + + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) + buf[j] = i + j + count; + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + count += 1; + + gtk_widget_draw (preview, NULL); + + return TRUE; +} + +void +gray_preview_destroy (GtkWidget *widget, + GtkWidget **window) +{ + gtk_idle_remove (gray_idle); + gray_idle = 0; + + destroy_window (widget, window); +} + +void +create_gray_preview () +{ + static GtkWidget *window = NULL; + GtkWidget *preview; + guchar buf[256]; + int i, j; + + if (!window) + { + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gray_preview_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) gray_preview_destroy, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + preview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE); + gtk_preview_size (GTK_PREVIEW (preview), 256, 256); + gtk_container_add (GTK_CONTAINER (window), preview); + gtk_widget_show (preview); + + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) + buf[j] = i + j; + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + gray_idle = gtk_idle_add ((GtkFunction) gray_idle_func, preview); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Selection Test + */ +void +selection_test_received (GtkWidget *list, GtkSelectionData *data) +{ + GdkAtom *atoms; + GtkWidget *list_item; + GList *item_list; + int i, l; + + if (data->length < 0) + { + g_print ("Selection retrieval failed\n"); + return; + } + if (data->type != GDK_SELECTION_TYPE_ATOM) + { + g_print ("Selection \"TARGETS\" was not returned as atoms!\n"); + return; + } + + /* Clear out any current list items */ + + gtk_list_clear_items (GTK_LIST(list), 0, -1); + + /* Add new items to list */ + + atoms = (GdkAtom *)data->data; + + item_list = NULL; + l = data->length / sizeof (GdkAtom); + for (i = 0; i < l; i++) + { + char *name; + name = gdk_atom_name (atoms[i]); + if (name != NULL) + { + list_item = gtk_list_item_new_with_label (name); + g_free (name); + } + else + list_item = gtk_list_item_new_with_label ("(bad atom)"); + + gtk_widget_show (list_item); + item_list = g_list_append (item_list, list_item); + } + + gtk_list_append_items (GTK_LIST (list), item_list); + + return; +} + +void +selection_test_get_targets (GtkWidget *widget, GtkWidget *list) +{ + static GdkAtom targets_atom = GDK_NONE; + + if (targets_atom == GDK_NONE) + targets_atom = gdk_atom_intern ("TARGETS", FALSE); + + gtk_selection_convert (list, GDK_SELECTION_PRIMARY, targets_atom, + GDK_CURRENT_TIME); +} + +void +create_selection_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *scrolled_win; + GtkWidget *list; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Selection Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + /* Create the list */ + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (vbox), 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, + TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new ("Gets available targets for current selection"); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0); + gtk_widget_set_usize (scrolled_win, 100, 200); + gtk_widget_show (scrolled_win); + + list = gtk_list_new (); + gtk_container_add (GTK_CONTAINER (scrolled_win), list); + + gtk_signal_connect (GTK_OBJECT(list), "selection_received", + GTK_SIGNAL_FUNC (selection_test_received), NULL); + gtk_widget_show (list); + + /* .. And create some buttons */ + button = gtk_button_new_with_label ("Get Targets"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (selection_test_get_targets), list); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Gamma Curve + */ +void +create_gamma_curve () +{ + static GtkWidget *window = NULL, *curve; + static int count = 0; + gfloat vec[256]; + gint max; + gint i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + curve = gtk_gamma_curve_new (); + gtk_container_add (GTK_CONTAINER (window), curve); + gtk_widget_show (curve); + } + + max = 127 + (count % 2)*128; + gtk_curve_set_range (GTK_CURVE (GTK_GAMMA_CURVE (curve)->curve), + 0, max, 0, max); + for (i = 0; i < max; ++i) + vec[i] = (127 / sqrt (max)) * sqrt (i); + gtk_curve_set_vector (GTK_CURVE (GTK_GAMMA_CURVE (curve)->curve), + max, vec); + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else if (count % 4 == 3) + { + gtk_widget_destroy (window); + window = NULL; + } + + ++count; +} + + +/* + * Timeout Test + */ +static int timer = 0; + +void +timeout_test (GtkWidget *label) +{ + static int count = 0; + static char buffer[32]; + + sprintf (buffer, "count: %d", ++count); + gtk_label_set (GTK_LABEL (label), buffer); +} + +void +start_timeout_test (GtkWidget *widget, + GtkWidget *label) +{ + if (!timer) + { + timer = gtk_timeout_add (100, (GtkFunction) timeout_test, label); + } +} + +void +stop_timeout_test (GtkWidget *widget, + gpointer data) +{ + if (timer) + { + gtk_timeout_remove (timer); + timer = 0; + } +} + +void +destroy_timeout_test (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + stop_timeout_test (NULL, NULL); +} + +void +create_timeout_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_timeout_test, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_timeout_test, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Timeout Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + label = gtk_label_new ("count: 0"); + gtk_misc_set_padding (GTK_MISC (label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + label, TRUE, TRUE, 0); + gtk_widget_show (label); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("start"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) start_timeout_test, + label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("stop"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) stop_timeout_test, + NULL); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Idle Test + */ +static int idle = 0; + +gint +idle_test (GtkWidget *label) +{ + static int count = 0; + static char buffer[32]; + + sprintf (buffer, "count: %d", ++count); + gtk_label_set (GTK_LABEL (label), buffer); + + return TRUE; +} + +void +start_idle_test (GtkWidget *widget, + GtkWidget *label) +{ + if (!idle) + { + idle = gtk_idle_add ((GtkFunction) idle_test, label); + } +} + +void +stop_idle_test (GtkWidget *widget, + gpointer data) +{ + if (idle) + { + gtk_idle_remove (idle); + idle = 0; + } +} + +void +destroy_idle_test (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + stop_idle_test (NULL, NULL); +} + +void +create_idle_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_idle_test, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_idle_test, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Idle Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + label = gtk_label_new ("count: 0"); + gtk_misc_set_padding (GTK_MISC (label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + label, TRUE, TRUE, 0); + gtk_widget_show (label); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("start"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) start_idle_test, + label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("stop"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) stop_idle_test, + NULL); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +test_destroy (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + gtk_main_quit (); +} + +/* + * Basic Test + */ +void +create_test () +{ + static GtkWidget *window = NULL; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) test_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) test_destroy, + &window); + + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + } + + if (!GTK_WIDGET_VISIBLE (window)) + { + gtk_widget_show (window); + + g_print ("create_test: start\n"); + gtk_main (); + g_print ("create_test: done\n"); + } + else + gtk_widget_destroy (window); +} + + +/* + * Main Window and Exit + */ +void +do_exit () +{ + gtk_exit (0); +} + +void +create_main_window () +{ + struct { + char *label; + void (*func) (); + } buttons[] = + { + { "buttons", create_buttons }, + { "toggle buttons", create_toggle_buttons }, + { "check buttons", create_check_buttons }, + { "radio buttons", create_radio_buttons }, + { "button box", create_button_box }, + { "reparent", create_reparent }, + { "pixmap", create_pixmap }, + { "tooltips", create_tooltips }, + { "menus", create_menus }, + { "scrolled windows", create_scrolled_windows }, + { "drawing areas", NULL }, + { "entry", create_entry }, + { "list", create_list }, + { "color selection", create_color_selection }, + { "file selection", create_file_selection }, + { "dialog", create_dialog }, + { "miscellaneous", NULL }, + { "range controls", create_range_controls }, + { "rulers", create_rulers }, + { "text", create_text }, + { "notebook", create_notebook }, + { "panes", create_panes }, + { "shapes", create_shapes }, + { "dnd", create_dnd }, + { "progress bar", create_progress_bar }, + { "preview color", create_color_preview }, + { "preview gray", create_gray_preview }, + { "gamma curve", create_gamma_curve }, + { "test selection", create_selection_test }, + { "test timeout", create_timeout_test }, + { "test idle", create_idle_test }, + { "test", create_test }, + }; + int nbuttons = sizeof (buttons) / sizeof (buttons[0]); + GtkWidget *window; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *scrolled_window; + GtkWidget *button; + GtkWidget *separator; + int i; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "main window"); + gtk_widget_set_usize (window, 200, 400); + gtk_widget_set_uposition (window, 20, 20); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gtk_exit, + NULL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) gtk_exit, + NULL); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (box1), scrolled_window, TRUE, TRUE, 0); + gtk_widget_show (scrolled_window); + + box2 = gtk_vbox_new (FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_container_add (GTK_CONTAINER (scrolled_window), box2); + gtk_widget_show (box2); + + for (i = 0; i < nbuttons; i++) + { + button = gtk_button_new_with_label (buttons[i].label); + if (buttons[i].func) + gtk_signal_connect (GTK_OBJECT (button), + "clicked", + (GtkSignalFunc) + buttons[i].func, NULL); + else + gtk_widget_set_sensitive (button, FALSE); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) do_exit, NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +int +main (int argc, char *argv[]) +{ + gtk_set_locale (); + + gtk_init (&argc, &argv); + gtk_rc_parse ("testgtkrc"); + + create_main_window (); + + gtk_main (); + + return 0; +} diff --git a/tests/testgtkrc b/tests/testgtkrc new file mode 100644 index 0000000000..e909e314b0 --- /dev/null +++ b/tests/testgtkrc @@ -0,0 +1,69 @@ +# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..." +# +# style <name> [= <name>] +# { +# <option> +# } +# +# widget <widget_set> style <style_name> +# widget_class <widget_class_set> style <style_name> + +pixmap_path "." + +style "window" +{ +# bg_pixmap[NORMAL] = "warning.xpm" +} + +style "scale" +{ + fg[NORMAL] = { 1.0, 0, 0 } + bg_pixmap[NORMAL] = "<parent>" +} + +style "button" +{ + fg[PRELIGHT] = { 1.0, 1.0, 1.0 } + bg[PRELIGHT] = { 0, 0, 0.75 } +} + +style "main_button" = "button" +{ + font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*" + bg[PRELIGHT] = { 0.75, 0, 0 } +} + +style "toggle_button" = "button" +{ + fg[NORMAL] = { 1.0, 0, 0 } + fg[ACTIVE] = { 1.0, 0, 0 } + bg_pixmap[NORMAL] = "<parent>" +} + +style "text" +{ + bg_pixmap[NORMAL] = "marble.xpm" + fg[NORMAL] = { 1.0, 1.0, 1.0 } +} + +style "ruler" +{ + font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*" +} + +style "curve" +{ + fg[NORMAL] = { 58000, 0, 0 } # red +} + +widget_class "GtkWindow" style "window" +widget_class "GtkDialog" style "window" +widget_class "GtkFileSelection" style "window" +widget_class "*Gtk*Scale" style "scale" +widget_class "*GtkCheckButton*" style "toggle_button" +widget_class "*GtkRadioButton*" style "toggle_button" +widget_class "*GtkButton*" style "button" +widget_class "*Ruler" style "ruler" +widget_class "*GtkText" style "text" +widget "main window.*GtkButton*" style "main_button" +widget "*GtkCurve" style "curve" diff --git a/tests/testinput.c b/tests/testinput.c new file mode 100644 index 0000000000..1c6dae0e1d --- /dev/null +++ b/tests/testinput.c @@ -0,0 +1,379 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtk.h" + +/* Backing pixmap for drawing area */ + +static GdkPixmap *pixmap = NULL; + +/* Information about cursor */ + +static gint need_cursor = FALSE; +static gint cursor_proximity = TRUE; +static gdouble cursor_x; +static gdouble cursor_y; + +/* Unique ID of current device */ +static guint32 current_device = GDK_CORE_POINTER; + +/* Check to see if we need to draw a cursor for current device */ +static void +check_cursor () +{ + GList *tmp_list; + + /* gdk_input_list_devices returns an internal list, so we shouldn't + free it afterwards */ + tmp_list = gdk_input_list_devices(); + + while (tmp_list) + { + GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data; + + if (info->deviceid == current_device) + { + need_cursor = !info->has_cursor; + break; + } + + tmp_list = tmp_list->next; + } +} + +/* Erase the old cursor, and/or draw a new one, if necessary */ +static void +update_cursor (GtkWidget *widget, gdouble x, gdouble y) +{ + static gint cursor_present = 0; + gint state = need_cursor && cursor_proximity; + + if (pixmap != NULL) + { + if (cursor_present && (cursor_present != state || + x != cursor_x || y != cursor_y)) + { + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pixmap, + cursor_x - 5, cursor_y - 5, + cursor_x - 5, cursor_y - 5, + 10, 10); + } + + cursor_present = state; + cursor_x = x; + cursor_y = y; + + if (cursor_present) + { + gdk_draw_rectangle (widget->window, + widget->style->black_gc, + TRUE, + cursor_x - 5, cursor_y -5, + 10, 10); + } + } +} + +/* Create a new backing pixmap of the appropriate size */ +static gint +configure_event (GtkWidget *widget, GdkEventConfigure *event) +{ + if (pixmap) + { + gdk_pixmap_destroy(pixmap); + } + pixmap = gdk_pixmap_new(widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + gdk_draw_rectangle (pixmap, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + return TRUE; +} + +/* Refill the screen from the backing pixmap */ +static gint +expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return FALSE; +} + +/* Draw a rectangle on the screen, size depending on pressure, + and color on the type of device */ +static void +draw_brush (GtkWidget *widget, GdkInputSource source, + gdouble x, gdouble y, gdouble pressure) +{ + GdkGC *gc; + GdkRectangle update_rect; + + switch (source) + { + case GDK_SOURCE_MOUSE: + gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)]; + break; + case GDK_SOURCE_PEN: + gc = widget->style->black_gc; + break; + case GDK_SOURCE_ERASER: + gc = widget->style->white_gc; + break; + default: + gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)]; + } + + update_rect.x = x - 10 * pressure; + update_rect.y = y - 10 * pressure; + update_rect.width = 20 * pressure; + update_rect.height = 20 * pressure; + gdk_draw_rectangle (pixmap, gc, TRUE, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height); + gtk_widget_draw (widget, &update_rect); +} + +static guint32 motion_time; + +static gint +button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + if (event->deviceid != current_device) + { + current_device = event->deviceid; + check_cursor (); + } + + cursor_proximity = TRUE; + + if (event->button == 1 && pixmap != NULL) + { + draw_brush (widget, event->source, event->x, event->y, + event->pressure); + motion_time = event->time; + } + + update_cursor (widget, event->x, event->y); + + return TRUE; +} + +static gint +motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +{ + GdkTimeCoord *coords; + int nevents; + int i; + + if (event->deviceid != current_device) + { + current_device = event->deviceid; + check_cursor (); + } + + cursor_proximity = TRUE; + + if (event->state & GDK_BUTTON1_MASK && pixmap != NULL) + { + coords = gdk_input_motion_events (event->window, event->deviceid, + motion_time, event->time, + &nevents); + motion_time = event->time; + if (coords) + { + for (i=0; i<nevents; i++) + draw_brush (widget, event->source, coords[i].x, coords[i].y, + coords[i].pressure); + g_free (coords); + } + else + { + if (event->is_hint) + gdk_input_window_get_pointer (event->window, event->deviceid, + NULL, NULL, NULL, NULL, NULL, NULL); + draw_brush (widget, event->source, event->x, event->y, + event->pressure); + } + } + else + { + gdk_input_window_get_pointer (event->window, event->deviceid, + &event->x, &event->y, + NULL, NULL, NULL, NULL); + } + + update_cursor (widget, event->x, event->y); + + return TRUE; +} + +/* We track the next two events to know when we need to draw a + cursor */ + +static gint +proximity_out_event (GtkWidget *widget, GdkEventProximity *event) +{ + cursor_proximity = FALSE; + update_cursor (widget, cursor_x, cursor_y); + return TRUE; +} + +static gint +leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) +{ + cursor_proximity = FALSE; + update_cursor (widget, cursor_x, cursor_y); + return TRUE; +} + +void +input_dialog_destroy (GtkWidget *w, gpointer data) +{ + *((GtkWidget **)data) = NULL; +} + +void +create_input_dialog () +{ + static GtkWidget *inputd = NULL; + + if (!inputd) + { + inputd = gtk_input_dialog_new(); + + gtk_signal_connect (GTK_OBJECT(inputd), "destroy", + (GtkSignalFunc)input_dialog_destroy, &inputd); + gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button), + "clicked", + (GtkSignalFunc)gtk_widget_hide, + GTK_OBJECT(inputd)); + gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button); + + gtk_signal_connect (GTK_OBJECT(inputd), "enable_device", + (GtkSignalFunc)check_cursor, NULL); + gtk_widget_show (inputd); + } + else + { + if (!GTK_WIDGET_MAPPED(inputd)) + gtk_widget_show(inputd); + else + gdk_window_raise(inputd->window); + } +} + +void +quit () +{ + gtk_exit (0); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *drawing_area; + GtkWidget *vbox; + + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "Test Input"); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (quit), NULL); + + /* Create the drawing area */ + + drawing_area = gtk_drawing_area_new (); + gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); + gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); + + gtk_widget_show (drawing_area); + + /* Signals used to handle backing pixmap */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", + (GtkSignalFunc) expose_event, NULL); + gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", + (GtkSignalFunc) configure_event, NULL); + + /* Event signals */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", + (GtkSignalFunc) motion_notify_event, NULL); + gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_signal_connect (GTK_OBJECT (drawing_area), "leave_notify_event", + (GtkSignalFunc) leave_notify_event, NULL); + gtk_signal_connect (GTK_OBJECT (drawing_area), "proximity_out_event", + (GtkSignalFunc) proximity_out_event, NULL); + + gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_PROXIMITY_OUT_MASK); + + /* The following call enables tracking and processing of extension + events for the drawing area */ + gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_ALL); + + /* .. And create some buttons */ + button = gtk_button_new_with_label ("Input Dialog"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (create_input_dialog), NULL); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/tests/testselection.c b/tests/testselection.c new file mode 100644 index 0000000000..3377cc6230 --- /dev/null +++ b/tests/testselection.c @@ -0,0 +1,466 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtk.h" + +typedef enum { + SEL_TYPE_NONE, + APPLE_PICT, + ATOM, + ATOM_PAIR, + BITMAP, + C_STRING, + COLORMAP, + COMPOUND_TEXT, + DRAWABLE, + INTEGER, + PIXEL, + PIXMAP, + SPAN, + STRING, + TEXT, + WINDOW, + LAST_SEL_TYPE, +} SelType; + +GdkAtom seltypes[LAST_SEL_TYPE]; + +typedef struct _Target { + gchar *target_name; + SelType type; + GdkAtom target; + gint format; + GtkSelectionFunction *handler; +} Target; + +/* The following is a list of all the selection targets defined + in the ICCCM */ + +static Target targets[] = { + { "ADOBE_PORTABLE_DOCUMENT_FORMAT", STRING, 0, 8, NULL }, + { "APPLE_PICT", APPLE_PICT, 0, 8, NULL }, + { "BACKGROUND", PIXEL, 0, 32, NULL }, + { "BITMAP", BITMAP, 0, 32, NULL }, + { "CHARACTER_POSITION", SPAN, 0, 32, NULL }, + { "CLASS", TEXT, 0, 8, NULL }, + { "CLIENT_WINDOW", WINDOW, 0, 32, NULL }, + { "COLORMAP", COLORMAP, 0, 32, NULL }, + { "COLUMN_NUMBER", SPAN, 0, 32, NULL }, + { "COMPOUND_TEXT", COMPOUND_TEXT, 0, 8, NULL }, + /* { "DELETE", "NULL", 0, ?, NULL }, */ + { "DRAWABLE", DRAWABLE, 0, 32, NULL }, + { "ENCAPSULATED_POSTSCRIPT", STRING, 0, 8, NULL }, + { "ENCAPSULATED_POSTSCRIPT_INTERCHANGE", STRING, 0, 8, NULL }, + { "FILE_NAME", TEXT, 0, 8, NULL }, + { "FOREGROUND", PIXEL, 0, 32, NULL }, + { "HOST_NAME", TEXT, 0, 8, NULL }, + /* { "INSERT_PROPERTY", "NULL", 0, ? NULL }, */ + /* { "INSERT_SELECTION", "NULL", 0, ? NULL }, */ + { "LENGTH", INTEGER, 0, 32, NULL }, + { "LINE_NUMBER", SPAN, 0, 32, NULL }, + { "LIST_LENGTH", INTEGER, 0, 32, NULL }, + { "MODULE", TEXT, 0, 8, NULL }, + /* { "MULTIPLE", "ATOM_PAIR", 0, 32, NULL }, */ + { "NAME", TEXT, 0, 8, NULL }, + { "ODIF", TEXT, 0, 8, NULL }, + { "OWNER_OS", TEXT, 0, 8, NULL }, + { "PIXMAP", PIXMAP, 0, 32, NULL }, + { "POSTSCRIPT", STRING, 0, 8, NULL }, + { "PROCEDURE", TEXT, 0, 8, NULL }, + { "PROCESS", INTEGER, 0, 32, NULL }, + { "STRING", STRING, 0, 8, NULL }, + { "TARGETS", ATOM, 0, 32, NULL }, + { "TASK", INTEGER, 0, 32, NULL }, + { "TEXT", TEXT, 0, 8 , NULL }, + { "TIMESTAMP", INTEGER, 0, 32, NULL }, + { "USER", TEXT, 0, 8, NULL }, +}; + +static int num_targets = sizeof(targets)/sizeof(Target); + +static int have_selection = FALSE; + +GtkWidget *selection_text; +GtkWidget *selection_button; +GString *selection_string = NULL; + +static void +init_atoms () +{ + int i; + + seltypes[SEL_TYPE_NONE] = GDK_NONE; + seltypes[APPLE_PICT] = gdk_atom_intern ("APPLE_PICT",FALSE); + seltypes[ATOM] = gdk_atom_intern ("ATOM",FALSE); + seltypes[ATOM_PAIR] = gdk_atom_intern ("ATOM_PAIR",FALSE); + seltypes[BITMAP] = gdk_atom_intern ("BITMAP",FALSE); + seltypes[C_STRING] = gdk_atom_intern ("C_STRING",FALSE); + seltypes[COLORMAP] = gdk_atom_intern ("COLORMAP",FALSE); + seltypes[COMPOUND_TEXT] = gdk_atom_intern ("COMPOUND_TEXT",FALSE); + seltypes[DRAWABLE] = gdk_atom_intern ("DRAWABLE",FALSE); + seltypes[INTEGER] = gdk_atom_intern ("INTEGER",FALSE); + seltypes[PIXEL] = gdk_atom_intern ("PIXEL",FALSE); + seltypes[PIXMAP] = gdk_atom_intern ("PIXMAP",FALSE); + seltypes[SPAN] = gdk_atom_intern ("SPAN",FALSE); + seltypes[STRING] = gdk_atom_intern ("STRING",FALSE); + seltypes[TEXT] = gdk_atom_intern ("TEXT",FALSE); + seltypes[WINDOW] = gdk_atom_intern ("WINDOW",FALSE); + + for (i=0; i<num_targets; i++) + targets[i].target = gdk_atom_intern (targets[i].target_name, FALSE); +} + +void +selection_toggled (GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + { + have_selection = gtk_selection_owner_set (widget, + GDK_SELECTION_PRIMARY, + GDK_CURRENT_TIME); + if (!have_selection) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE); + } + else + { + if (have_selection) + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, + GDK_CURRENT_TIME); + have_selection = FALSE; + } + } +} + +void +selection_handle (GtkWidget *widget, + GtkSelectionData *selection_data, gpointer data) +{ + guchar *buffer; + gint len; + + if (!selection_string) + { + buffer = NULL; + len = 0; + } + else + { + buffer = selection_string->str; + len = selection_string->len; + } + + gtk_selection_data_set (selection_data, + selection_data->target == seltypes[COMPOUND_TEXT] ? + seltypes[COMPOUND_TEXT] : seltypes[STRING], + 8, buffer, len); +} + +gint +selection_clear (GtkWidget *widget, GdkEventSelection *event) +{ + have_selection = FALSE; + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE); + + return TRUE; +} + +gchar * +stringify_atom (guchar *data, gint *position) +{ + gchar *str = gdk_atom_name (*(GdkAtom *)(data+*position)); + *position += sizeof(GdkAtom); + + return str; +} + +gchar * +stringify_text (guchar *data, gint *position) +{ + gchar *str = g_strdup ((gchar *)(data+*position)); + *position += strlen (str) + 1; + + return str; +} + +gchar * +stringify_xid (guchar *data, gint *position) +{ + gchar buffer[20]; + gchar *str; + + sprintf(buffer,"0x%x",*(guint32 *)(data+*position)); + str = g_strdup (buffer); + + *position += sizeof(guint32); + + return str; +} + +gchar * +stringify_integer (guchar *data, gint *position) +{ + gchar buffer[20]; + gchar *str; + + sprintf(buffer,"%d",*(int *)(data+*position)); + str = g_strdup (buffer); + + *position += sizeof(int); + + return str; +} + +gchar * +stringify_span (guchar *data, gint *position) +{ + gchar buffer[42]; + gchar *str; + + sprintf(buffer,"%d - %d",((int *)(data+*position))[0], + ((int *)(data+*position))[1]); + str = g_strdup (buffer); + + *position += 2*sizeof(int); + + return str; +} + +void +selection_received (GtkWidget *widget, GtkSelectionData *data) +{ + int position; + int i; + SelType seltype; + char *str; + + if (data->length < 0) + { + g_print("Error retrieving selection\n"); + return; + } + + seltype = SEL_TYPE_NONE; + for (i=0; i<LAST_SEL_TYPE; i++) + { + if (seltypes[i] == data->type) + { + seltype = i; + break; + } + } + + if (seltype == SEL_TYPE_NONE) + { + char *name = gdk_atom_name (data->type); + g_print("Don't know how to handle type: %s (%ld)\n", + name?name:"<unknown>", + data->type); + return; + } + + if (selection_string != NULL) + g_string_free (selection_string, TRUE); + + selection_string = g_string_new (NULL); + + gtk_text_freeze (GTK_TEXT (selection_text)); + gtk_text_set_point (GTK_TEXT (selection_text), 0); + gtk_text_foreward_delete (GTK_TEXT (selection_text), + gtk_text_get_length (GTK_TEXT (selection_text))); + + position = 0; + while (position < data->length) + { + switch (seltype) + { + case ATOM: + str = stringify_atom (data->data, &position); + break; + case COMPOUND_TEXT: + case STRING: + case TEXT: + str = stringify_text (data->data, &position); + break; + case BITMAP: + case DRAWABLE: + case PIXMAP: + case WINDOW: + case COLORMAP: + str = stringify_xid (data->data, &position); + break; + case INTEGER: + case PIXEL: + str = stringify_integer (data->data, &position); + break; + case SPAN: + str = stringify_span (data->data, &position); + break; + default: + { + char *name = gdk_atom_name (data->type); + g_print("Can't convert type %s (%ld) to string\n", + name?name:"<unknown>", + data->type); + position = data->length; + } + } + gtk_text_insert (GTK_TEXT (selection_text), NULL, + &selection_text->style->black, + NULL, str, -1); + gtk_text_insert (GTK_TEXT (selection_text), NULL, + &selection_text->style->black, + NULL, "\n", -1); + g_string_append (selection_string, str); + g_free (str); + } + gtk_text_thaw (GTK_TEXT (selection_text)); +} + +void +paste (GtkWidget *widget, GtkWidget *entry) +{ + char *name; + GdkAtom atom; + + name = gtk_entry_get_text (GTK_ENTRY(entry)); + atom = gdk_atom_intern (name, FALSE); + + if (atom == GDK_NONE) + { + g_print("Could not create atom: \"%s\"\n",name); + return; + } + + gtk_selection_convert (selection_button, GDK_SELECTION_PRIMARY, atom, + GDK_CURRENT_TIME); +} + +void +quit () +{ + gtk_exit (0); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *dialog; + GtkWidget *button; + GtkWidget *table; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *hbox; + + gtk_init (&argc, &argv); + + init_atoms(); + + dialog = gtk_dialog_new (); + gtk_widget_set_name (dialog, "Test Input"); + gtk_container_border_width (GTK_CONTAINER(dialog), 0); + + gtk_signal_connect (GTK_OBJECT (dialog), "destroy", + GTK_SIGNAL_FUNC (quit), NULL); + + table = gtk_table_new (4, 2, FALSE); + gtk_container_border_width (GTK_CONTAINER(table), 10); + + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 5); + gtk_table_set_row_spacing (GTK_TABLE (table), 1, 2); + gtk_table_set_row_spacing (GTK_TABLE (table), 2, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), + table, TRUE, TRUE, 0); + gtk_widget_show (table); + + selection_button = gtk_toggle_button_new_with_label ("Claim Selection"); + gtk_table_attach (GTK_TABLE (table), selection_button, 0, 2, 0, 1, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_widget_show (selection_button); + + gtk_signal_connect (GTK_OBJECT(selection_button), "toggled", + GTK_SIGNAL_FUNC (selection_toggled), NULL); + gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event", + GTK_SIGNAL_FUNC (selection_clear), NULL); + gtk_signal_connect (GTK_OBJECT(selection_button), "selection_received", + GTK_SIGNAL_FUNC (selection_received), NULL); + + gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY, + seltypes[STRING], selection_handle, NULL, NULL); + + gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY, + seltypes[TEXT], selection_handle, NULL, NULL); + + gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY, + seltypes[COMPOUND_TEXT], + selection_handle, NULL, NULL); + + selection_text = gtk_text_new (NULL, NULL); + gtk_table_attach_defaults (GTK_TABLE (table), selection_text, 0, 1, 1, 2); + gtk_widget_show (selection_text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (selection_text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (selection_text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 1, 2, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, 3, 4, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_widget_show (hbox); + + label = gtk_label_new ("Target:"); + gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX(hbox), entry, TRUE, TRUE, 0); + gtk_widget_show (entry); + + /* .. And create some buttons */ + button = gtk_button_new_with_label ("Paste"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (paste), entry); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (dialog)); + gtk_widget_show (button); + + gtk_widget_show (dialog); + + gtk_main (); + + return 0; +} |