xfreecd

Audio CD player for X
git clone https://www.brianlane.com/git/xfreecd
Log | Files | Refs | README | LICENSE

commit 3d4331ba3b413b608742d0c5b81cd31e0fbd0ddf
Author: Brian C. Lane <bcl@brianlane.com>
Date:   Tue, 11 Jan 2022 07:52:39 -0800

Initial commit: xfreecd v0.7.8

Diffstat:
ACOPYING | 340+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AHISTORY | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMakefile | 45+++++++++++++++++++++++++++++++++++++++++++++
AREADME | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/a0.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a1.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a2.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a3.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a4.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a5.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a6.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a7.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a8.xpm | 28++++++++++++++++++++++++++++
Abitmaps/a9.xpm | 28++++++++++++++++++++++++++++
Abitmaps/an.xpm | 26++++++++++++++++++++++++++
Abitmaps/b0.xpm | 35+++++++++++++++++++++++++++++++++++
Abitmaps/b1.xpm | 31+++++++++++++++++++++++++++++++
Abitmaps/b2.xpm | 31+++++++++++++++++++++++++++++++
Abitmaps/b3.xpm | 31+++++++++++++++++++++++++++++++
Abitmaps/b4.xpm | 31+++++++++++++++++++++++++++++++
Abitmaps/b5.xpm | 33+++++++++++++++++++++++++++++++++
Abitmaps/b6.xpm | 32++++++++++++++++++++++++++++++++
Abitmaps/b7.xpm | 30++++++++++++++++++++++++++++++
Abitmaps/b8.xpm | 31+++++++++++++++++++++++++++++++
Abitmaps/b9.xpm | 34++++++++++++++++++++++++++++++++++
Abitmaps/bar.xpm | 18++++++++++++++++++
Abitmaps/bn.xpm | 20++++++++++++++++++++
Abitmaps/cdrom.xpm | 22++++++++++++++++++++++
Abitmaps/concept1.xpm | 294+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/ejdn.xpm | 22++++++++++++++++++++++
Abitmaps/ejup.xpm | 22++++++++++++++++++++++
Abitmaps/exitdn.xpm | 22++++++++++++++++++++++
Abitmaps/exitup.xpm | 22++++++++++++++++++++++
Abitmaps/ffdn.xpm | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/ffup.xpm | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/freecd.xpm | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/freecdbase.xpm | 26++++++++++++++++++++++++++
Abitmaps/helpdn.xpm | 22++++++++++++++++++++++
Abitmaps/helpup.xpm | 22++++++++++++++++++++++
Abitmaps/mindn.xpm | 22++++++++++++++++++++++
Abitmaps/minup.xpm | 22++++++++++++++++++++++
Abitmaps/minus.xpm | 29+++++++++++++++++++++++++++++
Abitmaps/mnscddn.xpm | 22++++++++++++++++++++++
Abitmaps/mnscdup.xpm | 22++++++++++++++++++++++
Abitmaps/mnstrkdn.xpm | 22++++++++++++++++++++++
Abitmaps/mnstrkup.xpm | 22++++++++++++++++++++++
Abitmaps/nobar.xpm | 11+++++++++++
Abitmaps/nodisc.xpm | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/null.xpm | 35+++++++++++++++++++++++++++++++++++
Abitmaps/pauseup.xpm | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/playdn.xpm | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/playup.xpm | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/plscddn.xpm | 22++++++++++++++++++++++
Abitmaps/plscdup.xpm | 22++++++++++++++++++++++
Abitmaps/plstrkdn.xpm | 22++++++++++++++++++++++
Abitmaps/plstrkup.xpm | 22++++++++++++++++++++++
Abitmaps/redbar.xpm | 16++++++++++++++++
Abitmaps/rewdn.xpm | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/rewup.xpm | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/rptdn.xpm | 22++++++++++++++++++++++
Abitmaps/rptup.xpm | 22++++++++++++++++++++++
Abitmaps/rptupact.xpm | 22++++++++++++++++++++++
Abitmaps/sfwddn.xpm | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/slice.xpm | 22++++++++++++++++++++++
Abitmaps/srevdn.xpm | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/stopup.xpm | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abitmaps/voldn.xpm | 22++++++++++++++++++++++
Abitmaps/volup.xpm | 22++++++++++++++++++++++
Acd_control.c | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acd_control.h | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acddb.c | 888+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acddb.h | 27+++++++++++++++++++++++++++
Acddbd.c | 1220++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acddbd.h | 37+++++++++++++++++++++++++++++++++++++
Achild_sync.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Achild_sync.h | 10++++++++++
Axfreecd.c | 5293+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axfreecd.gif | 0
Axfreecd.h | 34++++++++++++++++++++++++++++++++++
Axfreecd.lsm | 21+++++++++++++++++++++
Axfreecd.sig | 0
Axfreecd.spec | 36++++++++++++++++++++++++++++++++++++
Axfreecd.wmconfig | 4++++
Axfreecd.xpm | 341+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axpm_button.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axpm_button.h | 24++++++++++++++++++++++++
86 files changed, 11605 insertions(+), 0 deletions(-)

diff --git a/COPYING b/COPYING @@ -0,0 +1,340 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 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. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, 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 software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, 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 show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, 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 redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), 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 Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/HISTORY b/HISTORY @@ -0,0 +1,64 @@ +0.7.8 Attempt to fix a bug that some people report happens 100% and that + happens about 5% for me. sigsegv after retrieving the cddb data. I + added some code to make sure displat.plabel was equal to NULL after + the progress box is destroyed (this didn't fix it, but cannot hurt) + And I removed a write to the progress box just before it is deleted. + At the moment this 'appears' to have fixed the problem. Tell me if + it hasn't! + +0.7.7 Small bugfix. In cddbd.c I had a small string that was a holdover + from the old way of ding things. It was catted onto the end of each + frame request sent to the server. Depending on the state of memory + it may have done nothing, or may have scrambled the request string. + It has now been fixed. + +0.7.6 Just a few minor bugfixes. I wasn't calculating the length of track + 1 correctly (because of the change from 1-99 ot 0-98 internally). + Fixed a problem with the first original submission to CDDB being + revision 2 instead of revision 1. + XfreeCD v0.7.6 and later are now certified to submit CD info to + the CDDB database. Thanks Steve! + Added real cddb submission email address. + Added RPM building to the Makefile. Thanks to Vincent Cautaerts + for creating the RPM version of 0.7.5 that I based this on. + +0.7.5 Massive Changes Again: + I removed all the static string storage used for the title + and track names and replaced with dynamic storage using the + GTK+ GString. Works pretty good. + Added support for extended CD information. This was required + to meet the standards for being able to submit CD information + the the CDDB database. You cannot edit this data in the + program, but it is preserved on disk, and can be edited with + a text editor if necisary + Fixed problems relating to 99 track CDs (NIN-Broken broke + things). + Added support for the Revision # downloaded from the cddb + database. When the CD is sent to the database for an updte + the Revision # is incremented by 1 + Changing the category of a CD now automatically erases the + old copy of the data in the old category. + Added support for multiple DTITLE, TTITLE, EXTD, EXTT, etc. + lines in the cddb support routines. + +0.7.4 Added sending CDDB updates to the server via email + Fixed a bug where changing categories would leave the entry in the + old category directory. + Fixed a bug that would display the previous CDs info in the Track + window while retrieving new CD data from the server. + Fixed a problem with editing. It wasn't initalizing the title or + the category, so if these weren't edited it could have ended up + in the wrong place. + Added support for multiple TITLEx lines in the CDDB file. + Fixed a bug when editing CD tracks with > 8 tracks. The clist was + popping back to the top after selecting the track to edit. This + now works right (I changed the way I update the list). + +0.7.3 Added titlebar control using different class names for the different + windows. + +0.7.2 Added -geometry support + + +0.7 Added CDDB support, rewrote low level controls. Split into 3 + processes. diff --git a/Makefile b/Makefile @@ -0,0 +1,45 @@ +# +# Makefile for XfreeCD +# Copyright 1998 by Brian C. Lane +# +ifeq ($(strip $(CC)),) + CC = gcc +else + CC:=${CC} +endif + +VERSION = 0.7.8 +CFLAGS = -O2 -Wall -pipe `gtk-config --cflags` -DVERSION=\"$(VERSION)\" +LDFLAGS = `gtk-config --libs` + +OBJS = xfreecd.o cd_control.o cddbd.o cddb.o child_sync.o xpm_button.o + +all: xfreecd + +xfreecd: $(OBJS) + $(CC) $(OBJS) -o xfreecd $(LDFLAGS) + +clean: + rm -f *.o *~ xfreecd xfreecd-$(VERSION).tar.gz core + rm -rf xfreecd-$(VERSION) + rm -f xfreecd-$(VERSION)-1.spec + rm -f xfreecd-$(VERSION).lsm + +# Build the tarball +dist: xfreecd +# gpg --detach-sig xfreecd + rm -rf xfreecd-$(VERSION) + mkdir xfreecd-$(VERSION) + mkdir xfreecd-$(VERSION)/bitmaps + cp bitmaps/* xfreecd-$(VERSION)/bitmaps + cp {Makefile,*.c,*.h,xfreecd,README,HISTORY,COPYING,xfreecd.xpm,xfreecd.gif,xfreecd.wmconfig,xfreecd.spec,xfreecd.lsm,xfreecd.sig} xfreecd-$(VERSION)/ + tar cvzf xfreecd-$(VERSION).tar.gz xfreecd-$(VERSION)/* + ln -s xfreecd.lsm xfreecd-$(VERSION).lsm + +# Build RedHat binary and source RPMs +rpm: dist + cp xfreecd-$(VERSION).tar.gz /usr/src/redhat/SOURCES + cp xfreecd.gif /usr/src/redhat/SOURCES + rm -f xfreecd-$(VERSION)-1.spec + ln -s xfreecd.spec xfreecd-$(VERSION)-1.spec + rpm -ba -vv xfreecd-$(VERSION)-1.spec diff --git a/README b/README @@ -0,0 +1,225 @@ + + XfreeCD v0.7.8 (c) 1998 by Brian C. Lane http://www.tatoosh.com/nexus +=============================================================================== + + + Hello! + + Thanks for trying out XfreeCD. The first thing is that you need to have a +copy of GTK+ v1.0.2 or later installed. This is the Gimp Toolkit, so if you +have a recent version of Gimp installed you are ready to compile XfreeCD by +typing make. If you don't have GTK+ then you need to download and install it. +It is available from http://www.gimp.org/gtk/ and the install is pretty easy. +Sorry about this (I know I hate having to install other stuff just to run +a program), but GTK+ is well worth it (as is Gimp) -- you will be seeing +many more programs using GTK+ in the future. + + Ok, so if you have GTK+ installed you can type make in the xfreecd directory +to build xfreecd. Then copy the xfreecd binary it to your favorite location and +run it. The standard place is in /usr/local/bin + + The program initially uses /dev/cdrom to access the CD device. This can be +changed in the setup dialog box (click on the question mark). It does not +work with SCSI devices yet, but that's on ly list of things to find other +people to do <G>. + + You also have to make sure you have read permission for the CD device. You +can do this by executing chmod ugo+r /dev/sbpcd (or whatever your device +is). Make sure you change the device itself, not a symlink like /dev/cdrom +since that won't work. + + Please read over the rest of this document! + + + + + What is xfreecd? + ---------------- + + XfreeCD is a X windows program that looks like the frontpanel of a cd +player. I stole the images from the win95 freeCD program. My thanks to Nate +Smith for making his code freely available. + + You can play CDs, move between tracks, adjust volume -- clicking the left +button on the speaker icon increases the volume. Clicking the right button +will decrease the volume. You can display 4 different times on the display: + + 1. Time elapsed on the track (icon has a plus and a 1/4 cdrom on it) + 2. Time remaining on the track (icon has a minus and 1/4 cdrom on it) + 3. Time elapsed on cdrom (icon has a plus and a full cdrom) + 4. Time remaining on cdrom (icon has a minus and a full cdrom) + + The repeat key causes the cdrom to keep playing when it reaches the end of +the cdrom. The question mark key opens a setup dialog box with 3 tabs for +the different setup screens. The 'Setup' tab allows you to set the CD device +to use and 3 other buttons: + + 1. AutoPlay When this is selected XfreeCD will start playing + the CD if there is one in the drive. If a CD is + already playing it doesn't disturb it. + + 2. Eject when done When selected this will eject the CD when it is done + playing it if the repeat button on the front panel + is not selected. + + 4. Eject on exit When this is selected and you exit XfreeCD with + the CD stopped or paused it will eject the CD. + + + A new feature for this version is support for the internet CD database CDDB +created by Ti Kan and Steve Scherf (Thanks Guys!). Select the CDDB tab from +the setup menu to setup this option. The Local CDDB path is where it will +store the CD info when it is downloaded from the internet or entered locally. +A number of directories are created under this directory for the different +categories of CDs (this is handles automatically, you don't need to create +any directories yourself, just make sure you have the right permissions for +the location you select). + + The CDDB server is the internet site that you want to use to retrieve CD +track names from. This should probably be geographicly near you for the +best performance. Initially only cddb.cddb.com is selected. A list of the +current sites can be downloaded by pressing the Refresh Servers button. + + The CDDB Submit email address is the email address of the CDDB server to +submit new CDs to. The default is xmcd-cddb@amb.org and the test address +is test-cddb@cddb.cddb.com -- The test address will tell you if the submission +would have been accepted or not. You can submit CD info from the Track Edit +window by pressing the 'Send to Server' button. This uses the 'cat' and 'mail' +programs, and they should be in your current PATH for it to work. + + As of version 0.7.6 XfreeCD submissions to the cddb database are accepted! +Now you can add that obscure CD of yours to the worldwide database. + + If the CDDB support button is selected XfreeCD will first search the local +database (it does this even if CDDB is not selected) for the current CD's +unique discid. If that fails then it will attempt to connect to the CDDB +server that you have selected and download the CD info. It will then store +that data locally. CDDB submission is available even when CDDB download +support is turned off. + + To use the CDDB download feature you will need to have your internet +connection online or be using a program like diald to automatically connect +to the internet. + + The track names are displayed by doing a left click in the main display +window (the one showing the time and track #). Doing a right click in +this window allows you to drag the XfreeCD window anywhere on your desktop. + + + At the bottom of the track list window is a button labeled 'edit tracks' +Click on it and another window similar to the first will be opened. Here +you can edit the track names and save the changes to the local database. +You don't need to have the internet CDDB support enabled. + + + Version 0.7 is a complete rewrite of the code. The old code didn't run +as well as I liked, the user interface was sometimes slow because it was +waiting for a response from the low-level CD routines which can sometimes +take a noticeable amount of time. And I wanted to add CDDB support without +the 'freezing' of alot of X programs. + + Some people requested track seeking (skipping forward a few seconds +within the track). I tried to implement this, but it seems that the +low level CD device drivers don't implement this function very well and +I removed the option (It would crash often and leave the cd_control +process with no way to kill it since it was frozen waiting for a kernel +call to finish). I have tested other players and none of them implement +this feature any better. If you want to add it yourself and can get it +to work, I'd be happy to integrate it into the next release of XfreeCD. + + If you do a 'ps' while running xfreecd you will notice 3 processes +running. This is perfectly normal. One process handles the GTK+ user +interface, another handles the low-level CD control and the third is the +cddb internet interface. + + In version 0.7.5 I have reduced the amount of static memory storage used +for strings, so you should notice a slightly smaller memory foorprint. On +my system a 'ps xm | grep xfreecd' shows: + + +v0.7.4 + PID TTY MAJFLT MINFLT TRS DRS SIZE SWAP RSS SHRD LIB DT COMMAND + 3183 p3 0 3 44 532 576 0 576 552 0 50 xfreecd + 3182 p3 14 7 48 588 636 0 636 592 0 52 xfreecd + 3181 p3 389 198 76 1500 1576 0 1576 1184 0 119 xfreecd + +v0.7.5 + PID TTY MAJFLT MINFLT TRS DRS SIZE SWAP RSS SHRD LIB DT COMMAND + 3189 p3 0 3 40 500 540 0 540 516 0 43 ./xfreecd + 3188 p3 14 5 48 532 580 0 580 556 0 43 ./xfreecd + 3187 p3 408 169 80 1404 1484 0 1484 1184 0 96 ./xfreecd + + + Not a huge difference, but an improvement. + + + -geometry + --------- + + XfreeCD now recognizes the -geometry command for x/y placement on the +screen. Use the standard X geometry placement parameters. Width and Height +are ignored. I use 'xfreecd -geometry +580-80' to place it at the end of my +AfterStep Wharf bar. + + The only small glitch with this is if you have titlebars on and use geometry +the placement will be relative to the main XfreeCD window, without respect to +the size of the titlebars. + + Title Bars + ---------- + + If you want to modify the way the XfreeCD windows look (I like the main +window to have no title bar and no resize bars) you can tell your window +manager to remove them. This depends on what manager you are running. There +are 5 types of windows associated with XfreeCD, but usually you will only be +concerned with the main window. + + XfreeCD is the main window. + XfreeCDt is the Track List window. + XfreeCDet is the Edit Track list window. + XfreeCDp is the progress window while connecting to the internet CDDB server. + XfreeCDs is the setup window. + + I run AfterStep, and to setup the main window without title bar or resize +handles you add a line like this to the database file: + + Style "XfreeCD" NoTitle, NoHandles + + +SCSI Support: + + I don't have a SCSI CD drive, so it would be difficult for me to test +any code I wrote. But it is possible for someone to modify the cd_control +module to support SCSI drives, preferably through a user selectable +button in the setup menu, not via compile time (I'm trying to make it +easy to distribute this as a binary for those who don't have gcc +installed on their system). + + This is beta software and it may have memory leaks and other problems. +Please report any problems or ideas to me for inclusion in future versions. + + Brian Lane + Nexus Computing + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + +Hall of Thanks +-------------- + +I would like to thank all of the beta testers for their help, bug reports, +and suggestions. If I have forgotten anyone, please let me know and I'll add +you to the list. + +Vincent Cautaerts (vincent@comf5.comm.eng.osaka-u.ac.jp) did the +RPM package for RedHat users for v0.7.5 (I have taken over the rpm +generation as of v0.7.6, so send any errors to me). + +The guys at www.cddb.com for their strict requirements for submission to +the database. They revealed several bug that have now been squashed. + +Users of v0.7.6 for reporting the error 500 problem and forcing me to +look over the code once again. I found the bug and squashed it! + +Users of v0.7.7 who kept insisting that it was sigsegving after a cddb +retrieval. I believed you! Really! diff --git a/bitmaps/a0.xpm b/bitmaps/a0.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a0_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +". .XXXXX. .", +"X. .X", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"X. .X", +". .", +". .", +"X. .X", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"X. .X", +". .XXXXX. .", +" .XXXXXXX. "}; diff --git a/bitmaps/a1.xpm b/bitmaps/a1.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a1_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" ", +" .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .", +" .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .", +" "}; diff --git a/bitmaps/a2.xpm b/bitmaps/a2.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a2_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +" .XXXXX. .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .XXXXX. .", +". .XXXXX. ", +"X. ", +"XX ", +"XX ", +"XX ", +"XX ", +"XX ", +"XX ", +"X. ", +". .XXXXX. ", +" .XXXXXXX. "}; diff --git a/bitmaps/a3.xpm b/bitmaps/a3.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a3_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +" .XXXXX. .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .XXXXX. .", +" .XXXXX. .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .XXXXX. .", +" .XXXXXXX. "}; diff --git a/bitmaps/a4.xpm b/bitmaps/a4.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a4_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" ", +". .", +"X. .X", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"X. .X", +". .XXXXX. .", +" .XXXXX. .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .", +" "}; diff --git a/bitmaps/a5.xpm b/bitmaps/a5.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a5_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +". .XXXXX. ", +"X. ", +"XX ", +"XX ", +"XX ", +"XX ", +"XX ", +"XX ", +"X. ", +". .XXXXX. ", +" .XXXXX. .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .XXXXX. .", +" .XXXXXXX. "}; diff --git a/bitmaps/a6.xpm b/bitmaps/a6.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a6_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +". .XXXXX. ", +"X. ", +"XX ", +"XX ", +"XX ", +"XX ", +"XX ", +"XX ", +"X. ", +". .XXXXX. ", +". .XXXXX. .", +"X. .X", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"X. .X", +". .XXXXX. .", +" .XXXXXXX. "}; diff --git a/bitmaps/a7.xpm b/bitmaps/a7.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a7_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +" .XXXXX. .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .", +" .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .", +" "}; diff --git a/bitmaps/a8.xpm b/bitmaps/a8.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a8_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +". .XXXXX. .", +"X. .X", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"X. .X", +". .XXXXX. .", +". .XXXXX. .", +"X. .X", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"X. .X", +". .XXXXX. .", +" .XXXXXXX. "}; diff --git a/bitmaps/a9.xpm b/bitmaps/a9.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * a9_xpm[] = { +"11 22 3 1", +" c #000000000000", +". c #861782078617", +"X c #FFFFFFFFFFFF", +" .XXXXXXX. ", +". .XXXXX. .", +"X. .X", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"XX XX", +"X. .X", +". .XXXXX. .", +" .XXXXX. .", +" .X", +" XX", +" XX", +" XX", +" XX", +" XX", +" XX", +" .X", +" .XXXXX. .", +" .XXXXXXX. "}; diff --git a/bitmaps/an.xpm b/bitmaps/an.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char * an_xpm[] = { +"11 22 1 1", +" c #000000000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/b0.xpm b/bitmaps/b0.xpm @@ -0,0 +1,35 @@ +/* XPM */ +static char * b0_xpm[] = { +"8 16 16 1", +" c #30C230C230C2", +". c #DF7DDF7DDF7D", +"X c #FFFFFFFFFFFF", +"o c #EFBEEFBEEFBE", +"O c #B6DAAEBAB6DA", +"+ c #000000000000", +"@ c #79E775D679E7", +"# c #492441034924", +"$ c #A6999E79A699", +"% c #965896589658", +"& c #38E338E338E3", +"* c #410341034103", +"= c #104008200820", +"- c #208118612081", +"; c #514451445144", +": c #F7DEF7DEF7DE", +" .XXXoO+", +"@#$%$% O", +"o&++++%X", +"X&++++$X", +"X*++++$X", +"X*++++$X", +"o&++++%X", +"@=++++-O", +";++++++@", +". ++++@X", +"X*++=+$X", +":*++++$X", +"X*++++$X", +"X&++++$X", +"O ***&*.", +"&OXXXo@ "}; diff --git a/bitmaps/b1.xpm b/bitmaps/b1.xpm @@ -0,0 +1,31 @@ +/* XPM */ +static char * b1_xpm[] = { +"8 16 12 1", +" c #000000000000", +". c #208118612081", +"X c #B6DAAEBAB6DA", +"o c #410338E34103", +"O c #FFFFFFFFFFFF", +"+ c #28A228A228A2", +"@ c #E79DE79DE79D", +"# c #514451445144", +"$ c #104008200820", +"% c #861779E779E7", +"& c #38E330C238E3", +"* c #F7DEF7DEF7DE", +" .", +" .X", +" oO", +" oO", +" oO", +" oO", +" +@", +" #", +" $%", +" &@", +" oO", +" oO", +" oO", +" &*", +" $%", +" "}; diff --git a/bitmaps/b2.xpm b/bitmaps/b2.xpm @@ -0,0 +1,31 @@ +/* XPM */ +static char * b2_xpm[] = { +"8 16 12 1", +" c #000000000000", +". c #9E799E799E79", +"X c #EFBEE79DEFBE", +"o c #FFFFF7DEFFFF", +"O c #FFFFFFFFFFFF", +"+ c #AEBAA699AEBA", +"@ c #38E338E338E3", +"# c #082008200820", +"$ c #38E330C238E3", +"% c #410338E338E3", +"& c #28A22CB228A2", +"* c #618559656185", +" .XoOO+@", +" #$@%@$+", +" # #%O", +" # %O", +" # # %O", +" # %O", +" # &X", +" $XoOo*%", +"+@....@ ", +"O. # ", +"O. #", +"O. ", +"o. ", +"O. ####", +"+@....@ ", +" +XOOoX&"}; diff --git a/bitmaps/b3.xpm b/bitmaps/b3.xpm @@ -0,0 +1,31 @@ +/* XPM */ +static char * b3_xpm[] = { +"8 16 12 1", +" c #000000000000", +". c #8E388A288E38", +"X c #F7DEEFBEEFBE", +"o c #FFFFF7DEFFFF", +"O c #FFFFFFFFFFFF", +"+ c #AEBAA699AEBA", +"@ c #38E334D338E3", +"# c #082008200820", +"$ c #410338E34103", +"% c #28A228A228A2", +"& c #514451445144", +"* c #208118612081", +" .XoOO+@", +" #@@$@@+", +" # #$O", +" $O", +" # # $O", +" $O", +" %X", +" @XoOo&&", +" *..++$.", +" @X", +" $O", +" # $O", +" $O", +" @X", +" *.+++$.", +" +OOOoX*"}; diff --git a/bitmaps/b4.xpm b/bitmaps/b4.xpm @@ -0,0 +1,31 @@ +/* XPM */ +static char * b4_xpm[] = { +"8 16 12 1", +" c #38E330C230C2", +". c #000000000000", +"X c #208118612081", +"o c #DF7DD75CDF7D", +"O c #38E338E338E3", +"+ c #9E799E799E79", +"@ c #FFFFFFFFFFFF", +"# c #410338E34103", +"$ c #082008200820", +"% c #69A669A669A6", +"& c #28A228A228A2", +"* c #F7DEF7DEF7DE", +" ......X", +"oO....X+", +"@+....#@", +"@+....#@", +"@+.$..#@", +"@+....#@", +"@%...$&o", +"%Oo@@*%#", +".X++++#+", +"......O*", +"......#*", +"......#@", +"......#@", +"......O*", +"......$%", +"......$."}; diff --git a/bitmaps/b5.xpm b/bitmaps/b5.xpm @@ -0,0 +1,33 @@ +/* XPM */ +static char * b5_xpm[] = { +"8 16 14 1", +" c #30C230C230C2", +". c #861782078617", +"X c #F7DEF3CEF7DE", +"o c #FFFFF7DEF7DE", +"O c #B6DAAEBAB6DA", +"+ c #208118612081", +"@ c #E79DDF7DDF7D", +"# c #410338E34103", +"$ c #410338E338E3", +"% c #186110401861", +"& c #000000000000", +"* c #9E799E799E79", +"= c #082000000000", +"- c #596555555965", +" .XoooO+", +"@#$###%&", +"o*&&&&&&", +"o*&&==&&", +"o*&&&&&&", +"o*&=&&&&", +"o-%&&=&&", +". @ooo-=", +"&+.***-.", +"&&&&&& X", +"&&&=&&#o", +"&&&&&&#o", +"&&&=&&#o", +"&&&&=&$X", +"&+****#.", +"&OXooo@ "}; diff --git a/bitmaps/b6.xpm b/bitmaps/b6.xpm @@ -0,0 +1,32 @@ +/* XPM */ +static char * b6_xpm[] = { +"8 16 13 1", +" c #30C230C230C2", +". c #96588E388E38", +"X c #F7DEEFBEEFBE", +"o c #FFFFF7DEFFFF", +"O c #AEBAA699AEBA", +"+ c #208118612081", +"@ c #38E338E338E3", +"# c #41033CF338E3", +"$ c #186110401861", +"% c #000000000000", +"& c #A6999E799E79", +"* c #082000000000", +"= c #69A665956185", +" .XoooO+", +"X@@@##$%", +"o&%%%%%%", +"o&%%**%%", +"o&%%*%%%", +"o&%*%*%%", +"o=%%*%%%", +". Xooo=%", +"O@.&&&#.", +"o.%%%%@X", +"o&%%%%#o", +"o&%%%%#o", +"o&%%%%#o", +"o.%%%*@X", +"O@.&&&#.", +"%OooooX "}; diff --git a/bitmaps/b7.xpm b/bitmaps/b7.xpm @@ -0,0 +1,30 @@ +/* XPM */ +static char * b7_xpm[] = { +"8 16 11 1", +" c #000000000000", +". c #71C675D671C6", +"X c #F7DEF3CEF7DE", +"o c #FFFFF7DEFFFF", +"O c #DF7DDF7DDF7D", +"+ c #28A228A228A2", +"@ c #082008200820", +"# c #104008200820", +"$ c #38E338E338E3", +"% c #410338E34103", +"& c #082000000820", +" .XoooO+", +"@#$%$$+O", +" @ @$X", +" %o", +" & & %o", +" %o", +" +O", +" %", +" #.", +" $X", +" %o", +" %o", +" %o", +" $X", +" @.", +" "}; diff --git a/bitmaps/b8.xpm b/bitmaps/b8.xpm @@ -0,0 +1,31 @@ +/* XPM */ +static char * b8_xpm[] = { +"8 16 12 1", +" c #30C230C230C2", +". c #8E388A288E38", +"X c #F7DEEFBEEFBE", +"o c #FFFFF7DEFFFF", +"O c #AEBAAAAAAEBA", +"+ c #38E338E338E3", +"@ c #DF7DDF7DDF7D", +"# c #41033CF338E3", +"$ c #A6999E799E79", +"% c #000000000000", +"& c #082000000000", +"* c #61855D756185", +" .XoooO+", +"@#+### O", +"o$%%%%#o", +"o$%%&&#o", +"o$%%%%#o", +"o$%&%%#o", +"o*&%&% @", +". @ooo**", +"O+.$$$#.", +"o.%%%%+X", +"o$%%%%#o", +"o$%%%%#o", +"o$%%%%#o", +"o.%%%&+X", +"O#.$$$#.", +"%Ooooo@ "}; diff --git a/bitmaps/b9.xpm b/bitmaps/b9.xpm @@ -0,0 +1,34 @@ +/* XPM */ +static char * b9_xpm[] = { +"8 16 15 1", +" c #30C230C230C2", +". c #71C671C671C6", +"X c #F7DEF3CEF7DE", +"o c #FFFFFFFFFFFF", +"O c #AEBAAAAAAEBA", +"+ c #38E33CF338E3", +"@ c #DF7DDF7DDF7D", +"# c #492441034924", +"$ c #A6999E799E79", +"% c #000000000000", +"& c #082000000000", +"* c #28A228A228A2", +"= c #FFFFF7DEF7DE", +"- c #208118612081", +"; c #965896589658", +" .XoooO+", +"@#++++ O", +"o$%%%%+o", +"o$%%&&+o", +"o$%%&%+o", +"o$%&%&+o", +"o.%%%&*@", +". @o=X.#", +"%-;$$$+.", +"%%%%%%+X", +"%%%&%%+=", +"%%%%%%+o", +"%%%&%%+o", +"%%%%&%+X", +"%-;$$;#.", +"%Ooooo@ "}; diff --git a/bitmaps/bar.xpm b/bitmaps/bar.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * bar_xpm[] = { +"4 7 8 1", +" c #000000000000", +". c #208118612081", +"X c #B6DAAEBAB6DA", +"o c #410338E34103", +"O c #FFFFFFFFFFFF", +"+ c #28A228A228A2", +"@ c #E79DE79DE79D", +"# c #514451445144", +" .X ", +" oO ", +" oO ", +" oO ", +" oO ", +" +@ ", +" # "}; diff --git a/bitmaps/bn.xpm b/bitmaps/bn.xpm @@ -0,0 +1,20 @@ +/* XPM */ +static char * bn_xpm[] = { +"8 16 1 1", +" c #000000000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/cdrom.xpm b/bitmaps/cdrom.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * cdrom_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXoooooXXX.", +" XXXXoooooooXX.", +" XXXXooooooo.X.", +" XXXXoooXooo.X.", +" XXXXooooooo.X.", +" XXXXooooooo.X.", +" XXXXXooooo..X.", +" XXXXXX.....XX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/concept1.xpm b/bitmaps/concept1.xpm @@ -0,0 +1,294 @@ +/* XPM */ +static char * concept1_xpm[] = { +"256 256 35 1", +" c #FFFFFFFFFFFF", +". c #000000000000", +"X c #965896589658", +"o c #492449244924", +"O c #CF3CCF3CCF3C", +"+ c #514451445144", +"@ c #BEFBBAEABEFB", +"# c #186118611861", +"$ c #69A66DB669A6", +"% c #EFBEEFBEEFBE", +"& c #596559655965", +"* c #38E338E338E3", +"= c #DF7DDF7DDF7D", +"- c #28A228A228A2", +"; c #D75CD75CD75C", +": c #082008200820", +"> c #C71BC30BC71B", +", c #CF3CCB2BCF3C", +"< c #B6DAB6DAB6DA", +"1 c #AEBAAEBAAEBA", +"2 c #A699A699A699", +"3 c #9E799E799E79", +"4 c #965892489658", +"5 c #8E388A288E38", +"6 c #861782078617", +"7 c #79E779E779E7", +"8 c #618565956185", +"9 c #59655D755965", +"0 c #514455555144", +"q c #410341034103", +"w c #30C230C230C2", +"e c #208124922081", +"r c #18611C711861", +"t c #104014511040", +"y c #08200C300820", +" ", +" ....................................................................................................................................... ", +" ..........................................................................................XXXXXXXXXXXXXX.XXXXXXXXXXXXXX.XXXXXXXXXXXXXX. ", +" ..........................................................................................Xooooooooooooo.Xooooooooooooo.Xooooooooooooo. ", +" ..........................................................................................XooooooOooOooo.Xooooooooooooo.XoOOooooooOOoo. ", +" ..........................................................................................XoooooOO.ooOoo.Xooooooooooooo.XoOOOooooOOO.o. ", +" ..........................................................................................XooooOOO.OoO.o.Xooooooooooooo.XooOOOooOOO..o. ", +" ..........................................................................................XoooOOOO.O.O.o.XoOOOOOOOOOOoo.XoooOOOOOO..oo. ", +" ..........................................................................................XoOOOOOO.O.O.o.XooOOOOOOOO..o.XooooOOOO..ooo. ", +" ..........................................................................................XoOOOOOO.O.O.o.XoooOOOOOO..oo.XooooOOOO.oooo. ", +" ..........................................................................................Xoo.OOOO.O.O.o.XooooOOOO..ooo.XoooOOOOOOoooo. ", +" ..........................................................................................XooooOOO.O.O.o.XoooooOO..oooo.XooOOO..OOOooo. ", +" ..........................................................................................XoooooOO.o.O.o.Xoooooo..ooooo.XoOOO..ooOOOoo. ", +" ..........................................................................................XooooooO.oOo.o.Xooooooooooooo.XoOO..ooooOO.o. ", +" ..........................................................................................Xooooooo.oo.oo.Xooooooooooooo.Xoo..oooooo..o. ", +" ..........................................................................................Xooooooooooooo.Xooooooooooooo.Xooooooooooooo. ", +" ....................................................................................................................................... ", +" ....... +.....@@....#$@ %@&.............@ @&....* *...*@ =@&#.....*@= @$...........XXXXXXXXXXXXXX.XXXXXXXXXXXXXX.XXXXXXXXXXXXXX. ", +" ....... %-....@@...-= ;$$X= O#...........@=$$$$; ;#..* *..o =X$X= =:...@ =X$$; ;#.........Xooooooooooooo.Xooooooooooooo.Xooooooooooooo. ", +" ....... =-...@@..#=%*.....$ @...........@@.....+ X..* *..@=.....*$...$ @.....o%$.........XooooooooOoooo.Xooooooooooooo.XooooOOOOOoooo. ", +" ....... @%=-..@@..$ -.......$ -..........@@......X #.* *..@%*.........%@.......:..........XooooooooOOooo.Xooooooooooooo.XoooOOOOOOOooo. ", +" ....... $-%;#.@@..@;........# $..........@@......* *.* *..-% =@*..* o..................XoooOOOOOOOOoo.XoooooOOoooooo.XoooOO..oOO.oo. ", +" ....... $.-%O#@@..@@......... $..........@@......* *.* *....*$$$X= *.* *..................XooOOOOOOOOO.o.XooooOOOOooooo.Xoooo..ooOO.oo. ", +" ....... $..+ ;@@..X #.......o o..........@@......X #.* *.........#=@.# X.......-#.........XoOOO....OO..o.XoooOOOOOOoooo.XoooooooOOO.oo. ", +" ....... $...+ @..#%;#.....-%=...........@@.....o X..* *..$*......=@..X +.....-%@.........XoOO..oooO..oo.XooOOOOOOOOooo.XooooooOOO..oo. ", +" ....... $....+ @...+ =X**oX =-...........@=$$$$; ;#..* *.:% ;$**&; o..#; X&*oX %-.........XoOO.ooooo.ooo.XoOOOOOOOOOOoo.XooooooOO..ooo. ", +" ....... $.....@@....-@ %X#............@ ;$#...* *..#$; =o....#$% X#..........XoOOOooooooooo.Xoo..........o.Xooooooo..oooo. ", +" .......................**-...................................#**-.........-**.............XooOOOOOOOOOoo.XoOOOOOOOOOOoo.XooooooOOooooo. ", +" ..........................................................................................XoooOOOOOOO..o.Xoo..........o.XooooooOO.oooo. ", +" ..........................................................................................Xoooo.......oo.Xooooooooooooo.Xooooooo..oooo. ", +" ..........................................................................................Xooooooooooooo.Xooooooooooooo.Xooooooooooooo. ", +" ....................................................................................................................................... ", +"O>>>>>>>>>>>>>>>>>>>>>>>>>>O.O>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>O.O>>>>>>>>>>>>>>>>>>>>>>>>>>O. ", +"O,,,,,,,,,,,,,,,,,,,,,,,,,,O.O,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,O.O,,,,,,,,,,,,,,,,,,,,,,,,,,O. ", +"O<<<<<<<<<<<<<<<<<<<<<<<<<<O.O<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<O.O<<<<<<<<<<<<<<<<<<<<<<<<<<O. ", +"O11111111111111111111111111O.O1111111111111111111111111111111111111111111111111111111111111111111111111111O.O11111111111111111111111111O. ", +"O22222222222222222222222222O.O2222222222222222222222222222222222222222222222222222222222222222222222222222O.O22222222222222222222222222O. ", +"O33333333333333333333333333O.O3333333333333333333333333333333333333333333333333333333333333333333333333333O.O33333333333333333333333333O. ", +"O44444444444444444444444444O.O4444444444444444444444444444444444444444444444444444444444444444444444444444O.O44444444444444444444444444O. ", +"O55555555555555555555555555O.O5555555555555555555555555555555555555555555555555555555555555555555555555555O.O55555555555555555555555555O. ", +"O6666OO666666OO666666OO6666O.O66666666666666666666666 66666666666666666666OOO66OOO66666666666666666666666O.O6666OO666666OO666666OO6666O. ", +"O7777OO77777OOO77777OOO7777O.O77777777777777777777777 77777777777777777OOO77OOO77777777777777777777777O.O7777OOO77777OOO77777OO7777O. ", +"O$$$$OO$$$$OOOO$$$$OOOO$$$$O.O$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$OOO$$OOO$$$$$$$$$$$$$$$$$$$$$$$O.O$$$$OOOO$$$$OOOO$$$$OO$$$$O. ", +"O8888OO888OOOOO888OOOOO8888O.O88888888888888888888888 88888888888OOO88OOO88888888888888888888888O.O8888OOOOO888OOOOO888OO8888O. ", +"O9999OO99OOOOOO99OOOOOO9999O.O99999999999999999999999 99999999OOO99OOO99999999999999999999999O.O9999OOOOOO99OOOOOO99OO9999O. ", +"O0000OO0OOOOOOO0OOOOOOO0000O.O00000000000000000000000 00000OOO00OOO00000000000000000000000O.O0000OOOOOOO0OOOOOOO0OO0000O. ", +",ooooOOOOOOOOOOOOOOOOOOoooo,.,ooooooooooooooooooooooo ooOOOooOOOooooooooooooooooooooooo,.,ooooOOOOOOOOOOOOOOOOOOoooo,. ", +"<qqqqOOOOOOOOOOOOOOOOOOqqqq<.<qqqqqqqqqqqqqqqqqqqqqqq qqOOOqqOOOqqqqqqqqqqqqqqqqqqqqqqq<.<qqqqOOOOOOOOOOOOOOOOOOqqqq<. ", +"2****OO*OOOOOOO*OOOOOOO****2.2*********************** *****OOO**OOO***********************2.2****OOOOOOO*OOOOOOO*OO****2. ", +"4wwwwOOwwOOOOOOwwOOOOOOwwww4.4wwwwwwwwwwwwwwwwwwwwwww wwwwwwwwOOOwwOOOwwwwwwwwwwwwwwwwwwwwwww4.4wwwwOOOOOOwwOOOOOOwwOOwwww4. ", +"6eeeeOOeeeOOOOOeeeOOOOOeeee6.6eeeeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeOOOeeOOOeeeeeeeeeeeeeeeeeeeeeee6.6eeeeOOOOOeeeOOOOOeeeOOeeee6. ", +"$rrrrOOrrrrOOOOrrrrOOOOrrrr$.$rrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrOOOrrOOOrrrrrrrrrrrrrrrrrrrrrrr$.$rrrrOOOOrrrrOOOOrrrrOOrrrr$. ", +"9ttttOOtttttOOOtttttOOOtttt9.9ttttttttttttttttttttttt tttttttttttttttttOOOttOOOttttttttttttttttttttttt9.9ttttOOOtttttOOOtttttOOtttt9. ", +"oyyyyOOyyyyyyOOyyyyyyOOyyyyo.oyyyyyyyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyyyyOOOyyOOOyyyyyyyyyyyyyyyyyyyyyyyo.oyyyyOOyyyyyyOOyyyyyyOOyyyyo. ", +"*..........................*.*............................................................................*.*..........................*. ", +"e..........................e.e............................................................................e.e..........................e. ", +"t..........................t.t............................................................................t.t..........................t. ", +"......................................................................................................................................... ", +"......................................................................................................................................... ", +"......................................................................................................................................... ", +"......................................................................................................................................... ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/ejdn.xpm b/bitmaps/ejdn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * ejdn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXooXXXXXX", +" .XXXXooooXXXXX", +" .XXXooooooXXXX", +" .XXooooooooXXX", +" .XooooooooooXX", +" .XX X", +" .XooooooooooXX", +" .XX X", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/ejup.xpm b/bitmaps/ejup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * ejup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXooXXXXXX.", +" XXXXooooXXXXX.", +" XXXooooooXXXX.", +" XXooooooooXXX.", +" XooooooooooXX.", +" XX..........X.", +" XooooooooooXX.", +" XX..........X.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/exitdn.xpm b/bitmaps/exitdn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * exitdn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XooXXXXXXooXX", +" .XoooXXXXooo X", +" .XXoooXXooo X", +" .XXXoooooo XX", +" .XXXXoooo XXX", +" .XXXXoooo XXXX", +" .XXXooooooXXXX", +" .XXooo oooXXX", +" .Xooo XXoooXX", +" .Xoo XXXXoo X", +" .XX XXXXXX X", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/exitup.xpm b/bitmaps/exitup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * exitup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XooXXXXXXooXX.", +" XoooXXXXooo.X.", +" XXoooXXooo..X.", +" XXXoooooo..XX.", +" XXXXoooo..XXX.", +" XXXXoooo.XXXX.", +" XXXooooooXXXX.", +" XXooo..oooXXX.", +" Xooo..XXoooXX.", +" Xoo..XXXXoo.X.", +" XX..XXXXXX..X.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/ffdn.xpm b/bitmaps/ffdn.xpm @@ -0,0 +1,59 @@ +/* XPM */ +static char * ffdn_xpm[] = { +"29 30 26 1", +" c None", +". c #000000", +"+ c #CFCFCF", +"@ c #C7C3C7", +"# c #CFCBCF", +"$ c #B6B6B6", +"% c #AEAEAE", +"& c #A6A6A6", +"* c #9E9E9E", +"= c #969296", +"- c #8E8A8E", +"; c #868286", +"> c #FFFFFF", +", c #797979", +"' c #696D69", +") c #616561", +"! c #595D59", +"~ c #515551", +"{ c #494949", +"] c #414141", +"^ c #383838", +"/ c #303030", +"( c #202420", +"_ c #181C18", +": c #101410", +"< c #080C08", +".............................", +".+@@@@@@@@@@@@@@@@@@@@@@@@@@+", +".+##########################+", +".+$$$$$$$$$$$$$$$$$$$$$$$$$$+", +".+%%%%%%%%%%%%%%%%%%%%%%%%%%+", +".+&&&&&&&&&&&&&&&&&&&&&&&&&&+", +".+**************************+", +".+==========================+", +".+--------------------------+", +".+;;;;;;;;;;;;>>;;;;;;>>;;;;+", +".+,,,,,,,,,,,,>>>,,,,,>>,,,,+", +".+''''''''''''>>>>''''>>''''+", +".+))))))))))))>>>>>)))>>))))+", +".+!!!!!!!!!!!!>>>>>>!!>>!!!!+", +".+~~~~~~~~~~~~>>>>>>>~>>~~~~+", +".#{{{{{{{{{{{{>>>>>>>>>>{{{{#", +".$]]]]]]]]]]]]>>>>>>>>>>]]]]$", +".&^^^^^^^^^^^^>>>>>>>^>>^^^^&", +".=////////////>>>>>>//>>////=", +".;((((((((((((>>>>>(((>>((((;", +".'____________>>>>____>>____'", +".!::::::::::::>>>:::::>>::::!", +".{<<<<<<<<<<<<>><<<<<<>><<<<{", +".^..........................^", +".(..........................(", +".:..........................:", +".............................", +".............................", +".............................", +"............................."}; diff --git a/bitmaps/ffup.xpm b/bitmaps/ffup.xpm @@ -0,0 +1,57 @@ +/* XPM */ +static char * ffup_xpm[] = { +"29 30 24 1", +" c #CF3CCF3CCF3C", +". c #C71BC30BC71B", +"X c #000000000000", +"o c #CF3CCB2BCF3C", +"O c #B6DAB6DAB6DA", +"+ c #AEBAAEBAAEBA", +"@ c #A699A699A699", +"# c #9E799E799E79", +"$ c #965892489658", +"% c #8E388A288E38", +"& c #861782078617", +"* c #79E779E779E7", +"= c #69A66DB669A6", +"- c #618565956185", +"; c #59655D755965", +": c #514455555144", +"> c #492449244924", +", c #410341034103", +"< c #38E338E338E3", +"1 c #30C230C230C2", +"2 c #208124922081", +"3 c #18611C711861", +"4 c #104014511040", +"5 c #08200C300820", +" .......................... X", +" oooooooooooooooooooooooooo X", +" OOOOOOOOOOOOOOOOOOOOOOOOOO X", +" ++++++++++++++++++++++++++ X", +" @@@@@@@@@@@@@@@@@@@@@@@@@@ X", +" ########################## X", +" $$$$$$$$$$$$$$$$$$$$$$$$$$ X", +" %%%%%%%%%%%%%%%%%%%%%%%%%% X", +" &&&& &&&&&& &&&&&& &&&& X", +" **** ***** ***** **** X", +" ==== ==== ==== ==== X", +" ---- --- --- ---- X", +" ;;;; ;; ;; ;;;; X", +" :::: : : :::: X", +"o>>>> >>>>oX", +"O,,,, ,,,,OX", +"@<<<< < < <<<<@X", +"$1111 11 11 1111$X", +"&2222 222 222 2222&X", +"=3333 3333 3333 3333=X", +";4444 44444 44444 4444;X", +">5555 555555 555555 5555>X", +"<XXXXXXXXXXXXXXXXXXXXXXXXXX<X", +"2XXXXXXXXXXXXXXXXXXXXXXXXXX2X", +"4XXXXXXXXXXXXXXXXXXXXXXXXXX4X", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}; diff --git a/bitmaps/freecd.xpm b/bitmaps/freecd.xpm @@ -0,0 +1,153 @@ +/* XPM */ +static char * freecd_xpm[] = { +"26 94 56 1", +" c #FFFFFFFFFFFF", +". c #FFFFFBEEFFFF", +"X c #F7DEF7DEF7DE", +"o c #EFBEEFBEEFBE", +"O c #EFBEEBADEFBE", +"+ c #E79DE79DE79D", +"@ c #E79DE38DE79D", +"# c #DF7DDF7DDF7D", +"$ c #DF7DDB6CDF7D", +"% c #D75CD75CD75C", +"& c #D75CD34CD75C", +"* c #CF3CCB2BCF3C", +"= c #C71BC71BC71B", +"- c #C71BC30BC71B", +"; c #BEFBBEFBBEFB", +": c #BEFBBAEABEFB", +"> c #B6DAB6DAB6DA", +", c #B6DAB2CAB6DA", +"< c #AEBAAEBAAEBA", +"1 c #AEBAAAAAAEBA", +"2 c #A699A289A699", +"3 c #9E799E799E79", +"4 c #A699A699A699", +"5 c #9E799A699E79", +"6 c #965896589658", +"7 c #965892489658", +"8 c #514451445144", +"9 c #18611C711861", +"0 c #208124922081", +"q c #28A228A228A2", +"w c #30C230C230C2", +"e c #30C234D330C2", +"r c #410345144103", +"t c #492449244924", +"y c #618561856185", +"u c #69A66DB669A6", +"i c #49244D344924", +"p c #71C671C671C6", +"a c #79E77DF779E7", +"s c #38E33CF338E3", +"d c #208120812081", +"f c #861782078617", +"g c #71C675D671C6", +"h c #69A669A669A6", +"j c #618565956185", +"k c #410341034103", +"l c #38E338E338E3", +"z c #CF3CCF3CCF3C", +"x c #8E388A288E38", +"c c #79E779E779E7", +"v c #8E388E388E38", +"b c #28A22CB228A2", +"n c #596559655965", +"m c #514455555144", +"M c #861786178617", +"N c #59655D755965", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+@#$%&*=-;:>,<123", +" .X*44233356667:>,<123", +" .890qqqqqqqqqqw3,<123", +" 59erttttttttttty,<123", +" uqr888888888888i,<123", +" pwi8888888888888,<123", +" pea:,<<<114443i8,<123", +" pe,O+@#$%&*=-;si,<123", +" pe<O+@#$%&*=-;0r,<123", +" pe<O+@#$%&*=-;dr,<123", +" pe<O+@#$%&*=-;dr,<123", +" pe<O+@#$%&*=-;dr,<123", +" pef6guuuuhhhhj0r,<123", +" petkeeeeeeeeeeli,<123", +" pei8iiiiiiiiiii8,<123", +" pei8888888888888,<123", +" pei8888888888888,<123", +" <;*z*=--;;:>>,<4,<123", +" &x2O+@#$%&*=-<cv,<123", +" udgO+@#$%&*=-1dw,<123", +" pb4O+@#$%&*=-;0k,<123", +" pe<O+@#$%&*=-;dr,<123", +" pe<O+@#$%&*=-;dr,<123", +" pe<O+@#$%&*=-;dr,<123", +" pe<O+@#$%&*=-;dr,<123", +" pe<O+@#$%&*=-;dr,<123", +" penuirrkkkkkkeqt,<123", +" pettsssssssssski,<123", +" pei8888888888888,<123", +" ;wi8888888888887,<123", +" .3j888888888886,,<123", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+@=,<<1--;<>,<123", +" .XoO+gdeskk1-;kq,<123", +" .XoO*dipaaa;-;tm,<123", +" .XoO<epv777--;ij,<123", +" .XoO<sa7777--;ij,<123", +" .XoO<k1&*,M--;ij,<123", +" .XoO<k:$%6h;-;ij,<123", +" .XoO<k>$%am;-;ij,<123", +" .XoO<k>$%c8;-;ij,<123", +" .XoO<k<$%c8;-;rj,<123", +" .XoO<kgyllyg8wsp,<123", +" .XoO<kcMccMxfccx,<123", +" .XoO:sa777777775,<123", +" .XoO+yg77777777;,<123", +" .XoO+@>;-;;;::;>,<123", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+3wwlss1-;mi,<123", +" .XoO%qkjggg:-;ti,<123", +" .XoO<bhx777--;iy,<123", +" .XoO<sc7777--;ij,<123", +" .XoO<k5*-1x--;ij,<123", +" .XoO<k:$%2p--;ij,<123", +" .XoO<k>$%fn;-;ij,<123", +" .XoO<k>$%c8;-;ij,<123", +" .XoO<k>$%c8;-;ij,<123", +" .XoO<kaMNrN7pmlu,<123", +" .XoO<kcahhcMgjuM,<123", +" .XoO<kavvxv7vxv7,<123", +" .XoO+8c77777777:,<123", +" .XoO+*31<<<<<<:>,<123", +" .XoO:tu*%&*=-;:>,<123", +" .XoO<wN&%&*=-;:>,<123", +" .XoO<sc$%&*=-;:>,<123", +" .XoO<ka$%&*=-;:>,<123", +" .XoO<ka$%&*=-;:>,<123", +" .XoO+rc>xcggggpN,<123", +" .XoO<egMy888888m,<123", +" .XoO<scvxMMMMMMM,<123", +" .XoO<ka777777777,<123", +" .XoO<ka777777777,<123", +" .XoO$%#$%&*=-;:>,<123", +" ,8gO+@#,<;*=-;:>,<123", +" ce5O+@#9ex*=-;:>,<123", +" ai;O+@#8y-*=-;:>,<123", +" f8-O+@#8h=*=-;:>,<123", +" f8-O+@#8j=*=-;:>,<123", +" f8-O+@#8j=*=-;:>,<123", +" f8-O+@#8j=*=-;:>,<123", +" f8-O+@#8j=*=-;:>,<123", +" f87MN88ku5gm8iiw,<123", +" f8achjjufxgjjjjj,<123", +" f8fvxxxvv7vxxxxv,<123", +" f8M7777777777777,<123", +" f8M7777777777777,<123", +" %OoO+@#$%&*=-;:>,<123", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+@#$%&*=-;:>,<123", +" .XoO+@#$%&*=-;:>,<123"}; diff --git a/bitmaps/freecdbase.xpm b/bitmaps/freecdbase.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char * freecdbase_xpm[] = { +"26 1 22 1", +" c #FFFFFFFFFFFF", +". c #FFFFFBEEFFFF", +"X c #F7DEF7DEF7DE", +"o c #EFBEEFBEEFBE", +"O c #EFBEEBADEFBE", +"+ c #E79DE79DE79D", +"@ c #E79DE38DE79D", +"# c #DF7DDF7DDF7D", +"$ c #DF7DDB6CDF7D", +"% c #D75CD75CD75C", +"& c #D75CD34CD75C", +"* c #CF3CCB2BCF3C", +"= c #C71BC71BC71B", +"- c #C71BC30BC71B", +"; c #BEFBBEFBBEFB", +": c #BEFBBAEABEFB", +"> c #B6DAB6DAB6DA", +", c #B6DAB2CAB6DA", +"< c #AEBAAEBAAEBA", +"1 c #AEBAAAAAAEBA", +"2 c #A699A289A699", +"3 c #9E799E799E79", +" .XoO+@#$%&*=-;:>,<123"}; diff --git a/bitmaps/helpdn.xpm b/bitmaps/helpdn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * helpdn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXoooooXXXX", +" .XXXoooooooXXX", +" .XXXoo Xoo XX", +" .XXXX XXoo XX", +" .XXXXXXXooo XX", +" .XXXXXXooo XX", +" .XXXXXXoo XXX", +" .XXXXXXX XXXX", +" .XXXXXXooXXXXX", +" .XXXXXXoo XXXX", +" .XXXXXXX XXXX", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/helpup.xpm b/bitmaps/helpup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * helpup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXoooooXXXX.", +" XXXoooooooXXX.", +" XXXoo..Xoo.XX.", +" XXXX..XXoo.XX.", +" XXXXXXXooo.XX.", +" XXXXXXooo..XX.", +" XXXXXXoo..XXX.", +" XXXXXXX..XXXX.", +" XXXXXXooXXXXX.", +" XXXXXXoo.XXXX.", +" XXXXXXX..XXXX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/mindn.xpm b/bitmaps/mindn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * mindn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XooooooooooXX", +" .XXoooooooo X", +" .XXXoooooo XX", +" .XXXXoooo XXX", +" .XXXXXoo XXXX", +" .XXXXXX XXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/minup.xpm b/bitmaps/minup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * minup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XooooooooooXX.", +" XXoooooooo..X.", +" XXXoooooo..XX.", +" XXXXoooo..XXX.", +" XXXXXoo..XXXX.", +" XXXXXX..XXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/minus.xpm b/bitmaps/minus.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * minus_xpm[] = { +"8 16 10 1", +" c #000000000000", +". c #38E330C238E3", +"X c #F7DEEFBEEFBE", +"o c #FFFFF7DEFFFF", +"O c #FFFFFFFFFFFF", +"+ c #514451445144", +"@ c #208118612081", +"# c #8E388E388E38", +"$ c #AEBAA699AEBA", +"% c #410338E34103", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +".XoOo+ ", +"@##$$% ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/mnscddn.xpm b/bitmaps/mnscddn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * mnscddn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXoooooXXX", +" .XXXXoooooooXX", +" .XXXXooooooo X", +" .XXXXoooXooo X", +" .XXXXooooooo X", +" .XXXXooooooo X", +" .Xoooooo.oo X", +" .Xoooooo XX", +" .XX XXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/mnscdup.xpm b/bitmaps/mnscdup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * mnscdup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXoooooXXX.", +" XXXXoooooooXX.", +" XXXXooooooo.X.", +" XXXXoooXooo.X.", +" XXXXooooooo.X.", +" XXXXooooooo.X.", +" Xoooooo oo..X.", +" Xoooooo....XX.", +" XX......XXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/mnstrkdn.xpm b/bitmaps/mnstrkdn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * mnstrkdn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXoooXXX", +" .XXXXXXXooooXX", +" .XXXXXXXoooo X", +" .XXXXXXXoooo X", +" .XXXXXXXX X", +" .XXXXXXXXXXXXX", +" .XooooooXXXXXX", +" .Xoooooo XXXXX", +" .XX XXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/mnstrkup.xpm b/bitmaps/mnstrkup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * mnstrkup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXoooXXX.", +" XXXXXXXooooXX.", +" XXXXXXXoooo.X.", +" XXXXXXXoooo.X.", +" XXXXXXXX....X.", +" XXXXXXXXXXXXX.", +" XooooooXXXXXX.", +" Xoooooo.XXXXX.", +" XX......XXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/nobar.xpm b/bitmaps/nobar.xpm @@ -0,0 +1,11 @@ +/* XPM */ +static char * nobar_xpm[] = { +"4 7 1 1", +" c #000000000000", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/nodisc.xpm b/bitmaps/nodisc.xpm @@ -0,0 +1,49 @@ +/* XPM */ +static char * nodisc_xpm[] = { +"92 30 16 1", +" c #000000000000", +". c #FFFFFFFFFFFF", +"X c #514451445144", +"o c #BEFBBAEABEFB", +"O c #186118611861", +"+ c #69A66DB669A6", +"@ c #EFBEEFBEEFBE", +"# c #596559655965", +"$ c #38E338E338E3", +"% c #DF7DDF7DDF7D", +"& c #28A228A228A2", +"* c #D75CD75CD75C", +"= c #965896589658", +"- c #CF3CCF3CCF3C", +"; c #492449244924", +": c #082008200820", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" .X oo O+o..@o# o.....o# $.$ $o..%o#O $o%..o+ ", +" .@& oo &%.*++=%.-O o%++++*.*O $.$ ;.%=+=%.%: o.%=++*.*O ", +" ..%& oo O%@$ +.o oo X.= $.$ o% $+ +.o ;@+ ", +" .o@%& oo +.& +.& oo =.O $.$ o@$ @o : ", +" .+&@*O oo o* O.+ oo $.$ $.$ &@....%o$ $.; ", +" .+ &@-Ooo oo .+ oo $.$ $.$ $+++=%.$ $.$ ", +" .+ X.*oo =.O ;.; oo =.O $.$ O%o O.= &O ", +" .+ X..o O@*O &@% oo ;.= $.$ +$ %o =.X &@o ", +" .+ X.o X.%=$$;=.%& o%++++*.*O $.$ :@.*+$$#*.; O*.=#$;=.@& ", +" .+ oo &o....@=O o.....*+O $.$ O+*....%; O+@....=O ", +" $$& O$$& &$$ ", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/null.xpm b/bitmaps/null.xpm @@ -0,0 +1,35 @@ +/* XPM */ +static char * null_xpm[] = { +"92 30 2 1", +" c #000000000000", +". c #FFFFFFFFFFFF", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" . ", +" . ", +" ", +" ", +" ", +" ", +" . ", +" . ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/pauseup.xpm b/bitmaps/pauseup.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static char * pauseup_xpm[] = { +"79 30 25 1", +" c #CF3CCF3CCF3C", +". c #C71BC30BC71B", +"X c #000000000000", +"o c #CF3CCB2BCF3C", +"O c #B6DAB6DAB6DA", +"+ c #AEBAAEBAAEBA", +"@ c #A699A699A699", +"# c #9E799E799E79", +"$ c #965892489658", +"% c #8E388A288E38", +"& c #861782078617", +"* c #FFFFFFFFFFFF", +"= c #79E779E779E7", +"- c #69A66DB669A6", +"; c #618565956185", +": c #59655D755965", +"> c #514455555144", +", c #492449244924", +"< c #410341034103", +"1 c #38E338E338E3", +"2 c #30C230C230C2", +"3 c #208124922081", +"4 c #18611C711861", +"5 c #104014511040", +"6 c #08200C300820", +" ............................................................................ X", +" oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo X", +" OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO X", +" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ X", +" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ X", +" ############################################################################ X", +" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ X", +" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% X", +" &&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&***&&***&&&&&&&&&&&&&&&&&&&&&&& X", +" ======================= =================***==***======================= X", +" ----------------------- --------------***--***----------------------- X", +" ;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;***;;***;;;;;;;;;;;;;;;;;;;;;;; X", +" ::::::::::::::::::::::: ::::::::***::***::::::::::::::::::::::: X", +" >>>>>>>>>>>>>>>>>>>>>>> >>>>>***>>***>>>>>>>>>>>>>>>>>>>>>>> X", +"o,,,,,,,,,,,,,,,,,,,,,,, ,,***,,***,,,,,,,,,,,,,,,,,,,,,,,oX", +"O<<<<<<<<<<<<<<<<<<<<<<< <<***<<***<<<<<<<<<<<<<<<<<<<<<<<OX", +"@11111111111111111111111 11111***11***11111111111111111111111@X", +"$22222222222222222222222 22222222***22***22222222222222222222222$X", +"&33333333333333333333333 33333333333***33***33333333333333333333333&X", +"-44444444444444444444444 44444444444444***44***44444444444444444444444-X", +":55555555555555555555555 55555555555555555***55***55555555555555555555555:X", +",66666666666666666666666 66666666666666666666***66***66666666666666666666666,X", +"1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1X", +"3XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX3X", +"5XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX5X", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}; diff --git a/bitmaps/playdn.xpm b/bitmaps/playdn.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static char * playdn_xpm[] = { +"79 30 25 1", +" c #000000000000", +". c #CF3CCF3CCF3C", +"X c #C71BC30BC71B", +"o c #CF3CCB2BCF3C", +"O c #B6DAB6DAB6DA", +"+ c #AEBAAEBAAEBA", +"@ c #A699A699A699", +"# c #9E799E799E79", +"$ c #965892489658", +"% c #8E388A288E38", +"& c #861782078617", +"* c #FFFFFFFFFFFF", +"= c #79E779E779E7", +"- c #69A66DB669A6", +"; c #618565956185", +": c #59655D755965", +"> c #514455555144", +", c #492449244924", +"< c #410341034103", +"1 c #38E338E338E3", +"2 c #30C230C230C2", +"3 c #208124922081", +"4 c #18611C711861", +"5 c #104014511040", +"6 c #08200C300820", +" ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.", +" .oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.", +" .OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.", +" .++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.", +" .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.", +" .############################################################################.", +" .$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$.", +" .%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.", +" .&&&&&&&&&&&&&&&&&&&&&&&**&&&&&&&&&&&&&&&&&&&&***&&***&&&&&&&&&&&&&&&&&&&&&&&.", +" .=======================*****=================***==***=======================.", +" .-----------------------********--------------***--***-----------------------.", +" .;;;;;;;;;;;;;;;;;;;;;;;***********;;;;;;;;;;;***;;***;;;;;;;;;;;;;;;;;;;;;;;.", +" .:::::::::::::::::::::::**************::::::::***::***:::::::::::::::::::::::.", +" .>>>>>>>>>>>>>>>>>>>>>>>*****************>>>>>***>>***>>>>>>>>>>>>>>>>>>>>>>>.", +" o,,,,,,,,,,,,,,,,,,,,,,,********************,,***,,***,,,,,,,,,,,,,,,,,,,,,,,o", +" O<<<<<<<<<<<<<<<<<<<<<<<********************<<***<<***<<<<<<<<<<<<<<<<<<<<<<<O", +" @11111111111111111111111*****************11111***11***11111111111111111111111@", +" $22222222222222222222222**************22222222***22***22222222222222222222222$", +" &33333333333333333333333***********33333333333***33***33333333333333333333333&", +" -44444444444444444444444********44444444444444***44***44444444444444444444444-", +" :55555555555555555555555*****55555555555555555***55***55555555555555555555555:", +" ,66666666666666666666666**66666666666666666666***66***66666666666666666666666,", +" 1 1", +" 3 3", +" 5 5", +" ", +" ", +" ", +" "}; diff --git a/bitmaps/playup.xpm b/bitmaps/playup.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static char * playup_xpm[] = { +"79 30 25 1", +" c #CF3CCF3CCF3C", +". c #C71BC30BC71B", +"X c #000000000000", +"o c #CF3CCB2BCF3C", +"O c #B6DAB6DAB6DA", +"+ c #AEBAAEBAAEBA", +"@ c #A699A699A699", +"# c #9E799E799E79", +"$ c #965892489658", +"% c #8E388A288E38", +"& c #861782078617", +"* c #FFFFFFFFFFFF", +"= c #79E779E779E7", +"- c #69A66DB669A6", +"; c #618565956185", +": c #59655D755965", +"> c #514455555144", +", c #492449244924", +"< c #410341034103", +"1 c #38E338E338E3", +"2 c #30C230C230C2", +"3 c #208124922081", +"4 c #18611C711861", +"5 c #104014511040", +"6 c #08200C300820", +" ............................................................................ X", +" oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo X", +" OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO X", +" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ X", +" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ X", +" ############################################################################ X", +" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ X", +" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% X", +" &&&&&&&&&&&&&&&&&&&&&&&**&&&&&&&&&&&&&&&&&&&& && &&&&&&&&&&&&&&&&&&&&&&& X", +" =======================*****================= == ======================= X", +" -----------------------********-------------- -- ----------------------- X", +" ;;;;;;;;;;;;;;;;;;;;;;;***********;;;;;;;;;;; ;; ;;;;;;;;;;;;;;;;;;;;;;; X", +" :::::::::::::::::::::::**************:::::::: :: ::::::::::::::::::::::: X", +" >>>>>>>>>>>>>>>>>>>>>>>*****************>>>>> >> >>>>>>>>>>>>>>>>>>>>>>> X", +"o,,,,,,,,,,,,,,,,,,,,,,,********************,, ,, ,,,,,,,,,,,,,,,,,,,,,,,oX", +"O<<<<<<<<<<<<<<<<<<<<<<<********************<< << <<<<<<<<<<<<<<<<<<<<<<<OX", +"@11111111111111111111111*****************11111 11 11111111111111111111111@X", +"$22222222222222222222222**************22222222 22 22222222222222222222222$X", +"&33333333333333333333333***********33333333333 33 33333333333333333333333&X", +"-44444444444444444444444********44444444444444 44 44444444444444444444444-X", +":55555555555555555555555*****55555555555555555 55 55555555555555555555555:X", +",66666666666666666666666**66666666666666666666 66 66666666666666666666666,X", +"1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1X", +"3XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX3X", +"5XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX5X", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}; diff --git a/bitmaps/plscddn.xpm b/bitmaps/plscddn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * plscddn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXoooooXXX", +" .XXXXoooooooXX", +" .XXXXooooooo X", +" .XXXXoooXooo X", +" .XXXoo.ooooo X", +" .XXXoo ooooo X", +" .Xoooooo.oo X", +" .Xoooooo XX", +" .XX oo XXXXX", +" .XXXoo XXXXXXX", +" .XXXX XXXXXXX"}; diff --git a/bitmaps/plscdup.xpm b/bitmaps/plscdup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * plscdup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXoooooXXX.", +" XXXXoooooooXX.", +" XXXXooooooo.X.", +" XXXXoooXooo.X.", +" XXXoo ooooo.X.", +" XXXoo.ooooo.X.", +" Xoooooo oo..X.", +" Xoooooo....XX.", +" XX.oo...XXXXX.", +" XXXoo.XXXXXXX.", +" XXXX..XXXXXXX.", +"..............."}; diff --git a/bitmaps/plstrkdn.xpm b/bitmaps/plstrkdn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * plstrkdn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXXXXXXXX", +" .XXXXXXXoooXXX", +" .XXXXXXXooooXX", +" .XXXXXXXoooo X", +" .XXXXXXXoooo X", +" .XXXooXXX X", +" .XXXoo XXXXXXX", +" .XooooooXXXXXX", +" .Xoooooo XXXXX", +" .XX oo XXXXX", +" .XXXoo XXXXXXX", +" .XXXX XXXXXXX"}; diff --git a/bitmaps/plstrkup.xpm b/bitmaps/plstrkup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * plstrkup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXoooXXX.", +" XXXXXXXooooXX.", +" XXXXXXXoooo.X.", +" XXXXXXXoooo.X.", +" XXXooXXX....X.", +" XXXoo.XXXXXXX.", +" XooooooXXXXXX.", +" Xoooooo.XXXXX.", +" XX.oo...XXXXX.", +" XXXoo.XXXXXXX.", +" XXXX..XXXXXXX.", +"..............."}; diff --git a/bitmaps/redbar.xpm b/bitmaps/redbar.xpm @@ -0,0 +1,16 @@ +/* XPM */ +static char * redbar_xpm[] = { +"4 7 6 1", +" c #000000000000", +". c #79E700000000", +"X c #CF3C00000000", +"o c #AEBA00000000", +"O c #FFFF00000000", +"+ c #DF7D00000000", +" .X ", +" oO ", +" oO ", +" oO ", +" oO ", +" .+ ", +" o "}; diff --git a/bitmaps/rewdn.xpm b/bitmaps/rewdn.xpm @@ -0,0 +1,59 @@ +/* XPM */ +static char * rewdn_xpm[] = { +"29 30 26 1", +" c None", +". c #000000", +"+ c #CFCFCF", +"@ c #C7C3C7", +"# c #CFCBCF", +"$ c #B6B6B6", +"% c #AEAEAE", +"& c #A6A6A6", +"* c #9E9E9E", +"= c #969296", +"- c #8E8A8E", +"; c #868286", +"> c #FFFFFF", +", c #797979", +"' c #696D69", +") c #616561", +"! c #595D59", +"~ c #515551", +"{ c #494949", +"] c #414141", +"^ c #383838", +"/ c #303030", +"( c #202420", +"_ c #181C18", +": c #101410", +"< c #080C08", +".............................", +".+@@@@@@@@@@@@@@@@@@@@@@@@@@+", +".+##########################+", +".+$$$$$$$$$$$$$$$$$$$$$$$$$$+", +".+%%%%%%%%%%%%%%%%%%%%%%%%%%+", +".+&&&&&&&&&&&&&&&&&&&&&&&&&&+", +".+**************************+", +".+==========================+", +".+--------------------------+", +".+;;;;>>;;;;;;>>;;;;;;;;;;;;+", +".+,,,,>>,,,,,>>>,,,,,,,,,,,,+", +".+''''>>''''>>>>''''''''''''+", +".+))))>>)))>>>>>))))))))))))+", +".+!!!!>>!!>>>>>>!!!!!!!!!!!!+", +".+~~~~>>~>>>>>>>~~~~~~~~~~~~+", +".#{{{{>>>>>>>>>>{{{{{{{{{{{{#", +".$]]]]>>>>>>>>>>]]]]]]]]]]]]$", +".&^^^^>>^>>>>>>>^^^^^^^^^^^^&", +".=////>>//>>>>>>////////////=", +".;((((>>(((>>>>>((((((((((((;", +".'____>>____>>>>____________'", +".!::::>>:::::>>>::::::::::::!", +".{<<<<>><<<<<<>><<<<<<<<<<<<{", +".^..........................^", +".(..........................(", +".:..........................:", +".............................", +".............................", +".............................", +"............................."}; diff --git a/bitmaps/rewup.xpm b/bitmaps/rewup.xpm @@ -0,0 +1,57 @@ +/* XPM */ +static char * rewup_xpm[] = { +"29 30 24 1", +" c #CF3CCF3CCF3C", +". c #C71BC30BC71B", +"X c #000000000000", +"o c #CF3CCB2BCF3C", +"O c #B6DAB6DAB6DA", +"+ c #AEBAAEBAAEBA", +"@ c #A699A699A699", +"# c #9E799E799E79", +"$ c #965892489658", +"% c #8E388A288E38", +"& c #861782078617", +"* c #79E779E779E7", +"= c #69A66DB669A6", +"- c #618565956185", +"; c #59655D755965", +": c #514455555144", +"> c #492449244924", +", c #410341034103", +"< c #38E338E338E3", +"1 c #30C230C230C2", +"2 c #208124922081", +"3 c #18611C711861", +"4 c #104014511040", +"5 c #08200C300820", +" .......................... X", +" oooooooooooooooooooooooooo X", +" OOOOOOOOOOOOOOOOOOOOOOOOOO X", +" ++++++++++++++++++++++++++ X", +" @@@@@@@@@@@@@@@@@@@@@@@@@@ X", +" ########################## X", +" $$$$$$$$$$$$$$$$$$$$$$$$$$ X", +" %%%%%%%%%%%%%%%%%%%%%%%%%% X", +" &&&& &&&&&& &&&&&& &&&& X", +" **** ***** ***** **** X", +" ==== ==== ==== ==== X", +" ---- --- --- ---- X", +" ;;;; ;; ;; ;;;; X", +" :::: : : :::: X", +"o>>>> >>>>oX", +"O,,,, ,,,,OX", +"@<<<< < < <<<<@X", +"$1111 11 11 1111$X", +"&2222 222 222 2222&X", +"=3333 3333 3333 3333=X", +";4444 44444 44444 4444;X", +">5555 555555 555555 5555>X", +"<XXXXXXXXXXXXXXXXXXXXXXXXXX<X", +"2XXXXXXXXXXXXXXXXXXXXXXXXXX2X", +"4XXXXXXXXXXXXXXXXXXXXXXXXXX4X", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}; diff --git a/bitmaps/rptdn.xpm b/bitmaps/rptdn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * rptdn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXXXoXXXX", +" .XXXXXXXXooXXX", +" .XXXooooooooXX", +" .XXooooooooo X", +" .Xooo oo X", +" .Xoo XXXo XX", +" .Xoo XXXXX XXX", +" .XoooXXXXXXXXX", +" .XXoooooooooXX", +" .XXXooooooo X", +" .XXXX XX", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/rptup.xpm b/bitmaps/rptup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * rptup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXoXXXX.", +" XXXXXXXXooXXX.", +" XXXooooooooXX.", +" XXooooooooo.X.", +" Xooo....oo..X.", +" Xoo..XXXo..XX.", +" Xoo.XXXXX.XXX.", +" XoooXXXXXXXXX.", +" XXoooooooooXX.", +" XXXooooooo..X.", +" XXXX.......XX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/rptupact.xpm b/bitmaps/rptupact.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * rptupact_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXoXXXX.", +" XXXXXXXXooXXX.", +" XXXooooooooXX.", +" XXooooooooo.X.", +" Xooo....oo..X.", +" Xoo..XXXo..XX.", +" Xoo.XXXXX.XXX.", +" XoooXXXXXXXXX.", +" XXoooooooooXX.", +" XXXooooooo..X.", +" XXXX.......XX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/sfwddn.xpm b/bitmaps/sfwddn.xpm @@ -0,0 +1,59 @@ +/* XPM */ +static char * sfwddn_xpm[] = { +"29 30 26 1", +" c None", +". c #000000", +"+ c #CFCFCF", +"@ c #C7C3C7", +"# c #CFCBCF", +"$ c #B6B6B6", +"% c #AEAEAE", +"& c #A6A6A6", +"* c #9E9E9E", +"= c #969296", +"- c #8E8A8E", +"; c #868286", +"> c #FFFFFF", +", c #797979", +"' c #696D69", +") c #616561", +"! c #595D59", +"~ c #515551", +"{ c #494949", +"] c #414141", +"^ c #383838", +"/ c #303030", +"( c #202420", +"_ c #181C18", +": c #101410", +"< c #080C08", +".............................", +".+@@@@@@@@@@@@@@@@@@@@@@@@@@+", +".+##########################+", +".+$$$$$$$$$$$$$$$$$$$$$$$$$$+", +".+%%%%%%%%%%%%%%%%%%%%%%%%%%+", +".+&&&&&&&&&&&&&&&&&&&&&&&&&&+", +".+**************************+", +".+==========================+", +".+--------------------------+", +".+;;;;>>;;;;;;>>;;;;;;;;;;;;+", +".+,,,,>>>,,,,,>>>,,,,,,,,,,,+", +".+''''>>>>''''>>>>''''''''''+", +".+))))>>>>>)))>>>>>)))))))))+", +".+!!!!>>>>>>!!>>>>>>!!!!!!!!+", +".+~~~~>>>>>>>~>>>>>>>~~~~~~~+", +".#{{{{>>>>>>>>>>>>>>>>{{{{{{#", +".$]]]]>>>>>>>>>>>>>>>>]]]]]]$", +".&^^^^>>>>>>>^>>>>>>>^^^^^^^&", +".=////>>>>>>//>>>>>>////////=", +".;((((>>>>>(((>>>>>(((((((((;", +".'____>>>>____>>>>__________'", +".!::::>>>:::::>>>:::::::::::!", +".{<<<<>><<<<<<>><<<<<<<<<<<<{", +".^..........................^", +".(..........................(", +".:..........................:", +".............................", +".............................", +".............................", +"............................."}; diff --git a/bitmaps/slice.xpm b/bitmaps/slice.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * slice_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXoooXXX.", +" XXXXXXXooooXX.", +" XXXXXXXoooo.X.", +" XXXXXXXoooo.X.", +" XXXXXXXX....X.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/bitmaps/srevdn.xpm b/bitmaps/srevdn.xpm @@ -0,0 +1,59 @@ +/* XPM */ +static char * srevdn_xpm[] = { +"29 30 26 1", +" c None", +". c #000000", +"+ c #CFCFCF", +"@ c #C7C3C7", +"# c #CFCBCF", +"$ c #B6B6B6", +"% c #AEAEAE", +"& c #A6A6A6", +"* c #9E9E9E", +"= c #969296", +"- c #8E8A8E", +"; c #868286", +"> c #FFFFFF", +", c #797979", +"' c #696D69", +") c #616561", +"! c #595D59", +"~ c #515551", +"{ c #494949", +"] c #414141", +"^ c #383838", +"/ c #303030", +"( c #202420", +"_ c #181C18", +": c #101410", +"< c #080C08", +".............................", +".+@@@@@@@@@@@@@@@@@@@@@@@@@@+", +".+##########################+", +".+$$$$$$$$$$$$$$$$$$$$$$$$$$+", +".+%%%%%%%%%%%%%%%%%%%%%%%%%%+", +".+&&&&&&&&&&&&&&&&&&&&&&&&&&+", +".+**************************+", +".+==========================+", +".+--------------------------+", +".+;;;;;;;;;;;;>>;;;;;;>>;;;;+", +".+,,,,,,,,,,,>>>,,,,,>>>,,,,+", +".+''''''''''>>>>''''>>>>''''+", +".+)))))))))>>>>>)))>>>>>))))+", +".+!!!!!!!!>>>>>>!!>>>>>>!!!!+", +".+~~~~~~~>>>>>>>~>>>>>>>~~~~+", +".#{{{{{{>>>>>>>>>>>>>>>>{{{{#", +".$]]]]]]>>>>>>>>>>>>>>>>]]]]$", +".&^^^^^^^>>>>>>>^>>>>>>>^^^^&", +".=////////>>>>>>//>>>>>>////=", +".;(((((((((>>>>>(((>>>>>((((;", +".'__________>>>>____>>>>____'", +".!:::::::::::>>>:::::>>>::::!", +".{<<<<<<<<<<<<>><<<<<<>><<<<{", +".^..........................^", +".(..........................(", +".:..........................:", +".............................", +".............................", +".............................", +"............................."}; diff --git a/bitmaps/stopup.xpm b/bitmaps/stopup.xpm @@ -0,0 +1,57 @@ +/* XPM */ +static char * stopup_xpm[] = { +"79 30 24 1", +" c #CF3CCF3CCF3C", +". c #C71BC30BC71B", +"X c #000000000000", +"o c #CF3CCB2BCF3C", +"O c #B6DAB6DAB6DA", +"+ c #AEBAAEBAAEBA", +"@ c #A699A699A699", +"# c #9E799E799E79", +"$ c #965892489658", +"% c #8E388A288E38", +"& c #861782078617", +"* c #79E779E779E7", +"= c #69A66DB669A6", +"- c #618565956185", +"; c #59655D755965", +": c #514455555144", +"> c #492449244924", +", c #410341034103", +"< c #38E338E338E3", +"1 c #30C230C230C2", +"2 c #208124922081", +"3 c #18611C711861", +"4 c #104014511040", +"5 c #08200C300820", +" ............................................................................ X", +" oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo X", +" OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO X", +" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ X", +" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ X", +" ############################################################################ X", +" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ X", +" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% X", +" &&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&& && &&&&&&&&&&&&&&&&&&&&&&& X", +" *********************** ***************** ** *********************** X", +" ======================= ============== == ======================= X", +" ----------------------- ----------- -- ----------------------- X", +" ;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;; ;; ;;;;;;;;;;;;;;;;;;;;;;; X", +" ::::::::::::::::::::::: ::::: :: ::::::::::::::::::::::: X", +"o>>>>>>>>>>>>>>>>>>>>>>> >> >> >>>>>>>>>>>>>>>>>>>>>>>oX", +"O,,,,,,,,,,,,,,,,,,,,,,, ,, ,, ,,,,,,,,,,,,,,,,,,,,,,,OX", +"@<<<<<<<<<<<<<<<<<<<<<<< <<<<< << <<<<<<<<<<<<<<<<<<<<<<<@X", +"$11111111111111111111111 11111111 11 11111111111111111111111$X", +"&22222222222222222222222 22222222222 22 22222222222222222222222&X", +"=33333333333333333333333 33333333333333 33 33333333333333333333333=X", +";44444444444444444444444 44444444444444444 44 44444444444444444444444;X", +">55555555555555555555555 55555555555555555555 55 55555555555555555555555>X", +"<XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<X", +"2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2X", +"4XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4X", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}; diff --git a/bitmaps/voldn.xpm b/bitmaps/voldn.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * voldn_xpm[] = { +"15 15 4 1", +" c #000000000000", +". c #965896589658", +"X c #492449244924", +"o c #FFFFFFFFFFFF", +" ", +" ..............", +" .XXXXXXXXXXXXX", +" .XXXXXXoXXoXXX", +" .XXXXXoo XXoXX", +" .XXXXooo oXo X", +" .XXXoooo o o X", +" .Xoooooo o o X", +" .Xoooooo o o X", +" .XX oooo o o X", +" .XXXXooo o o X", +" .XXXXXoo X o X", +" .XXXXXXo XoX X", +" .XXXXXXX XX XX", +" .XXXXXXXXXXXXX"}; diff --git a/bitmaps/volup.xpm b/bitmaps/volup.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * volup_xpm[] = { +"15 15 4 1", +" c #965896589658", +". c #000000000000", +"X c #492449244924", +"o c #CF3CCF3CCF3C", +" .", +" XXXXXXXXXXXXX.", +" XXXXXXoXXoXXX.", +" XXXXXoo.XXoXX.", +" XXXXooo.oXo.X.", +" XXXoooo.o.o.X.", +" Xoooooo.o.o.X.", +" Xoooooo.o.o.X.", +" XX.oooo.o.o.X.", +" XXXXooo.o.o.X.", +" XXXXXoo.X.o.X.", +" XXXXXXo.XoX.X.", +" XXXXXXX.XX.XX.", +" XXXXXXXXXXXXX.", +"..............."}; diff --git a/cd_control.c b/cd_control.c @@ -0,0 +1,415 @@ +/* ----------------------------------------------------------------------- + cd_control process + + part of XfreeCD + + Copyright (C) 1998 Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + 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. + + ==========================[ HISTORY ]================================== + 06/22/98 Bug in track length calculation. It was waiting until track + #2 before calculating the lengths (holdover from the change + to 0 offset from 1 offset). FIXED. + + 05/08/98 Added the control and init code from old version of xfreecd + Added software control of the EJECT on CLOSE state - using + the CD_SET_EJECT command and an argument of 0 to disable + eject on exit and 1 to enable eject on exit. + + 05/03/98 Wrote the synchronization code and basic switch statment. + Testing different shutdown situations. No hungup child + processes yet. + + Things this process needs to do: + x 1. Get the data on the current CD and send it to the + parent, in response to a request by the parent. + x 2. Play a CD + x 3. Pause a CD + x 4. Resume a CD + x 5. Go to next track + x 6. Go to Previous track + x 8. Eject a CD + x 9. Close the CD tray + 10. Switch CDs for a CD changer + 11. Seek forward (may need a kernel patch?) + 12. Seek backwards (may need a kernel patch?) + 13. Return error/status codes (like if a play is tried and + there is no CD in the player). + 14. Shuffle play (on one Cd or among multiple CDs) + 15. Repeat Song + 16. Repeat whole CD, repeat group of CDs + + + ----------------------------------------------------------------------- */ +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <gtk/gtk.h> +#include "child_sync.h" +#include "cd_control.h" +#include "cddb.h" + +int cd_control( int ); +int readline( register int, register char *, register int ); + +#undef DEBUG1 +#undef DEBUG3 + +/* + Fire up the cd_control process. + Create a socket pair. + Fork a child process + Return the parent's file descriptor for the socket or -1 + errno + fill in childpid with the child's PID + Child calls cd_control +*/ +int start_cd_control( int *childpid ) +{ + int fd[2]; + + if( socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) < 0 ) + return(-1); + + if( ( *childpid = fork() ) < 0 ) + { + perror("start_cd_control, cannot fork"); + return(-1); + } else if( *childpid == 0 ) { + close( fd[0] ); + + /* Synchronize with the parent, exit if it fails */ + if( parent_sync( fd[1] ) == 0 ) + cd_control( fd[1] ); + + close( fd[1] ); + exit(0); + } + close( fd[1] ); + + if( child_sync( fd[0] ) == 0 ) + return(fd[0]); + + return(-1); +} + + +/* + Load a new CD, read all of its info into the cdinfo array +*/ +int cdrom_init( struct CDINFO *cdinfo, struct cdrom_volctrl *volctrl, char *cd_device ) +{ + int fd; + int x; + + /* Try and open the /dev/cdrom device */ + if( ( fd = open( cd_device, O_RDONLY ) ) < 0 ) + { +#ifdef DEBUG3 + g_print( "device = %s\n", cd_device); +#endif + + perror("CDROM device" ); + return -1; + } + + /* Read the cdrom's header information */ + if( ioctl( fd, CDROMREADTOCHDR, &cdinfo->tochdr ) != 0 ) + { + perror("cdrom_init(CDROMREADTOCHDR-2)" ); + return -1; + } + + /* Get the time on the end of the last track */ + cdinfo->leadout.cdte_track = CDROM_LEADOUT; + cdinfo->leadout.cdte_format = CDROM_MSF; + + if( ioctl( fd, CDROMREADTOCENTRY, &cdinfo->leadout ) != 0 ) + { + perror( "cdrom_init(CDROMREADTOCENTRY-2)" ); + return -1; + } + + /* Calculate the total length of the CD */ + cdinfo->cd_length = cdinfo->leadout.cdte_addr.msf.second \ + + (cdinfo->leadout.cdte_addr.msf.minute * 60); + + /* Read the current CD volume level - different from soundcard volume */ + if( ioctl( fd, CDROMVOLREAD, volctrl ) == 0 ) + { + cdinfo->volume = volctrl->channel0; + } else { + perror( "cdrom_init(CDROMVOLREAD-2)" ); + return -1; + } + + /* Fill in the tracks[] array with info on all the tracks */ + for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ ) + { + /* Read the info for the current track */ + cdinfo->track[x].te.cdte_track = x+1; + cdinfo->track[x].te.cdte_format = CDROM_MSF; + if( ioctl( fd, CDROMREADTOCENTRY, &cdinfo->track[x].te ) != 0 ) + { + perror( "set_track_length(CDROMREADTOCENTRY)" ); + return -1; + } + + cdinfo->track[x].frame_offset = cdinfo->track[x].te.cdte_addr.msf.minute * 60 + cdinfo->track[x].te.cdte_addr.msf.second; + + /* Convert seconds to frames */ + cdinfo->track[x].frame_offset *= 75; + cdinfo->track[x].frame_offset += cdinfo->track[x].te.cdte_addr.msf.frame; + + /* + * Set the length of the previous track + * Accomplished by taking the start of the current track - start + * of the previous track. + */ + if( x > 0 ) + { + /* Set length to the start of the current one */ + cdinfo->track[x-1].length = (cdinfo->track[x].te.cdte_addr.msf.minute * 60) + cdinfo->track[x].te.cdte_addr.msf.second; + + /* Subtract the start of the previous track */ + cdinfo->track[x-1].length = cdinfo->track[x-1].length - ((cdinfo->track[x-1].te.cdte_addr.msf.minute * 60) + cdinfo->track[x-1].te.cdte_addr.msf.second); + +#ifdef DEBUG1 + /* Show some debug data on the tracks we find */ + g_print("track %d - length = %d seconds\n", x-1, cdinfo->track[x-1].length ); +#endif + } + } + + /* + * Set the length of the last track + * This is accomplished by subtracting the last track start from the + * length of the CD. + */ + x--; + cdinfo->track[x].length = cdinfo->cd_length - ((cdinfo->track[x].te.cdte_addr.msf.minute * 60) + cdinfo->track[x].te.cdte_addr.msf.second ); + +#ifdef DEBUG1 + /* Show debug data on the last track */ + g_print("track %d - length = %d seconds\n", x, cdinfo->track[x].length ); + + g_print("New CD loaded: "); + g_print("%d tracks, cd_length = %d, ", cdinfo->tochdr.cdth_trk1, cdinfo->cd_length ); + g_print("volume = %d\n", cdinfo->volume ); +#endif + + /* Calculate the discid for this CD */ + cdinfo->discid = cddb_discid( cdinfo ); + + cdinfo->revision = -1; + cdinfo->extd = NULL; + + + /* All is well */ + return fd; +} + + +/* ---------------------------------------------------------------------- + Control the low-level audio CD player + + Wait for commands from the parent, execute the command and send back + a response if one is needed + + A command is 2 bytes of data - a command and an optional argument. + The Commands are defined in cd_control.h as CD_* + + To init the cd, if status is called the first time it will try to init + the CD. If this fails it sets cd_fd to -1, so status won't repeatedly + try the CD. After the initial failure only a play will try. + + ----------------------------------------------------------------------- */ +int cd_control( int control_fd ) +{ + char cmnd[2], + cd_device[80]; /* Device to talk to */ + struct cdrom_volctrl volctrl; /* Volume control */ + struct CDINFO cdinfo; /* All the info on the CD */ + int fd_cd=0; + + /* Default cdrom device */ + strcpy( cd_device, "/dev/cdrom" ); + + for(;;) + { + /* Get the command from the parent process */ + if( read( control_fd, &cmnd, 2 ) != 2 ) + return(-1); + + switch( cmnd[0] ) + { + case CD_DIAG : + puts("cd_control diagnostic\n"); + break; + + case CD_STATUS : + if( fd_cd > 0 ) + { + cdinfo.sc.cdsc_format = CDROM_MSF; /* Info in MM:SS:FF format*/ + if( ioctl( fd_cd, CDROMSUBCHNL, &cdinfo.sc ) != 0 ) + { + /* perror( "cd_control(CDROMSUBCHNL-2)" ); */ + cdinfo.sc.cdsc_audiostatus = CDROM_AUDIO_NO_STATUS; + } + } else { + cdinfo.sc.cdsc_audiostatus = CDROM_AUDIO_NO_STATUS; + } + + /* Send the new data back to the main process */ + write( control_fd, &cdinfo, sizeof( struct CDINFO ) ); + break; + + + case CD_PLAY : + /* If we are not open yet, try to open it first */ + if( fd_cd < 1 ) + { + fd_cd = cdrom_init( &cdinfo, &volctrl, cd_device ); + + /* Start playing at the beginning*/ + cmnd[1] = cdinfo.tochdr.cdth_trk0; + } + + if( fd_cd > 0 ) + { + /* Setup the CD to play the indicated track */ + cdinfo.ti.cdti_trk0 = cmnd[1]; + cdinfo.ti.cdti_trk1 = cdinfo.tochdr.cdth_trk1; + cdinfo.ti.cdti_ind0 = cdinfo.ti.cdti_ind1 = 0; + + /* Stop playing previous track and start playing the next */ + /* Try this without the stop and see what happens... */ + if( ioctl( fd_cd, CDROMSTOP ) != 0 ) + { + perror( "cd_control(CDROMSTOP-1)" ); + } else if( ioctl( fd_cd, CDROMPLAYTRKIND, &cdinfo.ti ) != 0 ) { + perror( "cd_control(CDROMPLAYTRKIND-1)" ); + } + } + break; + + case CD_PAUSE : + if( fd_cd > 0 ) + { + if( ioctl( fd_cd, CDROMPAUSE ) != 0 ) + perror( "cd_control(CDROMPAUSE)" ); + } + break; + + case CD_RESUME : + if( fd_cd > 0 ) + { + if( ioctl( fd_cd, CDROMRESUME ) != 0 ) + perror( "cd_control(CDROMRESUME)" ); + } + break; + + case CD_STOP : + if( fd_cd > 0 ) + { + if( ioctl( fd_cd, CDROMSTOP ) != 0 ) + perror( "cd_control(CDROMSTOP-2)" ); + + close( fd_cd ); + fd_cd = 0; + } + break; + + case CD_VOLUME : + if( fd_cd > 0 ) + { + cdinfo.volume = (unsigned char) cmnd[1]; + + volctrl.channel0 = cdinfo.volume; + volctrl.channel1 = cdinfo.volume; + if( ioctl( fd_cd, CDROMVOLCTRL, &volctrl ) != 0 ) + perror( "cd_control(CDROMVOLCTRL-3)" ); + } + break; + + case CD_EJECT : + if( (fd_cd > 0) ) + { + /* Stop playing, then eject the CD */ + if( ioctl( fd_cd, CDROMSTOP ) != 0 ) + { + perror( "cd_control(CDROMSTOP-3)" ); + } else if( ioctl( fd_cd, CDROMEJECT ) != 0 ) { + perror( "cd_control(CDROMEJECT)" ); + } + close( fd_cd ); + fd_cd = 0; + } + break; + + case CD_SET_EJECT : + if( fd_cd > 0 ) + { + /* Set the software configurable eject on close state */ + if( ioctl( fd_cd, CDROMEJECT_SW, cmnd[1] ) != 0 ) + perror("cd_control(CDROMEJECT_SW)"); + } + break; + + /* Set the default device, close the current device and open the + new one */ + case CD_SET_DEVICE : + +#ifdef DEBUG3 + printf("got CD_SET_DEVICE\n"); +#endif + + /* + This routine is different from the others, it reads a string from + the sending process after receiving the 2 byte command + */ + if( readline( control_fd, cd_device, 80 ) < 0 ) + { + perror("readline - 2"); + } + + /* Strip trailing CR */ + if( cd_device[strlen(cd_device)-1] == '\n' ) + cd_device[strlen(cd_device)-1] = 0; + +#ifdef DEBUG3 + printf("Setting cd_control cd_device = %s\n", cd_device ); +#endif + /* If a device isn't open, then open one */ + if( fd_cd < 1 ) + fd_cd = cdrom_init( &cdinfo, &volctrl, cd_device ); + + break; + + + case CD_QUIT : + if( fd_cd ) + close( fd_cd ); + return(0); + break; + } + } + return(0); +} diff --git a/cd_control.h b/cd_control.h @@ -0,0 +1,85 @@ +/* ------------------------------------------------------------------------ + cd_control include file for XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + 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. + + ------------------------------------------------------------------------ */ +#include <linux/cdrom.h> + +#define CD_DIAG 0x00 +#define CD_PLAY 0x01 +#define CD_PAUSE 0x02 +#define CD_STOP 0x03 +#define CD_EJECT 0x04 +#define CD_SEEK_FWD 0x05 +#define CD_SEEK_REV 0x06 +#define CD_RESUME 0x07 +#define CD_VOLUME 0x08 +#define CD_STATUS 0x09 +#define CD_TOC 0x0A +#define CD_QUIT 0x0B +#define CD_SET_EJECT 0x0C +#define CD_SET_DEVICE 0x0D + + +int start_cd_control( int * ); + + +struct song_info { + struct cdrom_tocentry te; /* TOC entry data */ + int length; /* Length of this track in sec */ + long frame_offset; /* Frame Offset in 1/75 frames */ +}; + +struct CDINFO { + unsigned long discid; /* cddb disc ID */ + int disc; /* disc # being played, for + future support for jukeboxes + */ + int track_length; /* Length of current track */ + int cd_length; /* Length of the CD */ + int cd_remaining; /* Remaining # of seconds on CD */ + int volume; /* Volume setting */ + + /* Info on the current cdrom in the drive */ + struct cdrom_tochdr tochdr; /* TOC Headers */ + struct cdrom_tocentry leadout; /* Last track info */ + struct cdrom_ti ti; /* Track(s) to play + Track indexing + */ + struct cdrom_subchnl sc; /* Drive status */ + struct song_info track[99]; /* Info on songs on this CD */ + + GString *title; /* Title of this CD */ + GString *category; /* CDDBD category */ + GString *name[99]; /* Name of the track */ + GString *extd; /* Extended data for the CD */ + GString *extt[99]; /* Extended Track info */ + int revision; /* CDDB entry revision # */ + + + /* Data used for talking to the other processes */ + int cddbd_cmnd, /* Command for cddbd */ + cddbd_stat; /* Status of process */ + char server[80]; /* Server to connect to */ + int port; /* Port on server */ + char line[255]; /* Text from MOTD or SITES */ + char local_cddb[1024]; /* Path to local CDDB database */ + char device[80]; /* CDROM device */ +}; diff --git a/cddb.c b/cddb.c @@ -0,0 +1,888 @@ +/* --------------------------------------------------------------------- + basic cddb functions for XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + 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. + + =============================[ HISTORY ]============================= + 06/19/98 Adding write extended data to the database. DONE. + Switching to using g_malloc, g_free, g_realloc -- they're + safer than libc and can provide usage stats. + + 06/16/98 Need to add support for extended data lines. Split lines + too of course. This data needs to make it into the + database, and be able to send it to the server when + the CD is edited. + + Revision # support needs to be added to. Read it and + increment it when the CD is submitted to the server. + FIXED. + + 06/06/98 I need to support split TTITLE lines, and get the + track # from the TTITLE line instead of assuming they + just go in order. + I found my garbage at the end of the file problem. If + A long file was written then it was shortened it + wouldn't erase it first, it would just write over + the top and leave the old stuff hanging off the end. + So I added an unlink to delete it first. + + 05/27/98 Adding creation of the cddb database directories if + they don't exist (only creates the ones that don't + exist). Added to write_cddb(). Only creates what it + needs to. This way it isn't limited to a static list of + categories. Works. + Found a bug. CDDB read/write don't handle multiple + DTITLEs very well. + + 05/16/98 Added expansion of ~/ to $HOME enviornmental variable + Added a local_cddb path in the cdinfo structure to point + to the local storage location for writing and reading + cd information. + + 05/11/98 Split off reading code to read_cddb_file so it can be + used to read a specific temporary file after the data + is downloaded from the server. + + 05/09/98 Started this part of the XfreeCD code. + Correct operation confirmed for discid using + Bryan Adams / Waking up the Neighbors id 0xce118c0f + Writing database entries works well so far, frames, + length, and discid are correct. Default track and title + strings are saved ok too. + find_discid works. + + --------------------------------------------------------------------- + This file includes support for saving and loading local database + information. + --------------------------------------------------------------------- */ +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <dirent.h> +#include <stdlib.h> +#include <errno.h> +#include <gtk/gtk.h> +#include "xfreecd.h" +#include "cd_control.h" +#include "cddb.h" + +#undef DEBUG1 +#undef DEBUG2 +#undef DEBUG3 +#undef DEBUG6 +#undef DEBUG9 + +int +cddb_sum(int n) +{ + char buf[12], + *p; + int ret = 0; + + /* For backward compatibility this algorithm must not change */ + sprintf(buf, "%lu", n); + for (p = buf; *p != '\0'; p++) + ret += (*p - '0'); + + return (ret); +} + +unsigned long cddb_discid( struct CDINFO *cdinfo ) +{ + int i, + t = 0, + n = 0, + tot_trks; + + tot_trks = cdinfo->tochdr.cdth_trk1; + + /* For backward compatibility this algorithm must not change */ + for (i = 0; i < tot_trks; i++) + n += cddb_sum((cdinfo->track[i].te.cdte_addr.msf.minute * 60) + cdinfo->track[i].te.cdte_addr.msf.second); + + t = ((cdinfo->leadout.cdte_addr.msf.minute * 60) + cdinfo->leadout.cdte_addr.msf.second) - ((cdinfo->track[0].te.cdte_addr.msf.minute * 60) + cdinfo->track[0].te.cdte_addr.msf.second); + + return ((n % 0xff) << 24 | t << 8 | tot_trks); +} + + +/* ------------------------------------------------------------------------- + Write the data from cdinfo structure to the correct file in the selected + category. + + The master database directory is in cdinfo->local_cddb + + How do I check for the same CD with a different ID so I can symlink? + + if over is 0 then check to make sure the file doesn't already exist + if over is 1 then go ahead and overwrite it. + + return -2 if the file already exists. + return -3 if the HOME variable cannot be found + return -4 if we had trouble creating the local cddb directories + ------------------------------------------------------------------------- */ +int write_cddb( struct CDINFO *cdinfo, int over ) +{ + char fname[1024], + tmp_fname[1024], + tmpstr[255], + idstr[9], + *p; + int fd, + x, + i; + struct stat sbuf; + + /* Copy the path to the local datbase to a temporary variable */ + strncpy( fname, cdinfo->local_cddb, 1023 ); + + /* Convert a leading ~ into the user's HOME directory */ + if( fname[0] == '~' ) + { + /* Copy the reset of the path/filename to tmp_fname */ + strncpy( tmp_fname, &fname[1], 1023 ); + + if( ( p = getenv("HOME") ) == NULL ) + { + return(-3); + } + strncpy( fname, p, 1023 ); + + /* Make sure there is a slash inbetween */ + if( (fname[strlen(fname)-1] != '/') && (tmp_fname[0] != '/') ) + { + strcat( fname, "/" ); + } + + strncat( fname, tmp_fname, 1023-strlen( p ) ); + } + +#ifdef DEBUG1 + g_print("write_cddb( %s )\n", fname ); +#endif + + /* + See if we have the top level directory. If not, try to create it. + */ + if( stat( fname, &sbuf ) < 0 ) + { + /* If the top level directory doesn't exist, create it */ + if( errno == ENOENT ) + { + /* Try to make the top level directory, if it fails, quit */ + if( mkdir( fname, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH ) < 0 ) + { + return(-4); + } + } else { + return(-4); + } + } + + + /* Make sure we have slashes between the path and category directory */ + if( fname[strlen(fname)] != '/' ) + strcat( fname, "/" ); + strcat( fname, cdinfo->category->str ); + if( fname[strlen(fname)] != '/' ) + strcat( fname, "/" ); + + /* + See if the category directory exists. If not, create it. + */ + if( stat( fname, &sbuf ) < 0 ) + { + /* If the top level directory doesn't exist, create it */ + if( errno == ENOENT ) + { + /* Try to make the category directory, if it fails, quit with an error*/ + if( mkdir( fname, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH ) < 0 ) + { + return(-4); + } + } else { + return(-4); + } + } + + sprintf( idstr, "%08lx", cdinfo->discid ); + strcat( fname, idstr ); + + /* Should we check for prior existance? */ + if( !over ) + { + if( ( fd = open( fname, O_RDONLY ) ) != -1 ) + { + close( fd ); + return(-2); + } + } + + /* Make sure it is deleted */ + unlink( fname ); + + if( ( fd = open( fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ) < 0 ) + { + return(-1); + } + + /* Write the cddb entry from the info in the cdinfostructure */ + sprintf( tmpstr, "# xmcd CD database file generated by XfreeCD %s\n", VERSION ); + + if( write( fd, tmpstr, strlen( tmpstr) ) < 0 ) + { + close( fd ); + return(-1); + } + + sprintf( tmpstr, "#\n# Track frame offsets:\n" ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + /* Write the frame offset for each track */ + for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ ) + { + sprintf( tmpstr, "#\t%ld\n", cdinfo->track[x].frame_offset ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + } + + strcpy( tmpstr, "#\n" ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + sprintf( tmpstr, "# Disc length: %d seconds\n#\n", cdinfo->cd_length ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + sprintf( tmpstr, "# Revision: %d\n", cdinfo->revision ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + sprintf( tmpstr, "# Submitted via: XfreeCD %s\n#\n", VERSION ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + sprintf( tmpstr, "DISCID=%08lx\n", cddb_discid( cdinfo ) ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + if( (cdinfo->title == NULL) || (cdinfo->title->len == 0) ) + { + if( write( fd, "DTITLE=\n", 8 ) < 0 ) + { + close( fd ); + return(-1); + } + } else { + /* If the title is too long, split it up into 70 byte chunks */ + i = 0; + p = cdinfo->title->str; + while( i < cdinfo->title->len ) + { + strcpy( tmpstr, "DTITLE=" ); + strncat( tmpstr, p, 70 ); + strcat( tmpstr, "\n" ); + + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + if( cdinfo->title->len > 70 ) + { + p = p + 70; + i += 70; + } else { + i = cdinfo->title->len; + } + } + } + + /* Write the titles */ + for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ ) + { + if( (cdinfo->name[x] == NULL) || (cdinfo->name[x]->len == 0) ) + { + sprintf( tmpstr, "TTITLE%d=\n", x ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + } else { + + /* If the track name is too long, split it up into 70 byte chunks */ + i = 0; + p = cdinfo->name[x]->str; + while( i < cdinfo->name[x]->len ) + { + sprintf( tmpstr, "TTITLE%d=", x ); + strncat( tmpstr, p, 70 ); + strcat( tmpstr, "\n" ); + + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + if( cdinfo->name[x]->len > 70 ) + { + p = p + 70; + i += 70; + } else { + i = cdinfo->name[x]->len; + } + } + } + } + + /* Check for a null entry first */ + if( (cdinfo->extd == NULL) || (cdinfo->extd->len == 0) ) + { + if( write( fd, "EXTD=\n", 6 ) < 0 ) + { + close( fd ); + return(-1); + } + } else { + /* Write the extended disc data to the file. It it is too long, break it + up into 70 byte chuncks + */ + i = 0; + p = cdinfo->extd->str; + while( i < cdinfo->extd->len ) + { + strcpy( tmpstr, "EXTD=" ); + strncat( tmpstr, p, 70 ); + strcat( tmpstr, "\n" ); + + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + if( cdinfo->extd->len > 70 ) + { + p = p + 70; + i += 70; + } else { + i = cdinfo->extd->len; + } + } + } + + /* Write the extended title information to the database */ + for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ ) + { + if( (cdinfo->extt[x] == NULL) || (cdinfo->extt[x]->len == 0) ) + { + sprintf( tmpstr, "EXTT%d=\n", x ); + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + } else { + /* If the track name is too long, split it up into 70 byte chunks */ + i = 0; + p = cdinfo->extt[x]->str; + while( i < cdinfo->extt[x]->len ) + { + sprintf( tmpstr, "EXTT%d=", x ); + strncat( tmpstr, p, 70 ); + strcat( tmpstr, "\n" ); + + if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 ) + { + close( fd ); + return(-1); + } + + if( cdinfo->extt[x]->len > 70 ) + { + p = p + 70; + i += 70; + } else { + i = cdinfo->extt[x]->len; + } + } + } + } + + /* XfreeCD doesn't use this at all */ + if( write( fd, "PLAYORDER=\n", 11 ) < 0 ) + { + close( fd ); + return(-1); + } + + close( fd ); + + return(0); +} + + +/* ----------------------------------------------------------------------- + Search all sub-directories below CDDB_PATH for the file to read + Fills in the category with the name of the trailing directory that + it is found in. + + + Return 0 on file found + Return -1 on an error + Return -2 on no file found + ----------------------------------------------------------------------- */ +int find_discid( char *fname, /* Path to local database */ + unsigned long id, /* discid to search for */ + char *path, /* Return full path */ + GString **category ) /* Return category found */ +{ + DIR *dp; + struct dirent *dirp; + char idstr[9], + tmp_fname[1024], + *p; + int fp; + + /* Convert a leading ~ into the user's HOME directory */ + if( fname[0] == '~' ) + { + /* Copy the reset of the path/filename to tmp_fname */ + strncpy( tmp_fname, &fname[1], 1023 ); + + if( ( p = (char *) getenv("HOME") ) == NULL ) + { + return(-2); + } + strncpy( fname, p, 1023 ); + + /* Make sure there is a slash inbetween the two */ + if( (fname[strlen(fname)-1] != '/') && (tmp_fname[0] != '/') ) + { + strcat( fname, "/" ); + } + + strncat( fname, tmp_fname, 1023-strlen( p ) ); + } + +#ifdef DEBUG1 + g_print("find_discid( %s )\n", fname ); +#endif + + + sprintf( idstr, "%08lx", id ); + + if( ( dp = opendir( fname ) ) == NULL ) + return(-1); + + while( ( dirp = readdir( dp ) ) != NULL ) + { + if( (strcmp(dirp->d_name,"." )==0) || (strcmp(dirp->d_name, "..")==0) ) + continue; + + strcpy( path, fname ); + if( path[strlen(path)] != '/' ) + strcat( path, "/" ); + strcat( path, dirp->d_name ); + if( path[strlen(path)] != '/' ) + strcat( path, "/" ); + strcat( path, idstr ); + + /* Copy the directory name as the category name */ + if( *category == NULL ) + *category = g_string_new( dirp->d_name ); + else + *category = g_string_assign( *category, dirp->d_name ); + +#ifdef DEBUG1 + g_print("Checking %s\n", path ); +#endif + + /* Does this file exist? */ + if( ( fp = open( path, O_RDONLY ) ) != -1 ) + { + close( fp ); + closedir( dp ); + return(0); + } + } + + closedir( dp ); + + return(-2); +} + + +/* ----------------------------------------------------------------------- + Read the CDDB info from a filename into a cdinfo structure + Allocate all needed string storage using gtk's g_string functions + + return -2 = failed to find HOME enviornmental variable + ----------------------------------------------------------------------- */ +int read_cddb_file( char *fname, struct CDINFO *tmpinfo ) +{ + int gotid, + i, + x, + f; + FILE *fp; + char line[255], + discid[9], + *p; + + if( ( fp = fopen( fname, "r" ) ) == NULL ) + { + return(-1); + } + + /* Read the cddb file, placing data into tmpinfo */ + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + + /* Check the file to make sure its a cddb file */ + if( strncmp( line, "# xmcd", 6 ) != 0 ) + { + fclose( fp ); + return(-1); + } + +#ifdef DEBUG1 + g_print("%s", line ); +#endif + + /* Find the track offsets, abort serarch at the end of comments */ + while( ( line[0] == '#' ) && ( strncmp( line, "# Track frame offsets:",22 ) != 0 ) ) + { + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + + /* Skip all the reset of the comments up to Revision: */ + while( line[0] == '#' && (strncmp( line, "# Revision:", 11)!=0) ) + { + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + + /* If we got the Revision line, get the revision # */ + if( strncmp( line, "# Revision:", 11)==0 ) + { + sscanf( line, "# Revision: %d", &tmpinfo->revision ); + + /* Now read the rest of the comments */ + while( line[0] == '#' ) + { + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + } + + /* Read discid lines */ + /* + How should this be handled? check for our id, and discard all others + that may be present? + + DISCID= lines are comma seperated and can be multiple lines + */ + gotid = 0; + sprintf( discid, "%08lx", tmpinfo->discid ); + while( strncmp( line, "DISCID=", 7 ) == 0 ) + { + if( strstr( line, discid ) != NULL ) + gotid = 1; + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + + /* Process multiple DTITLE lines and concatanate them */ + i = 0; + f = 0; + while( strncmp( line, "DTITLE", 6 ) == 0 ) + { + p = strtok( line, "=\n" ); + p = strtok( NULL, "=\n" ); + + /* Add the title to the tmpinfo.title string */ + if( f == 0 ) + { + tmpinfo->title = g_string_new( p ); + f = 1; + } else { + tmpinfo->title = g_string_append( tmpinfo->title, p ); + } + + /* Keep reading DTITLE no matter what */ + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + +#ifdef DEBUG1 + g_print("title read = %s\n", tmpinfo->title->str ); +#endif + + /* + Copy the titles from the TTITLE strings + + This has to: + Get the track # from the TTITLEx + strcat split title lines up to the limit of storage (255) + */ + x = -1; + f = 0; + while( strncmp( line, "TTITLE", 6 ) == 0 ) + { + /* Get the track # */ + p = strtok( &line[6], "=\n" ); + + /* Is it a new track? */ + if( atoi(p) != x ) + { + /* Yes, reset the length counter and track name */ + i = 0; + f = 0; + tmpinfo->name[atoi(p)] = NULL; + } + + /* Get the track number and make sure its not too big. */ + if( ( x = atoi( p ) ) < 99 ) + { + /* Get the track name */ + p = strtok( NULL, "=\n" ); + + /* If its blank, then insert default track name */ + if( p == NULL ) + { + tmpinfo->name[x] = NULL; + } else { + if( f == 0 ) + { + tmpinfo->name[x] = g_string_new( p ); + f = 1; + } else { + tmpinfo->name[x] = g_string_append( tmpinfo->name[x], p ); + } + } + } + + /* Read the next line */ + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + + + /* Process multiple EXTD lines and concatanate them, dynamically + allocating memory at tmpinfo->extd for it + */ + i = 0; + f = 0; + tmpinfo->extd = NULL; + while( strncmp( line, "EXTD", 4 ) == 0 ) + { + /* Add to the data until the end is reached */ + p = strtok( line, "=\n" ); + p = strtok( NULL, "=\n" ); + + if( p != NULL ) + { + /* Move the pointer and copy the new string */ + if( f == 0 ) + { + tmpinfo->extd = g_string_new( p ); + f = 1; + } else { + tmpinfo->extd = g_string_append( tmpinfo->extd, p ); + } + } + + /* Keep reading lines */ + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + + + /* + Copy the extended title data from the EXTTx entries + + This has to: + Get the track # from the EXTTx + Allocate storage for it and copy it over, and handle multiple lines + for each track entry. + */ + x = -1; + f = 0; + while( strncmp( line, "EXTT", 4 ) == 0 ) + { + /* Get the track # */ + p = strtok( &line[4], "=\n" ); + + /* Is it a new track? */ + if( atoi(p) != x ) + { + /* Yes, reset the length counter and track name */ + i = 0; + f = 0; + tmpinfo->extt[atoi(p)] = NULL; + } + + /* Get the track number, make sure it isn't too big */ + if( ( x = atoi( p ) ) < 99 ) + { + /* Get the extended data from the rest of the line*/ + p = strtok( NULL, "=\n" ); + + /* Process multiple EXTT lines and concatanate them, dynamicly + allocating memory at tmpinfo->extd for it + */ + if( p != NULL ) + { + /* Move the pointer and copy the new string */ + if( f == 0 ) + { + tmpinfo->extt[x] = g_string_new( p ); + f = 1; + } else { + tmpinfo->extt[x] = g_string_append( tmpinfo->extt[x], p ); + } + } + } + + /* Read the next line */ + if( fgets( line, 255, fp ) == NULL ) + { + fclose( fp ); + return(-1); + } + } + + fclose( fp ); + + return(0); +} + + +/* ----------------------------------------------------------------------- + Read a cddb entry for the current CD + + This needs to search through the sub-directories in CDDB_PATH to find + the discid of the current CD. + + We then read the file, filling in the track names, etc. + We should also compare the frame count to make sure it is the + correct CD. + + Returns -1 if there was an error + Returns -2 if it cannot find the file + ----------------------------------------------------------------------- */ +int read_cddb( struct CDINFO *cdinfo ) +{ + int x; + char fname[255]; + struct CDINFO tmpinfo; + + /* Clean out the structure */ + bzero( &tmpinfo, sizeof( struct CDINFO ) ); + + tmpinfo.discid = cdinfo->discid; + + /* Find out where this ID lives and fill in fname with full name */ + if( find_discid( cdinfo->local_cddb, tmpinfo.discid, fname, &tmpinfo.category ) < 0 ) + { + /* Could not find an entry for this */ + return(-2); + } + + if( read_cddb_file( fname, &tmpinfo ) == 0 ) + { + cdinfo->title = tmpinfo.title; + for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ ) + { + cdinfo->name[x] = tmpinfo.name[x]; + } + + /* Copy the category over too */ + cdinfo->category = tmpinfo.category; + + /* Copy the revision # over if it is valid */ + if( tmpinfo.revision >= 0 ) + cdinfo->revision = tmpinfo.revision; + else + cdinfo->revision = 1; + + /* Copy the extd pointer over */ + cdinfo->extd = tmpinfo.extd; + + /* Copy all the extended track pointers */ + for( x = 0; x < 99; x++ ) + cdinfo->extt[x] = tmpinfo.extt[x]; + } + + return(0); +} diff --git a/cddb.h b/cddb.h @@ -0,0 +1,27 @@ +/* ------------------------------------------------------------------------ + cddb include file for XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + 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. + + ------------------------------------------------------------------------ */ +unsigned long cddb_discid( struct CDINFO * ); +int write_cddb( struct CDINFO *, int ); +int read_cddb( struct CDINFO * ); +int read_cddb_file( char *, struct CDINFO *); +int find_discid( char *, unsigned long, char *, GString ** ); diff --git a/cddbd.c b/cddbd.c @@ -0,0 +1,1220 @@ +/* --------------------------------------------------------------------- + cddbd interface for XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + 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. + + =============================[ HISTORY ]============================= + 07/05/98 Removed the strcat of tmpstr from the track offset loop + when requesting CD info. This was causing the odd + behavior, depending on the state of memory. + + 06/19/98 Changed offset in the track loop to be 0 reference + instead of 1. + + 06/16/98 NIN Broken is living up to its name. It is causing the + server to return an error 500. Hmm, I somehow left out + the length of the cd. This is fixed. It now downloads + NIN correctly (woo hoo, ack, pthhhtttt). Anyone want + a copy of NIN Broken? I'll mail it to you in little + pieces... + + 06/02/98 Sending the full line returned by the server to the + caling process in cdinfo.line + + 05/24/98 Adding support for inexact matches. + Adding a return type of CDDBD_INEX_LINE + + 05/11/98 Adding more information from main process. Passes a + cdinfo structure. + + 05/10/98 Added basic socket open/close/read/write functions. + + 05/09/98 Started this part of the XfreeCD code. + + + --------------------------------------------------------------------- + This implements the internet connection to a cddbd server. Local data + is accessed using the functions in ... + + Hmm, how to implemetn all this? + State machine for error responses and link to next command? + + I also need to get more info on the CD than just the CD's discid + + --------------------------------------------------------------------- */ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <string.h> +#include <gtk/gtk.h> +#include "xfreecd.h" +#include "child_sync.h" +#include "cd_control.h" +#include "cddbd.h" +#include "cddb.h" + + +#undef DEBUG1 +#undef DEBUG3 + +int cddbd( int ); + +/* + Fire up the cddb process. + Create a socket pair. + Fork a child process + Return the parent's file descriptor for the socket or -1 + errno + fill in childpid with the child's PID + Child calls cddbd +*/ +int start_cddbd( int *childpid ) +{ + int fd[2]; + + if( socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) < 0 ) + return(-1); + + if( ( *childpid = fork() ) < 0 ) + { + perror("start_cddbd, cannot fork"); + return(-1); + } else if( *childpid == 0 ) { + close( fd[0] ); + + /* Synchronize with the parent, exit if it fails */ + if( parent_sync( fd[1] ) == 0 ) + cddbd( fd[1] ); + + close( fd[1] ); + exit(0); + } + close( fd[1] ); + + if( child_sync( fd[0] ) == 0 ) + return(fd[0]); + + return(-1); +} + +/* ----------------------------------------------------------------------- + Read a line from the socket + ----------------------------------------------------------------------- */ +int readn( register int fd, register char *ptr, register int nbytes ) +{ + int nleft, + nread; + + nleft = nbytes; + while( nleft > 0 ) + { + nread = read( fd, ptr, nleft ); + if( nread < 0 ) + return( nread ); + else if( nread == 0 ) + break; + + nleft -= nread; + ptr += nread; + } + return (nbytes - nleft); +} + + +/* ----------------------------------------------------------------------- + Write n bytes of data to the socket + + Loop until all the data is written. + ----------------------------------------------------------------------- */ +int writen( register int fd, register char *ptr, register int nbytes ) +{ + int nleft, + nwritten; + + nleft = nbytes; + while( nleft > 0 ) + { + nwritten = write( fd, ptr, nleft ); + if( nwritten <= 0 ) + return( nwritten ); + + nleft -= nwritten; + ptr += nwritten; + } + + return (nbytes - nleft ); +} + + +/* ----------------------------------------------------------------------- + A VERY inefficent read routine. I need to rewrite this to read as much + as possible and scan the buffer read... + + But then how do you put back characters after the CR that you want to + read the next time it is called? Static holding previous spares maybe? + ----------------------------------------------------------------------- */ +int readline( register int fd, register char *ptr, register int maxlen ) +{ + int n, + rc; + char c; + + for( n = 1; n < maxlen; n++ ) + { + if( ( rc = read( fd, &c, 1 ) ) == 1 ) + { + *ptr++ = c; + if( c == '\n' ) + break; + } else if( rc == 0 ) { + if( n == 1 ) + return(0); + else + break; + } else { + return(-1); + } + } + + *ptr = 0; + return(n); +} + + +/* ----------------------------------------------------------------------- + Open a cddbd connection, return the fd + + This handles the connection and initial login to the server, + returns error codes on failure. + + Pass the server name and port + ----------------------------------------------------------------------- */ +int open_cddbd( char *server, int port ) +{ + struct sockaddr_in tcp_srv_addr; /* Server's Internet socket addr. */ + struct hostent tcp_host_info; /* from gethostbyname */ + struct hostent *hp; + unsigned long inaddr; + int fd; + + + bzero( &tcp_srv_addr, sizeof( tcp_srv_addr ) ); + tcp_srv_addr.sin_family = AF_INET; + + + /* Setup the port, exit if illegal passed */ + if( port < 1 ) + return(-2); + + tcp_srv_addr.sin_port = htons( port ); + + /* Try the hostname as a dotted decimal first */ + if( ( inaddr = inet_addr( server ) ) != INADDR_NONE ) + { + bcopy((char *)&inaddr,(char *)&tcp_srv_addr.sin_addr,sizeof(inaddr)); + tcp_host_info.h_name = NULL; + } else { + /* Not dotted decimal, try it as a name */ + if( ( hp = gethostbyname( server ) ) == NULL ) + { + return(-3); + } + tcp_host_info = *hp; /* Copy the structure */ + bcopy( hp->h_addr, (char *) &tcp_srv_addr.sin_addr, hp->h_length ); + } + + /* Create the socket */ + if( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) + { + return(-4); + } + + /* Connect to the server */ + if( connect(fd,(struct sockaddr *)&tcp_srv_addr,sizeof(tcp_srv_addr)) < 0 ) + { + close( fd ); + return(-5); + } + + return(fd); +} + +/* ----------------------------------------------------------------------- + Close down the connection to the server. + + Send quit and close socket + ----------------------------------------------------------------------- */ +int close_cddbd( fd ) +{ + char line[255]; + + writen( fd, "quit\n", strlen( "quit\n" ) ); + + /* Read the closing banner from the server */ + if( readline( fd, line, 255 ) < 0 ) + { + close( fd ); + return(-2); + } + +#ifdef DEBUG1 + g_print("%s", line ); +#endif + + close( fd ); + return(0); +} + + +/* ----------------------------------------------------------------------- + Return the response code + ----------------------------------------------------------------------- */ +int cddbd_code( char *line ) +{ + char *p; + + p = strtok( line, " \n" ); + return( atoi( p ) ); +} + + + +/* ----------------------------------------------------------------------- + Watch for commands from the main process and execute connections to + the indicated cddbd internet database server. + + Commands ... DB_* + Uses the cddbd_cmnd structure to pass the command, server and port. + + Also need to read the sites listing, and motd. + + Retrieve data for ID from server SERVER using PORT + + returns a CDINFO structure with a status byte? How to keep it updated + without returning a full CDINFO every time? + + As we progress thru the protocol, send back status updates to the parent + process. + + ----------------------------------------------------------------------- */ +int cddbd( int control_fd ) +{ + struct CDINFO cdinfo; + FILE *fp; + int cddbd_fd; + char line[255], + *tmpfile, + *p; + int x, + code; + + + for(;;) + { + /* Get the command from the parent process */ + if( read( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd read error"); + return(-1); + } + + switch( cdinfo.cddbd_cmnd ) + { + case DB_DIAG : + puts("cddbd diagnostic\n"); + break; + + /* Get the info on a CD from the server */ + case DB_READ : + +#ifdef DEBUG1 + g_print("Searching for 0x%08x at %s : %d\n", cdinfo.discid, cdinfo.server, cdinfo.port ); +#endif + + if( (cddbd_fd = open_cddbd( cdinfo.server, cdinfo.port )) < 0 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the connection failed */ + cdinfo.cddbd_stat = CDDBD_OPEN_ERR; + sprintf( cdinfo.line, "err=%d", cddbd_fd ); + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-1"); + break; + } + break; + } + + /* Tell the parent we are connected ok */ + cdinfo.cddbd_stat = CDDBD_OPEN_OK; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-2"); + break; + } + + /* Read the opening banner from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-3"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 201 ) + { + close_cddbd( cddbd_fd ); + /* Tell the parent the connect failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-4"); + break; + } + break; + } + + /* Identify ourself to the server */ + sprintf( line, "cddb hello %s %s XfreeCD %s\n", getenv("USER"), + getenv("HOSTNAME"), + VERSION ); + +#ifdef DEBUG1 + g_print("%s", line ); +#endif + + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-5"); + break; + } + break; + } + + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-6"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 200 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-7"); + break; + } + break; + } + + /* Send a Query to the server */ + /* This can be quite! long (try NIN broken, 99 tracks) so break it up + into smaller chuncks + */ + sprintf( line, "cddb query %08lx %d ", cdinfo.discid, cdinfo.tochdr.cdth_trk1 ); + +#ifdef DEBUG1 + g_print("%s", line ); +#endif + + /* Write the first part of the query to the server */ + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + break; + } + + /* List of offsets, send it one offset at a time */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + sprintf( line, "%ld ", cdinfo.track[x].frame_offset ); + +#ifdef DEBUG1 + g_print("[%d]%s", x, line ); +#endif + + /* Write this next chunck of the request */ + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + break; + } + } + + /* End of the query with length in seconds */ + sprintf(line, "%d\n", cdinfo.cd_length ); + +#ifdef DEBUG1 + g_print("%s", line ); +#endif + + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + break; + } + + /* Get the response from the server, get the coded response, + and the rest up to the '.' + */ + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-9"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( (code > 211) || (code==202) ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-10"); + break; + } + break; + } + + /* Inexact match, get the list */ + if( code == 211 ) + { + /* Return the inexact match lines to the sparent process */ + while( line[0] != '.' ) + { + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-11"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + /* Send the line to the parent */ + cdinfo.cddbd_stat = CDDBD_INEX_LINE; + strncpy( cdinfo.line, line, 254 ); + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-11a"); + break; + } + } + + /* We are finished with the server */ + close_cddbd( cddbd_fd ); + break; + } + + /* Exact match, get the category ?? and discid ?? */ + if( code == 200 ) + { + /* Tell the parent that we got a match */ + cdinfo.cddbd_stat = CDDBD_MATCH_OK; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-11a"); + break; + } + + /* Get the category (code has already placed a null in line) */ + p = strtok( NULL, " \n" ); + if( cdinfo.category == NULL ) + cdinfo.category = g_string_new( p ); + else + cdinfo.category = g_string_assign( cdinfo.category, p ); + +#ifdef DEBUG3 + g_print("category = %s\n", cdinfo.category->str ); +#endif + /* We could also get the discid and title here... */ + } + + + /* Send a read command to the server */ + sprintf( line, "cddb read %s %08lx\n", cdinfo.category->str, cdinfo.discid ); + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-12"); + break; + } + break; + } + + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-13"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 210 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-14"); + break; + } + break; + } + + /* + Get the database file from the server. + Write the file into a temporary file to be read by cddb_read + */ + if( ( tmpfile = tmpnam( NULL ) ) == NULL ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_TMPF_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-15"); + break; + } + break; + } + + if( ( fp = fopen( tmpfile, "wb" ) ) == NULL ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_FOPEN_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-16"); + break; + } + break; + } + + /* Tell the parent we are reading the database entry */ + cdinfo.cddbd_stat = CDDBD_ENTRY_OK; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-14a"); + break; + } + + while( line[0] != '.' ) + { + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-17"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + /* Strip trailing CR -- kludge, may not be there... */ + line[strlen(line)-2] = 0; + fprintf(fp, "%s\n", line); + } + + fclose( fp ); + + /* We are finished with the server */ + close_cddbd( cddbd_fd ); + + + /* Read the file into the cdinfo structure, and write it to its + final location in the local database. + */ + if( read_cddb_file( tmpfile, &cdinfo ) == 0 ) + { + /* Make sure it is saved with our discid! */ + cdinfo.discid = cddb_discid( &cdinfo ); + + if( write_cddb( &cdinfo, 1 ) == 0 ) + cdinfo.cddbd_stat = CDDBD_DONE_OK; + else + cdinfo.cddbd_stat = CDDBD_DONE_ERR; + } else { + cdinfo.cddbd_stat = CDDBD_DONE_ERR; + } + +#ifdef DEBUG3 + g_print("category = %s\n", cdinfo.category->str ); +#endif + + /* Send the new structure back to the parent process */ + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-18"); + break; + } + + /* Delete the temporary file */ +#ifdef DEBUG1 + g_print( "tmpfile=%s\n", tmpfile ); +#else + unlink( tmpfile ); +#endif + + break; + + /* Get the MOTD from the current server */ + case DB_MOTD : + if( (cddbd_fd = open_cddbd( cdinfo.server, cdinfo.port )) < 0 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the connection failed */ + cdinfo.cddbd_stat = CDDBD_OPEN_ERR; + sprintf( cdinfo.line, "err=%d", cddbd_fd ); + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-1"); + break; + } + break; + } + + /* Read the opening banner from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-3"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 201 ) + { + close_cddbd( cddbd_fd ); + /* Tell the parent the connect failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-4"); + break; + } + break; + } + + /* Identify ourself to the server */ + sprintf( line, "cddb hello %s %s XfreeCD %s\n", getenv("USER"), + getenv("HOSTNAME"), + VERSION ); + +#ifdef DEBUG1 + g_print("%s", line ); +#endif + + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-5"); + break; + } + break; + } + + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-6"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 200 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-7"); + break; + } + break; + } + + /* Tell the server we want the MOTD */ + strcpy( line, "motd\n" ); + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-7"); + break; + } + break; + } + + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 210 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-7"); + break; + } + break; + } + + /* Tell the parent about the MOTD date and time */ + cdinfo.cddbd_stat = CDDBD_MOTD_LINE; + strncpy( cdinfo.line, line, 254 ); + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + + /* Read the MOTD one line at a time */ + while( line[0] != '.' ) + { + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + break; + } + +#ifdef DEBUG10 + g_print( "%s", line ); +#endif + + /* Send the line to the parent */ + cdinfo.cddbd_stat = CDDBD_MOTD_LINE; + strncpy( cdinfo.line, line, 254 ); + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + } + + close_cddbd( cddbd_fd ); + + break; + + /* + Read the list of sites from the server. + Only return sites that we can talk to (cddb, not html) + */ + case DB_SITES : + if( (cddbd_fd = open_cddbd( cdinfo.server, cdinfo.port )) < 0 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the connection failed */ + cdinfo.cddbd_stat = CDDBD_OPEN_ERR; + sprintf( cdinfo.line, "err=%d", cddbd_fd ); + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-1"); + break; + } + break; + } + + /* Read the opening banner from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-3"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 201 ) + { + close_cddbd( cddbd_fd ); + /* Tell the parent the connect failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-4"); + break; + } + break; + } + + /* Identify ourself to the server */ + sprintf( line, "cddb hello %s %s XfreeCD %s\n", getenv("USER"), + getenv("HOSTNAME"), + VERSION ); + +#ifdef DEBUG1 + g_print("%s", line ); +#endif + + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-5"); + break; + } + break; + } + + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-6"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 200 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-7"); + break; + } + break; + } + + /* Tell the server we want the MOTD */ + strcpy( line, "sites\n" ); + if( writen( cddbd_fd, line, strlen( line ) ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the write failed */ + cdinfo.cddbd_stat = CDDBD_WRITE_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-7"); + break; + } + break; + } + + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + break; + } + +#ifdef DEBUG1 + g_print( "%s", line ); +#endif + + strncpy( cdinfo.line, line, 254 ); + code = cddbd_code( line ); + if( code > 210 ) + { + close_cddbd( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = code; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-7"); + break; + } + break; + } + + /* Read the MOTD one line at a time */ + while( line[0] != '.' ) + { + /* Get the response from the server */ + if( readline( cddbd_fd, line, 255 ) < 0 ) + { + close( cddbd_fd ); + + /* Tell the parent the read failed */ + cdinfo.cddbd_stat = CDDBD_READ_ERR; + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + break; + } + +#ifdef DEBUG10 + g_print( "%s", line ); +#endif + + /* + Here we should check the protocol level and parse the + response and only return sites that we can talk to. + + For the moment, just return the lines to the parent + */ + + /* Send the line to the parent */ + cdinfo.cddbd_stat = CDDBD_SITE_LINE; + strncpy( cdinfo.line, line, 254 ); + if( write( control_fd, &cdinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror("cddbd write error-8"); + break; + } + } + + close_cddbd( cddbd_fd ); + break; + + + case DB_QUIT : + return(0); + break; + } + } + return(0); +} diff --git a/cddbd.h b/cddbd.h @@ -0,0 +1,37 @@ +/* ------------------------------------------------------------------------ + cddbd include file for XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + ------------------------------------------------------------------------ */ +#define DB_DIAG 0x00 +#define DB_READ 0x01 +#define DB_QUIT 0x02 +#define DB_MOTD 0x03 +#define DB_SITES 0x04 +#define DB_WRITE 0x05 + +#define CDDBD_DONE_OK 0x00 +#define CDDBD_OPEN_ERR 0x01 +#define CDDBD_OPEN_OK 0x02 +#define CDDBD_READ_ERR 0x03 +#define CDDBD_WRITE_ERR 0x04 +#define CDDBD_TMPF_ERR 0x05 +#define CDDBD_FOPEN_ERR 0x06 +#define CDDBD_DONE_ERR 0x07 +#define CDDBD_MATCH_OK 0x08 +#define CDDBD_ENTRY_OK 0x09 +#define CDDBD_MOTD_LINE 0x0A +#define CDDBD_SITE_LINE 0x0B +#define CDDBD_INEX_LINE 0x0C +#define CDDBD_MAX 0x10 + + +int start_cddbd( int * ); + +int readn( register int, register char *, register int ); +int writen( register int, register char *, register int ); +int readline( register int, register char *, register int ); + diff --git a/child_sync.c b/child_sync.c @@ -0,0 +1,66 @@ +/* ----------------------------------------------------------------------- + child process synchronization functions + + part of XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + ==========================[ HISTORY ]================================== + 05/09/98 Moved these functions into this seperate file + + ----------------------------------------------------------------------- */ +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + + + +/* + Synchronize with the parent process. Wait until we receive a 'P' + from the parent. Send a 'C' to the parent in response + + Return a 0 if all went ok + Return a -1 if something went wrong +*/ +int parent_sync( int fd ) +{ + char c; + + if( read( fd, &c, 1 ) != 1 ) + return(-1); + + if( write( fd, "C", 1 ) != 1 ) + return(-1); + + return(0); +} + + + +/* + Synchronize with the child process. Send a 'P' to the child and wait + until a 'C' is received back. + + Return a 0 if all went ok + Return a -1 if something went wrong +*/ +int child_sync( int fd ) +{ + char c; + + if( write( fd, "P", 1 ) != 1 ) + return(-1); + + if( read( fd, &c, 1 ) != 1 ) + return(-1); + + if( c != 'C' ) + return(-1); + + return(0); +} diff --git a/child_sync.h b/child_sync.h @@ -0,0 +1,10 @@ +/* ------------------------------------------------------------------------ + child_sync include file for XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + ------------------------------------------------------------------------ */ +int parent_sync( int fd ); +int child_sync( int fd ); diff --git a/xfreecd.c b/xfreecd.c @@ -0,0 +1,5293 @@ +/* --------------------------------------------------------------------- + + XfreeCD v0.7.8 + + Copyright (C) 1998 Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + 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. + + ============================[ HISTORY ]============================== + 12/02/98 Tracking down the crash on CDDB retrieveal bug that people + have been reporting. I've finally duplicated it myself + and narrowed it down to the code after printing the string + "Got the new data ok" and the call to local_cddb(); + My theory is that display.plabel or display.progress don't + get set to a NULL when deleted, so my checks fail and + it tries to write to already freed memory. + Removed the progress update right before destroying the + progress box, no point if its going to get deleted! + I cannot be 100% positive, but I think this has fixed the + recall problem. Needs testing. + + Another bug. If the progress box is killed, it never opens + again until the program is restarted. Fix this in next + version. + + + 07/05/98 Fixed intermittant bug with recalling CD info. There was + a spare strcat(tmpstr) in the request loop of offsets! + Depending on the state of memory this could really hose + the requests. + + 06/26/98 Fixing Revision # for original submissions. Store them + locally as #0 so that the first send to the server will + increment it to #1 and the server will get #1. + Also added the VERSION number to the makefile to make + changing the version easier. + + 06/22/98 I just noticed a problem. The Length of track #1 is wrong! + Seems to be stuck at 20:36. cd_control.c was waiting until + the track was at #2 before calculating the length. FIXED. + + 06/20/98 TODO + 1. Fix EXT problems. + FIXED. + 2. Reread spec on blank tracks. It refused 'Track 6' + I shouldn't save any default strings to disk or send + them to the database. Only show them when updating + the clist. DONE. Sends a blank ttitle if none is + entered. + + 3. Made change, but edit doesn't work and it complains + about lots of g_strings != NULL (means ==) that need + to be fixed (probably in the edit an edit copy). Make + sure the (blank) placeholders are not copied over unless + they are edited. + Writing of blank tracks doesn't work when the user has + deleted everything since it holds a string of zero + length. + FIXED. Check the length for 0. + + 4. If the CD is paused when XfreeCD is run it doesn't + show the current track in the display. FIXED. + + 5. If the CD is paused when XfreeCD is run and you show + the track names, it is blank. The database has not + been read yet. FIXED. + + 6. Main Tracklist display is updated every second... + This is because some of the CDDB entries have a revision + of -1. I convert these into revision 1 now. + + 06/19/98 Finishing up the extended data support. Adding free_cdinfo + to the appropriate places. Need to make sure its only called + when its needed and not in the update loop. + Changed Cancel button in edit window to Close + + Shit. Nov I've broken it and I don't know how. Well, then + I'll just break it more. Changing all string usage to + dynamically allocated GString * from gtk. + + Whew! Okay, I've converted all the static string storage + over to GString usage. It appears to be working okay for + the moment. Now to stress test it with all the CDDB + requirements. + + Testing and making submissions to CDDB test server. + 1. Inexact doesn't save to disk with my ID, it saves it + with the downloaded id (because I canged the way it + is saved after being received!). Change in cddbd.c + so it save to local, reads it, changes discid and + saves it again <ICK>. FIXED. + + 2. There is a problem when reading extended info. It + is writing a blank EXTD and EXT0 then another EXT0 + and then up to the end-1 tracks. Fix it tomorrow. + FIXED. 1 - off error. + + 06/16/98 Things that need fixing: + 1. 99 track CD isn't downloaded, causes an error and + it retries the server endlessly. + The track array in cdinfo was 1 short! I should use + 0-98 instead of 1-99 for all access. + FIXED. + + 2. Server error caused by not sending all the track offsets + (buffer overflow). Fixed by sending it the offsets one + at a time. FIXED. + + 3. Edit window coredumps when trying to edit 99 track + NIN-broken. FIXED. display structure had a [99] in it. + + 4. Main tracklist window flickers every second... + + 5. Need to process extended data, save to local database, + resend it to server when tracks change. Don't need + to edit it or display it (most CDs don't use it at all). + Reading works now. + a. Need to write it back to disk. DONE. + b. Need to free the used memory when a CD is ejected + DONE. + + 6. Need to read the Revision # correctly + DONE. + + 06/06/98 Fixed problem with changing categories. Once the new + category has successfully been written it erases the + old category. + While it is waiting to get new data from the server + it is displaying the old track data. Needs to be erased + from the cdinfo structure as well as the display. + FIXED. + I would like to make long title in the track window + wrap automatically, but the GTK label doesn't have + wrapping, so too bad. + Adding a Send to Server option. This just uses the + local mail binary (must be in the path). This should + work for everyone. + Works, Tested successfully. + Added support for multiple TITLEx lines. Tested, and it + works fine. Sent 5 test of long title and long track + names to the cddb-test server. + I just noticed a bug with the clist edit window. It + is resetting the vertical scroll bar when you select + a track that has to be scrolled down to. Probably + because I reload the clist when the trackname is + edited. FIXED. + + 06/05/98 Trying to tidy up all the loose ends. + GTK cannot figure out the geometry of the window before + it is actually showing, so the negative geometry with + titlebar doean't work right. Hardcoded the window size + to 137x60 + + 06/02/98 Adding display of full string returned by server error. + Fixed close error, I was returning the wrong thing from + delete_event. + + 06/01/98 Adding seperate Window Class names to the different + windows so that the user can individually control the + title bar, move/resize, etc. As suggested by Michael + J. Hammel + + 05/31/98 Adding support for -geometry, apparently this has not + been added to GTK+ itself yet, so I have to do it + myself, using XParseGeometry. Works Great! + When geometry is passed a '- it needs to be relative + to the other corner of the window, not the upper + left. Fixed. + + 05/28/98 Bug with eject on exit. It needs to send the current + state to the cd_control process when it reads the + config file. FIXED. + Need to add dropdown list for categories in edit. DONE. + + 05/27/98 More finishing touches <G>. + Added selection of next track in the track window when + it goes to the next track. Looks nicer. + Fixed a bug with multiple DTITLE lines. + + NEED TO DO: + x 1. Build local cddb directories sometime (either under + the setup menu, or the first time it writes, + or at compile time). The best would be when it + tries to write to a non-existant directory, create + the structure needed. + Works. It creates only the category directory + needed and the root cddb directory if it doesn't + exist yet. This way the categories aren't limited + to a static list. + x 2. Editing track names and saving to local database. + x 3. Sending edited track info to the database, or just + a new discid for the CD. Requires email. Use the + mail binary, but allow users to spec. it? + x 4. Allow user to select local .cddb support or internet + so they can build their own database in the cddb + format even if they have no inet connection. + 5. Clean up code. Add comments. + There is a bunch of duplicated code that can be + put into a subroutine with maybe 1 parameter + passed to it. The clist updating routines are + one. + x 6. Convert my usage of printf to g_print + + 05/26/98 Finishing touches. Got the text window to work, thanks + to Owen. I had to add it to the notebook before + it is realized, otherwise it doesn't know who its + parent is (this is because text windows are changes as + you add to them). + Changed to main window to be a POPUP so that it has no + title bars. Keeps people from resizing it too! + + 05/25/98 Problem with using device from main process -- we only + send 2 bytes to the cd_control process!! How am I going + to pass the new device? A 2 stage send? With the second + part being the new device? + + Added CD_SET_DEVICE to cd_control. + Adding sending of it to read_config. + Switching cd device is now working! + + Adding clear of display.tclist to no disc display points + + + 05/24/98 Adding support for inexact matches. CDDBD_INEX_LINE. + Inexact matching works!!! It saves it as the locally + calculated discid (recalculated just before the save). + + x 1. Need to update the track list if its already open + when the new data is downloaded from the server or + read from disk. + x 2. Clear the track list and title when nodisc info is + available (on change, use Track #, etc). + x 3. Click on a track in the track list to jump to + that track directly. + no 5. CD changer support... + x 6. Volume update is slow, needs to be called on click. + + I've decided not to include changer support. Too hard to + integrate into the current GUI. And there probably isn't + a great need. + + 05/23/98 The Help/Setup dialog is partially working. It still + complains when making the help text box, why? + The startup sequence isn't working right. Not playing + after closing the tray, or even when already closed. + + I also don't like the startup pause for checking for the + current status. That should be handled by a startup + state machine in the status callback. May help solve the + startup play problem. Fixed. Status returned was NO_STATUS + which I was checking for some reason. + + Software selectable eject on exit with no play is now + working correctly. + + Server refresh is working as far as updating the internal + list but the list in the setup dialog isn't working. Also + changes to cddb and device are cross-polinated! It is + happening at the realloc in the device_edit and cddb_edit + routines. Pointer copied over somehow? realloc wrong? + typical bug. Assignment to wrong place. + + Some of th things left to do: + x 1. refresh server listing after update from internet + while dialog box is still open. + x 2. Status box showing the info while connected to the + server. + x 3. Implement Inexact match + x a. receive list of discids and titles from the server + Add a new command to cddbd return value + x b. Show a dialog box with the list of titles and have + the user pick one or Cancel. + x c. re-submit the query using the user selected discid + x 4. Saving to disk saves the wrong revision #, -1 + o 5. Popup window when display is left clicked that shows + and allows editing of title and tracks. + showing title and track is working. + 6. Need to switch to using config.device and telling the + cd_control process about it when we change it. + 7. Submitting a new disc to the database (via email?) + + + 05/22/98 Need to finish the help/setup menu window. + x Device (defaults to /dev/cdrom) + x Server List + x cddb support + no changer support + x Eject at end? + x Startup behavior + + + Since I have the WM set to no titles and bars it makes it + hard to manipulate the setup screen! How about if I were + to extend the cdplayers window up or down (how to tell?) + and include the setup/server/tracklist data that way? + How do you delete things once you've packed them? Or can + you? + + + 05/21/98 Right click on display window and dragging now works + fine for moving the window around. + + + 05/20/98 Blink isn't working. Fixed. Multiple places calling + update_display. FIXED. + Also need to add window dragging if right clicked in + the display area. + Need to add parallel tracklist window popup if right + click on either of the track digits (or area). + + At startup we need to know the current state of the + CD before we go off and send a play command to it. FIXED. + When it has to close the door to play it doesn't start + playing automatically. + When it tries to play with no CD in the drive it doesn't + recover when you insert a disc and hit play. + Because fd_cd is < 0. Check for this. + + There is a problem with setting the play button graphic + and state at the point where it is sent to control. + it it fails then the state/button is wrong! But if I + wait until it succeeds/fails then response time is + greatly delayed... Added code to make sure the button + state matched the display state and to change it if it + differs. Seems to work nicely. Shows playup until it + fails and then switches to stopup. WORKS WELL. + + Eject doesn't work with status doing an init. Do an + initial init when cd_control is started. FIXED. + + Dragging now sortof works. It loses track of the cursor + if its moved too fast, and won't ungrab (ick!) + + 05/19/98 Read/Write config now works, needs to still be tested + with multiple servers though. + + 05/18/98 Adding configuration writing and reading + + 05/17/98 Found a chunck of startup code that was double-copied, + The player actually plays, ejects, etc. OK. + The volume display needs to update immediatly as does + the time display update when the key is pressed. Eject + should eject even when no cd has been opened. + At startup we should? + Play automatically + Show no disc and do nothing until play pressed + Show total # of tracks and time remaining + All of these should be user selectable. + When a CD is opened for the first time (no discid stored + in cdinfo) we should query the database. + Clicking (right probably) on the display should pop up a + list of the tracks (editable). + There are some == NULL problems that need to be taken care + at starup, probably due to not realizing widgets first? + Blink isn't working right (doesn't blink) + Remaining on track counts up, not down! + Help/Setup dialog needs to be nicer looking, black to match + the look of the main box (how do I change the colors of + the dialogs?) + + 05/16/98 Finishing up the cd control, adding get motd and get + server list from cddb.cddb.com + I really should add protocol support, but really, it + works fine like this... + OK, it 'looks like' the low level and server support is + now working okay. The code is a bit hard to read and + could probably use some macroing or other cleanups, + but I'll save that for later. + + Now to start adding the GTK+ GUI stuff again and integrate + it with the data returning from the server and the CD + control process. + + Well, the UI is sort of running. It complains a little, + and puts two 'NO DISC' pixmaps in the window, but it + starts at least! + + 05/09/98 Added local cddb database support. It successfully reads + the disc info from the database. + + 05/03/98 Restarted this whole project from the ground up. I am + writing the CD control and cddb support code first, + and then adding the GUI interface. + + cd_control and cddb will be seperate processes forked + from the main process at startup. + + -------------------------------------------------------------------- */ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include "cd_control.h" +#include "cddbd.h" +#include "cddb.h" +#include "xfreecd.h" +#include "xpm_button.h" + + +/* Include all the bitmaps used (in xpm format) */ +#include "bitmaps/ffup.xpm" +#include "bitmaps/ffdn.xpm" +#include "bitmaps/rewup.xpm" +#include "bitmaps/rewdn.xpm" +#include "bitmaps/sfwddn.xpm" +#include "bitmaps/srevdn.xpm" +#include "bitmaps/stopup.xpm" +#include "bitmaps/playup.xpm" +#include "bitmaps/playdn.xpm" +#include "bitmaps/pauseup.xpm" +#include "bitmaps/ejup.xpm" +#include "bitmaps/ejdn.xpm" +#include "bitmaps/exitup.xpm" +#include "bitmaps/exitdn.xpm" +#include "bitmaps/helpup.xpm" +#include "bitmaps/helpdn.xpm" +#include "bitmaps/rptup.xpm" +#include "bitmaps/rptdn.xpm" +#include "bitmaps/rptupact.xpm" +#include "bitmaps/volup.xpm" +#include "bitmaps/voldn.xpm" +#include "bitmaps/null.xpm" +#include "bitmaps/nodisc.xpm" +#include "bitmaps/plstrkup.xpm" +#include "bitmaps/plstrkdn.xpm" +#include "bitmaps/mnstrkup.xpm" +#include "bitmaps/mnstrkdn.xpm" +#include "bitmaps/plscdup.xpm" +#include "bitmaps/plscddn.xpm" +#include "bitmaps/mnscdup.xpm" +#include "bitmaps/mnscddn.xpm" +#include "bitmaps/minus.xpm" +#include "bitmaps/bar.xpm" +#include "bitmaps/redbar.xpm" +#include "bitmaps/nobar.xpm" +#include "bitmaps/a0.xpm" +#include "bitmaps/a1.xpm" +#include "bitmaps/a2.xpm" +#include "bitmaps/a3.xpm" +#include "bitmaps/a4.xpm" +#include "bitmaps/a5.xpm" +#include "bitmaps/a6.xpm" +#include "bitmaps/a7.xpm" +#include "bitmaps/a8.xpm" +#include "bitmaps/a9.xpm" +#include "bitmaps/an.xpm" +#include "bitmaps/b0.xpm" +#include "bitmaps/b1.xpm" +#include "bitmaps/b2.xpm" +#include "bitmaps/b3.xpm" +#include "bitmaps/b4.xpm" +#include "bitmaps/b5.xpm" +#include "bitmaps/b6.xpm" +#include "bitmaps/b7.xpm" +#include "bitmaps/b8.xpm" +#include "bitmaps/b9.xpm" +#include "bitmaps/bn.xpm" + + +#undef DEBUG1 +#undef DEBUG2 +#undef DEBUG3 +#undef DEBUG4 +#undef DEBUG5 +#undef DEBUG6 +#undef DEBUG7 +#undef DEBUG8 +#undef DEBUG9 +#undef MAIL_DEBUG + +#define CDROM_NODISC 0 +#define CDROM_PLAYING 1 +#define CDROM_PAUSED 2 + +#define TRACK_ELAPSED 0 +#define TRACK_REMAIN 1 +#define CD_ELAPSED 2 +#define CD_REMAIN 3 + + +#define HELP_TEXT( x ) gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, x, -1) +#define COLOR_TEXT( x, y ) gtk_text_insert (GTK_TEXT (text), NULL, y, NULL, x, -1) + +int read_config( struct CONFIG * ); +int run_gtk(); +void free_config( struct CONFIG * ); +gint delete_event(GtkWidget *, gpointer); +void destroy (GtkWidget *, gpointer); +void cd_fd_read( gpointer, gint, GdkInputCondition); +void cddbd_fd_read( gpointer, gint, GdkInputCondition); +void ff_press(GtkWidget *, GdkEventButton *); +void ff_release(GtkWidget *, GdkEventButton *); +void rew_press(GtkWidget *, GdkEventButton *); +void rew_release(GtkWidget *, GdkEventButton *); +void play_press(GtkWidget *, GdkEventButton *); +void play_release(GtkWidget *, GdkEventButton *); +void eject_press(GtkWidget *, GdkEventButton *); +void eject_release(GtkWidget *, GdkEventButton *); +void ex_press(GtkWidget *, GdkEventButton *); +void ex_release(GtkWidget *, GdkEventButton *); +void help_press(GtkWidget *, GdkEventButton *); +void help_release(GtkWidget *, GdkEventButton *); +void tdisp_press(GtkWidget *, GdkEventButton *); +void tdisp_release(GtkWidget *, GdkEventButton *); +void rpt_press(GtkWidget *, GdkEventButton *); +void rpt_release(GtkWidget *, GdkEventButton *); +void vol_press(GtkWidget *, GdkEventButton *); +void vol_release(GtkWidget *, GdkEventButton *); +void set_vol( int amount ); +static int expose_display( GtkWidget *, GdkEventExpose *); +gint update_cdrom( gpointer ); +void play_next(); +void play_previous(); +void pause_cdrom(); +void resume_cdrom(); +void play_track(int); +void update_display(); +void stop_cdrom(); +void eject_cdrom(); +int cdrom_status(); +int write_config( struct CONFIG * ); +static void display_released (GtkWidget *); +static void display_motion (GtkWidget *, GdkEventMotion *); +static void display_pressed (GtkWidget *, GdkEventButton *); +void wait_status(); +gint show_tracks(); +void set_eject( int ); + + +typedef struct _cursoroffset {gint x,y;} CursorOffset; + +/* Global Variables and structures */ +struct CDINFO cdinfo; +struct CONFIG config; + +char cmnd[2]; +int cd_pid, cd_fd, /* Communications with the CD control */ + cddbd_pid, cddbd_fd; /* Communications with cd database */ +gint gdk_cd_fd, + gdk_cddbd_fd; + + +static GdkWindow *root_win = NULL; + + +struct _pbutton ff, /* Fast Forward button */ + rew, /* Rewind */ + play, /* Play */ + vol, /* Volume control */ + eject, /* Elect */ + tdisp, /* Time Display */ + rpt, /* Repeat */ + ex, /* Exit button */ + help; /* Help */ + +/* Display pixmaps and current disc status */ +struct _display +{ + GtkWidget *main_window; /* The main window */ + GtkWidget *vbox; /* Vbox holding everything */ + GtkWidget *wid; /* Widget for placing pixmaps */ + GtkWidget *progress; /* CDDBD progress dialog window */ + GtkWidget *plabel; /* Progress dialog label */ + GtkWidget *twindow; /* Track Window pointer */ + GtkWidget *tclist; /* List of tracks */ + GtkWidget *ttitle; /* Track list title widget */ + GtkWidget *tewindow; /* Track Edit Window */ + GtkWidget *teentry; /* Track Entry Window */ + GtkWidget *teclist; /* Clist for Track Edit */ + GtkWidget *cb; /* ComboBox list of Servers */ + GdkPixmap *image; /* image to paint onto */ + GdkPixmap *null_pixmap; /* Blank with : */ + GdkBitmap *null_mask; + GdkPixmap *nodisc_pixmap; /* NO DISC */ + GdkBitmap *nodisc_mask; + GdkPixmap *minus_pixmap; /* Minus sign */ + GdkBitmap *minus_mask; + GdkPixmap *playup_pixmap; /* Play in white */ + GdkBitmap *playup_mask; + GdkPixmap *playdn_pixmap; + GdkBitmap *playdn_mask; + GdkPixmap *pauseup_pixmap; /* Pause bars in white */ + GdkBitmap *pauseup_mask; + GdkPixmap *stopup_pixmap; /* play and pause in gray */ + GdkBitmap *stopup_mask; + GdkPixmap *sfwddn_pixmap; /* Seek forward down button */ + GdkBitmap *sfwddn_mask; + GdkPixmap *srevdn_pixmap; /* Seek reverse down button */ + GdkBitmap *srevdn_mask; + GdkPixmap *rptupact_pixmap; /* repeat active (white) */ + GdkBitmap *rptupact_mask; + GdkPixmap *plstrkup_pixmap; /* Elapsed track time */ + GdkBitmap *plstrkup_mask; + GdkPixmap *plstrkdn_pixmap; + GdkBitmap *plstrkdn_mask; + GdkPixmap *mnstrkup_pixmap; /* Remaining track time */ + GdkBitmap *mnstrkup_mask; + GdkPixmap *mnstrkdn_pixmap; + GdkBitmap *mnstrkdn_mask; + GdkPixmap *plscdup_pixmap; /* Elapsed CD time */ + GdkBitmap *plscdup_mask; + GdkPixmap *plscddn_pixmap; + GdkBitmap *plscddn_mask; + GdkPixmap *mnscdup_pixmap; /* Remaining CD time */ + GdkBitmap *mnscdup_mask; + GdkPixmap *mnscddn_pixmap; + GdkBitmap *mnscddn_mask; + GdkPixmap *bar_pixmap; /* Volume Bargraph */ + GdkBitmap *bar_mask; + GdkPixmap *redbar_pixmap; /* Volume Bargraph */ + GdkBitmap *redbar_mask; + GdkPixmap *nobar_pixmap; /* Volume Bargraph */ + GdkBitmap *nobar_mask; + + GdkPixmap *a_pixmap[11]; /* Large digits */ + GdkBitmap *a_mask[11]; + GdkPixmap *b_pixmap[11]; /* Small Digits */ + GdkBitmap *b_mask[11]; + + GString *tmp_category; /* New Category entry */ + GString *tmp_title; /* Title storage for edit_tracks*/ + GString *tmp_track[99]; /* Song names for editing */ + int tmp_row; /* Current row in tmp_track */ + + short startup; /* Startup State machine */ + short cddb_lock; /* Lock cddb access while busy */ + int status; /* Current player status + 0 = no disc in drive + 1 = stopped + 2 = playing + 3 = paused + */ + int playbtn; /* State of play button, same as + above (use CDROM_ equates) + */ + int time; /* Time mode */ + int track, /* track # - 1 to end of CD */ + minute, + second; /* Info for the display */ + int repeat; /* Repeat status */ +} display; + + + +/* Signal handling code */ +static int caught_fatal_sig = 0; + +static void on_signal (int sig_num) +{ + if (caught_fatal_sig) +/* raise (sig_num);*/ + kill (getpid (), sig_num); + caught_fatal_sig = 1; + + switch (sig_num) + { + case SIGHUP: + g_print("sighup caught\n"); + gdk_exit(1); + break; + case SIGINT: + g_print("sigint caught\n"); + gdk_exit(1); + break; + case SIGQUIT: + g_print("sigquit caught\n"); + gdk_exit(1); + break; + case SIGABRT: + g_print("sigabrt caught\n"); + gdk_exit(1); + break; + case SIGBUS: + g_print("sigbus caught\n"); + destroy(NULL,NULL); + break; + case SIGSEGV: + g_print("sigsegv caught\n"); + destroy(NULL,NULL); + break; + case SIGPIPE: + g_print("sigpipe caught\n"); + gdk_exit(1); + break; + case SIGTERM: + g_print("sigterm caught\n"); + gdk_exit(1); + break; + case SIGFPE: + g_print("sigfpe caught\n"); + destroy(NULL,NULL); + break; + default: + g_print("unknown signal\n"); + destroy(NULL,NULL); + break; + } +} + +static void on_sig_child (int sig_num) +{ + int pid; + int status; + + while (1) + { + pid = waitpid (WAIT_ANY, &status, WNOHANG); + if (pid <= 0) + break; + } +} + + +/* ------------------------------------------------------------------------ + Where it all begins... + ------------------------------------------------------------------------ */ +int main( int argc, char *argv[] ) +{ + int x, + x_ret, + y_ret, + w_ret, + h_ret, + stat=0; + + bzero( &cdinfo, sizeof( struct CDINFO ) ); + + /* Start up the CD control process */ + if( ( cd_fd = start_cd_control( &cd_pid ) ) < 0 ) + { + perror("start_cd_control error"); + exit(-1); + } + + /* Start up the CDDBD control process */ + if( ( cddbd_fd = start_cddbd( &cddbd_pid ) ) < 0 ) + { + perror("start_cd_dbd error"); + exit(-1); + } + + /* Startup GTK */ + gtk_init (&argc, &argv); + + /* Tell gdk to watch the cd control and cddb pipes for reading */ + gdk_cd_fd = gdk_input_add( cd_fd, GDK_INPUT_READ, cd_fd_read, 0 ); + gdk_cddbd_fd = gdk_input_add( cddbd_fd, GDK_INPUT_READ, cddbd_fd_read, 0 ); + + /* Get the -geometry parameters */ + for( x = 0; x < argc; x++ ) + { + if( (strcasecmp( argv[x], "-geometry" ) == 0) || (strcasecmp( argv[x], "-geom" ) == 0) ) + { + if( argv[x+1] != NULL ) + { +#ifdef DEBUG7 + g_print("Passing %s to XParseGeometry\n", argv[x+1]); +#endif + + stat = XParseGeometry( argv[x+1], &x_ret, &y_ret, &w_ret, &h_ret ); + +#ifdef DEBUG7 + g_print("%d = XParseGeometry( s, %d, %d, %d, %d )\n", + stat, x_ret, y_ret, w_ret, h_ret ); +#endif + } + } + } + + /* Handle some signals */ + signal (SIGHUP, on_signal); + signal (SIGINT, on_signal); + signal (SIGQUIT, on_signal); + signal (SIGABRT, on_signal); + signal (SIGBUS, on_signal); + signal (SIGSEGV, on_signal); + signal (SIGPIPE, on_signal); + signal (SIGTERM, on_signal); + signal (SIGFPE, on_signal); + + /* Handle child exits */ + signal (SIGCHLD, on_sig_child); + + run_gtk( stat, x_ret, y_ret ); + + gdk_input_remove( gdk_cd_fd ); + gdk_input_remove( gdk_cddbd_fd ); + + /* Tell cd_control to quit */ + cmnd[0] = CD_QUIT; + cmnd[1] = 0; + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + close( cd_fd ); + exit(-1); + } + + /* Tell cddbd to quit */ + cdinfo.cddbd_cmnd = DB_QUIT; + if( write( cddbd_fd, &cdinfo, sizeof( struct CDINFO ) ) < 0 ) + { + perror("write to cddbd error"); + close( cd_fd ); + close( cddbd_fd ); + exit(-1); + } + + close( cd_fd ); + close( cddbd_fd ); + return(0); +} + + + +/* ----- subroutines follow ------ */ + + +void send_device() +{ + char buffer[80]; + + /* Send the CD device to the cd_control process */ + buffer[0] = CD_SET_DEVICE; + buffer[1] = 0; + if( write( cd_fd, buffer, 2 ) < 0 ) + { + perror("write to cd_control error - 1a"); + } + + sprintf( buffer, "%s\n", config.device ); + if( write( cd_fd, buffer, strlen(buffer) ) < 0 ) + { + perror("write to cd_control error - 1b"); + } +} + + +/* ------------------------------------------------------------------------ + Read the configuration file from $HOME/.xfreecdrc + + Return -2 if a malloc fails + ------------------------------------------------------------------------ */ +int read_config( struct CONFIG *config ) +{ + FILE *fp; + char fname[1024], + line[80], + *p; + struct SITE *sp, *sp2; + + if( ( p = getenv( "HOME" ) ) == NULL ) + { + g_print("Cannot find HOME enviornmental variable\n"); + return(-1); + } + + strncpy( fname, p, 1023 ); + if( fname[strlen(fname)-1] != '/' ) + strcat( fname, "/" ); + strcat( fname, ".xfreecdrc" ); + + if( ( fp = fopen( fname, "rb" ) ) == NULL ) + { + /* Setup reasonable defaults */ + + /* Setup for the default device (/dev/cdrom) */ + if( ( config->device = (char *) malloc( strlen(DEFAULT_DEVICE)+1 ) ) == NULL ) + { + return(-2); + } + strcpy( config->device, DEFAULT_DEVICE ); + + /* Get some memory for the path to the local database. + By default I put this in the user's home directory ~/.cddb + */ + if( ( config->local_cddb = (char *) malloc( strlen(DEFAULT_CDDB_PATH)+1 ) ) == NULL ) + { + return(-2); + } + strcpy( config->local_cddb, DEFAULT_CDDB_PATH ); + strcpy( cdinfo.local_cddb, config->local_cddb ); + + /* Get some memory for the cddbd email address */ + if( ( config->to_cddbd = (char *) malloc( strlen(DEFAULT_TO_CDDBD)+1 ) ) == NULL ) + { + return(-2); + } + strcpy( config->to_cddbd, DEFAULT_TO_CDDBD ); + + /* Get some memory for the SITE */ + if( ( config->server = (struct SITE *) malloc( sizeof(struct SITE) ) ) == NULL ) + { + return(-2); + } + + bzero( config->server, sizeof(struct SITE) ); + + /* Fill in the site with cddb.cddb.com */ + if( ( config->server->name = (char *) malloc( strlen(DEFAULT_SERVER)+1 ) ) == NULL ) + { + return(-2); + } + strcpy( config->server->name, DEFAULT_SERVER ); + config->server->port = 888; + config->server->next = NULL; + + /* Set current server to the default */ + if( ( config->current = (char *) malloc( strlen(DEFAULT_SERVER)+1 ) ) == NULL ) + { + return(-2); + } + strcpy( config->current, DEFAULT_SERVER ); + + config->done_eject = 0; /* Eject when done playing */ + config->exit_eject = 0; /* Eject on exit when not playing */ + config->startup = 1; /* Play at startup */ + config->cddb = 0; + config->changer = 0; + config->saved = 0; /* Needs to be saved */ + + /* Write this as the default */ + return( write_config( config ) ); + } + + /* Process the lines in the file */ + while( fgets( line, 80, fp ) != NULL ) + { + if( (line[0] == '#') || (line[0] == '\n') ) + continue; + + p = strtok( line, "= \n" ); + if( strcmp( p, "DEVICE" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + /* Get some memory for the device */ + if( ( config->device = (char *) malloc( strlen(p)+1 ) ) == NULL ) + { + fclose( fp ); + return(-2); + } + strcpy( config->device, p ); + + continue; + } + + if( strcmp( p, "LOCAL_CDDB" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + /* Get some memory for the path to the local database. + */ + if( ( config->local_cddb = (char *) malloc( strlen(p)+1 ) ) == NULL ) + { + fclose( fp ); + return(-2); + } + strcpy( config->local_cddb, p ); + strcpy( cdinfo.local_cddb, p ); + continue; + } + + if( strcmp( p, "TO_CDDBD" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + /* Get some memory for the path to the local database. + */ + if( ( config->to_cddbd = (char *) malloc( strlen(p)+1 ) ) == NULL ) + { + fclose( fp ); + return(-2); + } + strcpy( config->to_cddbd, p ); + continue; + } + + if( strcmp( p, "SERVER" ) == 0 ) + { + p = strtok( NULL, "=: \n" ); + + /* Reserve some space for this server, add it to the end of the list */ + if( ( sp = (struct SITE *) malloc( sizeof(struct SITE) ) ) == NULL ) + { + return(-2); + } + bzero( sp, sizeof(struct SITE) ); + + /* Reserve space for the name */ + if( ( sp->name = (char *) malloc( strlen(p)+1 ) ) == NULL ) + { + return(-2); + } + strcpy( sp->name, p ); + + p = strtok( NULL, "=: \n" ); + sp->port = atoi(p); + sp->next = NULL; + + /* Is it the first in the list? */ + if( config->server == NULL ) + { + /* Yep, First in the list */ + config->server = sp; + } else { + /* Walk to the end of the list (no cuts!!) */ + sp2 = config->server; + while( sp2->next != NULL ) + { + sp2 = sp2->next; + } + + /* Add the new site to the end of the list */ + sp2->next = sp; + } + + continue; + } + + if( strcmp( p, "CURRENT" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + + /* Get some memory for the current server name */ + if( ( config->current = (char *) malloc( strlen(p)+1 ) ) == NULL ) + { + fclose( fp ); + return(-2); + } + strcpy( config->current, p ); + continue; + } + + if( strcmp( p, "DONE_EJECT" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + config->done_eject = atoi( p ); + continue; + } + + if( strcmp( p, "EXIT_EJECT" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + config->exit_eject = atoi( p ); + set_eject( config->exit_eject ); /* Tell the CD_CONTROL device about state */ + continue; + } + + if( strcmp( p, "STARTUP" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + config->startup = atoi( p ); + continue; + } + + if( strcmp( p, "CDDB" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + config->cddb = atoi( p ); + continue; + } + + if( strcmp( p, "CHANGER" ) == 0 ) + { + p = strtok( NULL, "= \n" ); + config->changer = atoi( p ); + continue; + } + + + } + fclose( fp ); + + + /* + I've added config->to_cddbd since last release, so if it wasn't read from the + rcfile give it a default value so people don't need to erase their old rcfile + */ + if( config->to_cddbd == NULL ) + { + if( ( config->to_cddbd = (char *) malloc( strlen( DEFAULT_TO_CDDBD ) + 1 ) ) == NULL ) + { + fclose( fp ); + return(-2); + } + strcpy( config->to_cddbd, DEFAULT_TO_CDDBD ); + } + + config->saved = 1; /* Just read it, same as saved file */ + + return 0; +} + + +/* ------------------------------------------------------------------------ + Write the configuration file to $HOME/.xfreecdrc + ------------------------------------------------------------------------ */ +int write_config( struct CONFIG *config ) +{ + FILE *fp; + char fname[1024], + *p; + struct SITE *sp; + + /* Already saved, no need to save it again */ + if( config->saved == 1 ) + return(0); + + if( ( p = getenv( "HOME" ) ) == NULL ) + { + g_print("Cannot find HOME enviornmental variable\n"); + return(-1); + } + + strncpy( fname, p, 1023 ); + if( fname[strlen(fname)-1] != '/' ) + strcat( fname, "/" ); + strcat( fname, ".xfreecdrc" ); + + if( ( fp = fopen( fname, "wb" ) ) == NULL ) + { + return(-2); + } + + fprintf( fp, "# XfreeCD v%s configuration file\n", VERSION ); + fprintf( fp, "#\n"); + fprintf( fp, "DEVICE=%s\n", config->device ); + fprintf( fp, "LOCAL_CDDB=%s\n", config->local_cddb ); + fprintf( fp, "TO_CDDBD=%s\n", config->to_cddbd ); + + /* Walk down the list of servers */ + sp = config->server; + while( sp != NULL ) + { + fprintf( fp, "SERVER=%s:%d\n", sp->name, sp->port); + sp = sp->next; + } + + fprintf( fp, "CURRENT=%s\n", config->current ); + fprintf( fp, "DONE_EJECT=%d\n", config->done_eject ); + fprintf( fp, "EXIT_EJECT=%d\n", config->exit_eject ); + fprintf( fp, "STARTUP=%d\n", config->startup ); + fprintf( fp, "CDDB=%d\n", config->cddb ); + fprintf( fp, "CHANGER=%d\n", config->changer ); + + fclose( fp ); + + config->saved = 1; /* config is now same as saved on disk */ + + return 0; +} + + + +/* ----------------------------------------------------------------------- + Free up the info used in the cdinfo structure + ----------------------------------------------------------------------- */ +void free_cdinfo() +{ + int x; + +#ifdef DEBUG8 + g_print("Freeing any used extended data\n" ); +#endif + + if( cdinfo.title != NULL ) + { + g_string_free( cdinfo.title, 1 ); + cdinfo.title = NULL; + } + + if( cdinfo.category != NULL ) + { + g_string_free( cdinfo.category, 1 ); + cdinfo.category = NULL; + } + + for( x = 0; x < 99; x++ ) + { + if( cdinfo.name[x] != NULL ) + { + g_string_free( cdinfo.name[x], 1 ); + cdinfo.name[x] = NULL; + } + } + + + if( cdinfo.extd != NULL ) + { + g_string_free( cdinfo.extd, 1 ); + cdinfo.extd = NULL; + } + + for( x = 0; x < 99; x++ ) + { + if( cdinfo.extt[x] != NULL ) + { + g_string_free( cdinfo.extt[x], 1 ); + cdinfo.extt[x] = NULL; + } + } + + /* Clean up the display's temporary storage */ + if( display.tmp_category != NULL ) + { + g_string_free( display.tmp_category, 1 ); + display.tmp_category = NULL; + } + + if( display.tmp_title != NULL ) + { + g_string_free( display.tmp_title, 1 ); + display.tmp_title = NULL; + } + + for( x = 0; x < 99; x++ ) + { + if( display.tmp_track[x] != NULL ) + { + g_string_free( display.tmp_track[x], 1 ); + display.tmp_track[x] = NULL; + } + } +} + + +/* ----------------------------------------------------------------------- + Free up any memory used by the config structure to store the paths + and site names. + ----------------------------------------------------------------------- */ +void free_config( struct CONFIG *config ) +{ + struct SITE *sp; + + /* Need to free up memory usage */ + free( config->local_cddb ); + free( config->device ); + free( config->to_cddbd ); + + /* Walk the server list, freeing up memory */ + while( config->server != NULL ) + { + sp = config->server; + config->server = config->server->next; + free( sp->name ); + free( sp ); + } + + /* Free up the dynamically allocated strings in cdinfo */ + free_cdinfo(); +} + + + +/* ----------------------------------------------------------------------- + Load the CD info from the local database or set defaults + ----------------------------------------------------------------------- */ +void local_cddb() +{ + +#ifdef DEBUG1 + g_print("Loading local Database\n"); +#endif + + /* No internet support, just try and read the local DB */ + if( read_cddb( &cdinfo ) < 0 ) + { + +#ifdef DEBUG1 + g_print("Not found on disk, defaulting\n"); +#endif + + /* Unknown title */ + if( cdinfo.title == NULL ) + cdinfo.title = g_string_new( "Unknown CD" ); + else + cdinfo.title = g_string_assign( cdinfo.title, "Unknown CD" ); + + if( cdinfo.category == NULL ) + cdinfo.category = g_string_new( "misc" ); + else + cdinfo.category = g_string_assign( cdinfo.category, "misc" ); + + /* Set a default revision, so they can edit the list */ + cdinfo.revision = 0; + } + +#ifdef DEBUG9 + g_print("local_cddb() revision = %d\n", cdinfo.revision ); +#endif + +} + + +/* ----------------------------------------------------------------------- + The Main GTK setup routine + ----------------------------------------------------------------------- */ +int run_gtk( int stat, int x_ret, int y_ret ) +{ + GtkWidget *window, + *button, + *hbox1, + *hbox2, + *table; + GtkTooltips *tips; + GtkStyle *style; + GdkColor tip_color; + GdkColormap *colormap; + gint timer; + CursorOffset *icon_pos; + int x_pos, + y_pos; + + bzero( &config, sizeof( struct CONFIG ) ); + bzero( &display, sizeof( struct _display ) ); + bzero( &cdinfo, sizeof( struct CDINFO ) ); + + cdinfo.revision = -1; /* Initalize the revision number */ + + /* Copyright info, version info */ + g_print("XfreeCD v%s\n", VERSION ); + g_print("Copyright 1998 by Brian C. Lane\n<http://www.tatoosh.com/nexus>\n\n"); + + root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + display.main_window = window; + gtk_container_border_width( GTK_CONTAINER( window ), 0 ); + + /* Give it a name */ + gtk_window_set_title (GTK_WINDOW (window), "XfreeCD"); + gtk_window_set_wmclass(GTK_WINDOW(window), "XfreeCD", NULL ); + + /* when the window is given the "delete_event" signal (this is given + * by the window manager (usually the 'close' option, or on the + * titlebar), we ask it to call the delete_event () function + * as defined above. The data passed to the callback + * function is NULL and is ignored in the callback. */ + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (delete_event), NULL); + + /* here we connect the "destroy" event to a signal handler. + * This event occurs when we call gtk_widget_destroy() on the window, + * or if we return 'FALSE' in the "delete_event" callback. */ + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (destroy), NULL); + + gtk_widget_realize(window); + + /* Start up a new list of tool tips */ + tips = gtk_tooltips_new(); + + /* Show the tooltips after the cursor has paused for 2 seconds */ + gtk_tooltips_set_delay( tips, 2000 ); + + /* + * This section fills in all the data structures used by the xpm_button + * subroutine call to create buttons. + * Eventually this will be more automatic/cleaner/maybe a widget? + */ + + ff.up_xpm = (gchar *) ffup_xpm; + ff.dn_xpm = (gchar *) ffdn_xpm; + ff.press = &ff_press; + ff.release = &ff_release; + + rew.up_xpm = (gchar *) rewup_xpm; + rew.dn_xpm = (gchar *) rewdn_xpm; + rew.press = &rew_press; + rew.release = &rew_release; + + play.up_xpm = (gchar *) stopup_xpm; + play.dn_xpm = (gchar *) playdn_xpm; + play.press = &play_press; + play.release = &play_release; + + eject.up_xpm = (gchar *) ejup_xpm; + eject.dn_xpm = (gchar *) ejdn_xpm; + eject.press = &eject_press; + eject.release = &eject_release; + + ex.up_xpm = (gchar *) exitup_xpm; + ex.dn_xpm = (gchar *) exitdn_xpm; + ex.press = &ex_press; + ex.release = &ex_release; + + help.up_xpm = (gchar *) helpup_xpm; + help.dn_xpm = (gchar *) helpdn_xpm; + help.press = &help_press; + help.release = &help_release; + + tdisp.up_xpm = (gchar *) plstrkup_xpm; + tdisp.dn_xpm = (gchar *) plstrkdn_xpm; + tdisp.press = &tdisp_press; + tdisp.release = &tdisp_release; + + rpt.up_xpm = (gchar *) rptup_xpm; + rpt.dn_xpm = (gchar *) rptdn_xpm; + rpt.press = &rpt_press; + rpt.release = &rpt_release; + + vol.up_xpm = (gchar *) volup_xpm; + vol.dn_xpm = (gchar *) voldn_xpm; + vol.press = &vol_press; + vol.release = &vol_release; + + + /* + * The XfreeCD window consists of: + * one vertical box that contains: + * Two vertical boxes + * The top one with hbox of the display and right justified, a 3x2 table + * The bottom one with a hbox of 3 buttons + */ + + /* Make a vbox to hold our hboxes */ + display.vbox = gtk_vbox_new( FALSE, 0 ); + gtk_container_add( GTK_CONTAINER( window ), display.vbox ); + gtk_widget_show( display.vbox ); + + /* Make a hbox to hold the bottom row of buttons REW/PLAY/FF */ + hbox1 = gtk_hbox_new( FALSE, 0 ); + gtk_box_pack_end( GTK_BOX( display.vbox ), hbox1, FALSE, FALSE, 0 ); + gtk_widget_show( hbox1 ); + + /* Make a hbox to put the table into */ + hbox2 = gtk_hbox_new( FALSE, 0 ); + gtk_box_pack_start( GTK_BOX( display.vbox ), hbox2, FALSE, FALSE, 0 ); + gtk_widget_show( hbox2 ); + + /* Make the xpm_buttons and add the tooltips for each one */ + button = xpm_button( window, &rew ); + gtk_box_pack_start( GTK_BOX( hbox1 ), button, FALSE, FALSE, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Previous Track", "ContextHelp/buttons/Prev" ); + + button = xpm_button( window, &play ); + gtk_box_pack_start( GTK_BOX( hbox1 ), button, FALSE, FALSE, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Play/Pause", "ContextHelp/buttons/Play" ); + + button = xpm_button( window, &ff ); + gtk_box_pack_start( GTK_BOX( hbox1 ), button, FALSE, FALSE, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Next Track", "ContextHelp/buttons/Next" ); + + /* Make a table for the 6 control buttons */ + table = gtk_table_new( 2, 3, TRUE ); + + /* Add the table to the end of the hbox (the display goes first) */ + gtk_box_pack_end( GTK_BOX( hbox2 ), table, FALSE, FALSE, 0 ); + + /* Make sure it is showing */ + gtk_widget_show( table ); + + button = xpm_button( window, &vol ); + gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 0, 1, 0, 0, 0, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Volume", "ContextHelp/buttons/Volume" ); + + button = xpm_button( window, &tdisp ); + gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 0, 1, 0, 0, 0, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Time Display", "ContextHelp/buttons/Time" ); + + button = xpm_button( window, &ex ); + gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1, 0, 0, 0, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Exit", "ContextHelp/buttons/Exit" ); + + button = xpm_button( window, &rpt ); + gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 1, 2, 0, 0, 0, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Repeat", "ContextHelp/buttons/Repeat" ); + + button = xpm_button( window, &eject ); + gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 1, 2, 0, 0, 0, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Eject", "ContextHelp/buttons/Eject" ); + + button = xpm_button( window, &help ); + gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 1, 2, 0, 0, 0, 0 ); + gtk_widget_show( button ); + gtk_tooltips_set_tip( tips, button, "Help", "ContextHelp/buttons/Help" ); + + + /* Get the window's style info */ + style = gtk_widget_get_style( window ); + + /* Load all the other pixmaps (some are duplicates) */ + display.null_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.null_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) null_xpm ); + + display.nodisc_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.nodisc_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) nodisc_xpm ); + + display.minus_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.minus_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) minus_xpm ); + + display.playup_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.playup_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) playup_xpm ); + + display.playdn_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.playdn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) playdn_xpm ); + + display.pauseup_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.pauseup_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) pauseup_xpm ); + + display.stopup_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.stopup_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) stopup_xpm ); + + display.sfwddn_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.sfwddn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) sfwddn_xpm ); + + display.srevdn_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.srevdn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) srevdn_xpm ); + + display.rptupact_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.rptupact_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) rptupact_xpm ); + + display.plstrkup_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.plstrkup_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) plstrkup_xpm ); + + display.plstrkdn_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.plstrkdn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) plstrkdn_xpm ); + + display.mnstrkup_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.mnstrkup_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) mnstrkup_xpm ); + + display.mnstrkdn_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.mnstrkdn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) mnstrkdn_xpm ); + + display.plscdup_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.plscdup_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) plscdup_xpm ); + + display.plscddn_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.plscddn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) plscddn_xpm ); + + display.mnscdup_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.mnscdup_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) mnscdup_xpm ); + + display.mnscddn_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.mnscddn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) mnscddn_xpm ); + + display.bar_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.bar_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) bar_xpm ); + + display.nobar_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.nobar_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) nobar_xpm ); + + display.redbar_pixmap = gdk_pixmap_create_from_xpm_d( window->window, + &display.redbar_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) redbar_xpm ); + + display.a_pixmap[0] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[0], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a0_xpm ); + + display.a_pixmap[1] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[1], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a1_xpm ); + + display.a_pixmap[2] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[2], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a2_xpm ); + + display.a_pixmap[3] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[3], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a3_xpm ); + + display.a_pixmap[4] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[4], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a4_xpm ); + + display.a_pixmap[5] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[5], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a5_xpm ); + + display.a_pixmap[6] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[6], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a6_xpm ); + + display.a_pixmap[7] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[7], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a7_xpm ); + + display.a_pixmap[8] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[8], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a8_xpm ); + + display.a_pixmap[9] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[9], + &style->bg[GTK_STATE_NORMAL], + (gchar **) a9_xpm ); + + display.a_pixmap[10] = gdk_pixmap_create_from_xpm_d( window->window, + &display.a_mask[10], + &style->bg[GTK_STATE_NORMAL], + (gchar **) an_xpm ); + + + display.b_pixmap[0] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[0], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b0_xpm ); + + display.b_pixmap[1] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[1], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b1_xpm ); + + display.b_pixmap[2] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[2], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b2_xpm ); + + display.b_pixmap[3] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[3], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b3_xpm ); + + display.b_pixmap[4] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[4], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b4_xpm ); + + display.b_pixmap[5] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[5], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b5_xpm ); + + display.b_pixmap[6] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[6], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b6_xpm ); + + display.b_pixmap[7] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[7], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b7_xpm ); + + display.b_pixmap[8] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[8], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b8_xpm ); + + display.b_pixmap[9] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[9], + &style->bg[GTK_STATE_NORMAL], + (gchar **) b9_xpm ); + + display.b_pixmap[10] = gdk_pixmap_create_from_xpm_d( window->window, + &display.b_mask[10], + &style->bg[GTK_STATE_NORMAL], + (gchar **) bn_xpm ); + + /* + * Create a drawing area for us to show the track and time + */ + display.wid = gtk_drawing_area_new(); + gtk_box_pack_start( GTK_BOX( hbox2 ), display.wid, FALSE, FALSE, 0 ); + gtk_widget_show( display.wid ); + + /* Make sure it is redrawn when covered and uncovered by others */ + gtk_signal_connect( GTK_OBJECT( display.wid ), "expose_event", + (GtkSignalFunc) expose_display, NULL ); + + gtk_drawing_area_size( GTK_DRAWING_AREA(display.wid), 92, 30 ); + gtk_widget_set_events( display.wid, GDK_EXPOSURE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_PRESS_MASK); + + /* gtk_widget_realize (display.wid);*/ + + gtk_signal_connect (GTK_OBJECT (display.wid), "button_press_event", + GTK_SIGNAL_FUNC (display_pressed),NULL); + gtk_signal_connect (GTK_OBJECT (display.wid), "button_release_event", + GTK_SIGNAL_FUNC (display_released),NULL); + gtk_signal_connect (GTK_OBJECT (display.wid), "motion_notify_event", + GTK_SIGNAL_FUNC (display_motion),NULL); + + /* Data area to keep track of the cursor position for moving the window */ + icon_pos = g_new (CursorOffset, 1); + gtk_object_set_user_data(GTK_OBJECT(display.wid), icon_pos); + + x_pos = 0; + y_pos = 0; + /* Check the retun bits -- we want XValue & YValue */ + if( stat & XValue ) + { + /* Is the value negative (relative to right side?) */ + if( stat & XNegative ) + { + /* Make sure it returned a negative value */ + if( x_ret < 0 ) + x_pos = (gdk_screen_width()-137) + x_ret; + else + x_pos = (gdk_screen_width()-137) - x_ret; + } else { + x_pos = x_ret; + } + } + + /* Did we get a Y position? */ + if( stat & YValue ) + { + /* Is the value negative (relative to bottom side?) */ + if( stat & YNegative ) + { + /* Make sure it returned a negative value */ + if( y_ret < 0 ) + y_pos = (gdk_screen_height()-60) + y_ret; + else + y_pos = (gdk_screen_height()-60) - y_ret; + } else { + y_pos = y_ret; + } + } + +#ifdef DEBUG7 + g_print("Setting x=%d y=%d\n", x_pos, y_pos ); +#endif + + /* Put the window where the user wants it (x_pos,y_pos) */ + gtk_widget_set_uposition( window, x_pos, y_pos ); + + /* Setup the colors for the tooltip windows, postit yellow */ + colormap = gdk_window_get_colormap (window->window); + tip_color.red = 61669; + tip_color.green = 59113; + tip_color.blue = 35979; + gdk_color_alloc (colormap, &tip_color); + + /* Set the foreground/background of the tooltips */ + gtk_tooltips_set_colors( tips, &tip_color, &window->style->fg[GTK_STATE_NORMAL] ); + + /* Showing the window last so everything pops up at once. */ + gtk_widget_show (window); + + /* Start the 1 second update timer */ + timer = gtk_timeout_add( 1000, update_cdrom, NULL ); + + /* + Read some useful info from .xfreecdrc + Path to local database + server list + default server + */ + if( read_config( &config ) < 0 ) + { + g_print("read_config failed\n"); + g_free( icon_pos ); + exit(-1); + } + + /* Send the device to the cd_control process */ + send_device(); + + /* Tell cd_control about the exit on eject decision */ + set_eject( config.exit_eject ); + + gtk_main (); + + /* Turn off the 1 second timeout */ + gtk_timeout_remove( timer ); + + g_free( icon_pos ); + + free_config( &config ); /* Free up config's memory usage */ + + return(0); +} + + +gint delete_event(GtkWidget *widget, gpointer data) +{ + /* if you return FALSE in the "delete_event" signal handler, + * GTK will emit the "destroy" signal. Returning TRUE means + * you don't want the window to be destroyed. + * This is useful for popping up 'are you sure you want to quit ?' + * type dialogs. */ + + /* Change TRUE to FALSE and the main window will be destroyed with + * a "delete_event". */ + + return (FALSE); +} + +/* another callback */ +void destroy (GtkWidget *widget, gpointer data) +{ + gtk_main_quit (); +} + + + +/* -------------------------------------------------------------- + Copy the edited data over to cdinfo and write to local database + --------------------------------------------------------------- */ +void write_tracks() +{ + GString *old_category; + int x; + char *texts[3], + *p, + text1[255], + text2[255], + fname[1024], + tmp_fname[1024]; + + + /* Sanity checks. We can't save or send if some of the important fields + are blank. + */ + if( display.tmp_title == NULL ) + return; + + if( display.tmp_category == NULL ) + return; + + if( cdinfo.category == NULL ) + return; + + /* Save the old category so we can erase it if its changed */ + old_category = g_string_new( cdinfo.category->str ); + + /* Copy the new title into the cdinfo structure */ + cdinfo.title = g_string_assign( cdinfo.title, display.tmp_title->str ); + g_string_free( display.tmp_title, 1 ); + display.tmp_title = NULL; + + /* Copy the track names if they exist and delete display storage */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + if( display.tmp_track[x] != NULL ) + { + if( cdinfo.name[x] == NULL ) + cdinfo.name[x] = g_string_new( display.tmp_track[x]->str ); + else + cdinfo.name[x] = g_string_assign( cdinfo.name[x], display.tmp_track[x]->str ); + g_string_free( display.tmp_track[x], 1 ); + display.tmp_track[x] = NULL; + } + } + + /* Copy the new categry name over */ + cdinfo.category = g_string_assign( cdinfo.category, display.tmp_category->str ); + + /* Update the track window's info if its still open */ + if( display.twindow != NULL ) + { + gtk_clist_freeze (GTK_CLIST (display.tclist)); + + /* Clear out the old list first */ + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Set the new title */ + if( cdinfo.title != NULL ) + sprintf( text1, "%s", cdinfo.title->str ); + else + strcpy( text1, "" ); + + gtk_label_set( GTK_LABEL( display.ttitle ), text1 ); + + /* Add the track names */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + sprintf( text1, "%d", x+1 ); + sprintf( text2, "%d:%02d",cdinfo.track[x].length/60,cdinfo.track[x].length%60 ); + texts[0] = text1; + texts[2] = text2; + if( cdinfo.name[x] != NULL ) + texts[1] = cdinfo.name[x]->str; + else + texts[1] = "(blank)"; + + gtk_clist_append (GTK_CLIST (display.tclist), texts); + } + gtk_clist_thaw( GTK_CLIST( display.tclist ) ); + gtk_clist_select_row( GTK_CLIST(display.tclist), display.track-1, -1 ); + } + + /* Save to database -- overwrite previous */ + if( write_cddb( &cdinfo, 1 ) < 0 ) + { + perror("write_cddb error"); + } else { +#ifdef DEBUG3 + g_print("Wrote %08lx ok\n", cddb_discid( &cdinfo ) ); +#endif + + /* The write was successful, we can erase the old category if it is different */ + if( strcmp( cdinfo.category->str, old_category->str ) != 0 ) + { + /* Build the path to the old entry */ + /* Convert a leading ~ into the user's HOME directory */ + if( cdinfo.local_cddb[0] == '~' ) + { + /* Copy the reset of the path/filename to tmp_fname */ + strncpy( tmp_fname, &cdinfo.local_cddb[1], 1023 ); + + if( ( p = (char *) getenv("HOME") ) == NULL ) + { + return; + } + strncpy( fname, p, 1023 ); + + /* Make sure there is a slash inbetween the two */ + if( (fname[strlen(fname)-1] != '/') && (tmp_fname[0] != '/') ) + { + strcat( fname, "/" ); + } + + strncat( fname, tmp_fname, 1023-strlen( p ) ); + } else { + strncpy( fname, cdinfo.local_cddb, 1023 ); + } + + if( fname[strlen(fname)-1] != '/') + strcat( fname, "/" ); + + /* Add the category name */ + strcat( fname, old_category->str ); + strcat( fname, "/" ); + sprintf( tmp_fname, "%08lx", cdinfo.discid ); + strcat( fname, tmp_fname ); + + /* Delete it */ + unlink( fname ); + } + } + + g_string_free( old_category, 1 ); +} + + + +/* -------------------------------------------------------------- + Send the cdinfo to the database + + Increment the revision and save the new one to disk. + Use a system call to mail and cat + --------------------------------------------------------------- */ +void send_cddbd( GtkWidget *widget, GtkWidget *window) +{ + char *p, + tmp_fname[1024], + fname[1024], + buffer[1024]; + + /* Close the edit window */ + gtk_widget_destroy( window ); + + /* Increment the revision number */ + cdinfo.revision++; + + /* Copy all the changes to the cdinfo structure */ + write_tracks(); + + /* Make sure it has a title */ + if( cdinfo.title != NULL ) + { + /* Convert a leading ~ into the user's HOME directory */ + if( cdinfo.local_cddb[0] == '~' ) + { + /* Copy the reset of the path/filename to tmp_fname */ + strncpy( tmp_fname, &cdinfo.local_cddb[1], 1023 ); + + if( ( p = (char *) getenv("HOME") ) == NULL ) + { + return; + } + strncpy( fname, p, 1023 ); + + /* Make sure there is a slash inbetween the two */ + if( (fname[strlen(fname)-1] != '/') && (tmp_fname[0] != '/') ) + { + strcat( fname, "/" ); + } + + strncat( fname, tmp_fname, 1023-strlen( p ) ); + } else { + strncpy( fname, cdinfo.local_cddb, 1023 ); + } + + if( fname[strlen(fname)-1] != '/') + strcat( fname, "/" ); + + /* Add the category name */ + strcat( fname, cdinfo.category->str ); + strcat( fname, "/" ); + sprintf( tmp_fname, "%08lx", cdinfo.discid ); + strcat( fname, tmp_fname ); + + sprintf( buffer, "cat %s | %s -s \"cddb %s %08lx\" %s", fname, MAIL_BINARY, cdinfo.category->str, cdinfo.discid, config.to_cddbd ); + +#ifdef MAIL_DEBUG + g_print( "%s\n", buffer ); +#else + /* Make a system call */ + system( buffer ); +#endif + } +} + + +/* -------------------------------------------------------------- + Save the new cd data to the local cd database + --------------------------------------------------------------- */ +void save_tracks( GtkWidget *widget, GtkWidget *window) +{ + gtk_widget_destroy( window ); + + /* Update cdinfo and write the new data to the local database */ + write_tracks(); +} + + +/* ---------------------------------------------------------------------- + The track entry data has changed. Copy it to a temporary location... + ---------------------------------------------------------------------- */ +void track_entry(GtkWidget *widget, GtkWidget *entry) +{ + gchar *entry_text; + char *texts[3], + text1[255], + text2[255]; + + entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); + + if( display.tmp_track[display.tmp_row] == NULL ) + display.tmp_track[display.tmp_row] = g_string_new( entry_text ); + else + display.tmp_track[display.tmp_row] = g_string_assign( display.tmp_track[display.tmp_row], entry_text ); + + /* Update the clist in the edit window */ + if( display.tewindow != NULL ) + { + gtk_clist_freeze (GTK_CLIST (display.teclist)); + + /* Remove the old entry first */ + gtk_clist_remove( GTK_CLIST( display.teclist ), display.tmp_row ); + + /* Insert the new data */ + sprintf( text1, "%d", display.tmp_row+1 ); + sprintf( text2, "%d:%02d",cdinfo.track[display.tmp_row].length/60,cdinfo.track[display.tmp_row].length%60 ); + texts[0] = text1; + texts[2] = text2; + if( display.tmp_track[display.tmp_row] != NULL ) + texts[1] = display.tmp_track[display.tmp_row]->str; + else + texts[1] = "(blank)"; + gtk_clist_insert (GTK_CLIST (display.teclist), display.tmp_row, texts); + + /* Select the correct row in the clist */ + gtk_clist_select_row( GTK_CLIST(display.teclist), display.tmp_row, -1 ); + + gtk_clist_thaw( GTK_CLIST( display.teclist ) ); + + } +} + + +/* ------------------------------------------------------------------- + The Title entry data has changed, copy it to a temporary location + ------------------------------------------------------------------- */ +void title_entry(GtkWidget *widget, GtkWidget *entry) +{ + gchar *entry_text; + + entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); + + if( display.tmp_title == NULL ) + display.tmp_title = g_string_new( entry_text ); + else + display.tmp_title = g_string_assign( display.tmp_title, entry_text ); +} + + +/* ---------------------------------------------------------------------- + The user selected a track, copy its data into the edit widget + (display.teedit) + ---------------------------------------------------------------------- */ +void select_teclist (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent) +{ + +#ifdef DEBUG9 + g_print ("Selection: Track #%d by button %d\n", row, bevent ? bevent->button : 0 ); +#endif + + if( bevent ) + { + if( bevent->button == 1 ) + { + display.tmp_row = row; + /* Copy the track name into the edit widget */ + if( display.tmp_track[display.tmp_row] != NULL ) + gtk_entry_set_text( GTK_ENTRY( display.teentry ), display.tmp_track[display.tmp_row]->str); + else + gtk_entry_set_text( GTK_ENTRY( display.teentry ), "(blank)" ); + } + } +} + + + + +/* -------------------------------------------------------------------- + If the user select a track in the tracklist window, play that + track now. + -------------------------------------------------------------------- */ +void select_tclist (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent) +{ + +#ifdef DEBUG9 + g_print ("Selection: Track #%d by button %d\n", row, bevent ? bevent->button : 0 ); +#endif + + if( bevent ) + { + if( bevent->button == 1 ) + { + play_track( row+1 ); + } + } +} + + + + +/* ----------------------------------------------------------------------- + Handle the button press events + + Each button has a xx_press and xx_release event where they change their + pixmaps to show a up or down state. + + The FF, REW, Eject button also have to update the state of the play + button since they can effect the state that the player is in. I'm sure + there is a better way to do this... + ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- + Copy the selected item into the category + ----------------------------------------------------------------------- */ +static void menuitem_response (gchar *string) +{ + if( display.tmp_category == NULL ) + display.tmp_category = g_string_new( string ); + else + display.tmp_category = g_string_assign( display.tmp_category, string ); +} + + +/* ----------------------------------------------------------------------- + Start up the window for editing the track list. + Close the normal track list while doing this. + Save it to cddb format when close is clicked. + Don't save when Cancel is clicked. + ----------------------------------------------------------------------- */ +static void edit_tracks(GtkWidget *widget, GtkWidget *data) +{ + GtkWidget *vbox1, + *hbox1, + *button, + *edit, + *optionmenu, + *menu, + *menuitem; + int x, + curr_cat; + char *texts[3], + text1[255], + text2[255]; + static char *titles[] = + { + "Track #", + "Title", + "Length" + }; + static char *categories[] = + { + "blues", + "classical", + "country", + "data", + "folk", + "jazz", + "misc", + "newage", + "reggae", + "rock", + "soundtrack" + }; + + + /* Don't allow edit if there's no disk */ + if( display.status == CDROM_NODISC ) + return; + + if (!display.tewindow) + { + display.tewindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize (display.tewindow, 300, 400); + + gtk_signal_connect (GTK_OBJECT (display.tewindow), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &display.tewindow); + + gtk_window_set_title (GTK_WINDOW (display.tewindow), "Edit Track Info" ); + gtk_container_border_width (GTK_CONTAINER (display.tewindow), 4); + gtk_window_set_wmclass(GTK_WINDOW(display.tewindow), "XfreeCDet", NULL ); + + /* create a vbox to hold the clist and buttons */ + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (display.tewindow), vbox1); + gtk_widget_show (vbox1); + + /* Make a hbox to hold discid and category dropdown */ + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start( GTK_BOX( vbox1 ), hbox1, FALSE, FALSE, 2 ); + gtk_widget_show (hbox1); + + /* Need to show the disc id and category */ + /* Maybe category should be a drop-down listing of the standard categories? */ + sprintf( text1, "Discid: 0x%08lx Category : ", cdinfo.discid ); + button = gtk_label_new( text1 ); + gtk_box_pack_start( GTK_BOX( hbox1 ), button, FALSE, FALSE, 2 ); + gtk_widget_show( button ); + + /* Optionmenu for selecting the category */ + optionmenu = gtk_option_menu_new(); + menu = gtk_menu_new(); + + curr_cat = 0; + /* Add the categories */ + for( x = 0; x < 11; x++ ) + { + /* Set the current category */ + if( cdinfo.category != NULL ) + { + if( strcmp( cdinfo.category->str, categories[x] ) == 0 ) + { + curr_cat = x; + if( display.tmp_category == NULL ) + display.tmp_category = g_string_new( cdinfo.category->str ); + else + display.tmp_category = g_string_assign( display.tmp_category, cdinfo.category->str ); + } + } else { + display.tmp_category= g_string_new( categories[0] ); + } + menuitem = gtk_menu_item_new_with_label( categories[x] ); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_signal_connect_object( GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(menuitem_response), (gpointer) categories[x] ); + gtk_widget_show (menuitem); + } + gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu); + gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), curr_cat ); + gtk_box_pack_start (GTK_BOX (hbox1), optionmenu, FALSE, FALSE, 0); + gtk_widget_show (optionmenu); + + + + /* Entry Widget for the title of the CD */ + edit = gtk_entry_new_with_max_length( 254 ); + gtk_signal_connect(GTK_OBJECT(edit), "changed", + GTK_SIGNAL_FUNC(title_entry), + edit); + + if( cdinfo.title != NULL ) + gtk_entry_set_text( GTK_ENTRY( edit ), cdinfo.title->str ); + gtk_editable_select_region( GTK_EDITABLE( edit ), 0, -1 ); + gtk_box_pack_start( GTK_BOX( vbox1 ), edit, FALSE, FALSE, 2 ); + gtk_widget_show( edit ); + + /* Initalize the title */ + if( cdinfo.title != NULL ) + display.tmp_title = g_string_new( cdinfo.title->str ); + + /* Entry Widget for the track name-changed by selecting a diff. track */ + display.teentry = gtk_entry_new_with_max_length( 254 ); + gtk_box_pack_start( GTK_BOX( vbox1 ), display.teentry, FALSE, FALSE, 2 ); + gtk_widget_show( display.teentry ); + + /* Create the clist */ + display.teclist = gtk_clist_new_with_titles (3, titles); + gtk_clist_set_row_height (GTK_CLIST (display.teclist), 20); + gtk_clist_set_column_width (GTK_CLIST (display.teclist), 0, 45); + gtk_clist_set_column_width (GTK_CLIST (display.teclist), 1, 150); + gtk_clist_set_column_width (GTK_CLIST (display.teclist), 2, 45); + gtk_signal_connect (GTK_OBJECT (display.teclist), + "select_row", + (GtkSignalFunc) select_teclist, + NULL); +#ifdef GOOBER + gtk_clist_set_selection_mode (GTK_CLIST (display.teclist), GTK_SELECTION_BROWSE); +#endif + gtk_clist_set_policy (GTK_CLIST (display.teclist), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_clist_set_column_justification (GTK_CLIST (display.teclist), 0, GTK_JUSTIFY_CENTER); + gtk_clist_set_column_justification (GTK_CLIST (display.teclist), 1, GTK_JUSTIFY_LEFT); + gtk_clist_set_column_justification (GTK_CLIST (display.teclist), 2, GTK_JUSTIFY_LEFT); + + gtk_clist_freeze (GTK_CLIST (display.teclist)); + + display.tmp_row = 0; + /* Add the track names */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + sprintf( text1, "%d", x+1 ); + sprintf( text2, "%d:%02d",cdinfo.track[x].length/60,cdinfo.track[x].length%60 ); + texts[0] = text1; + texts[2] = text2; + if( cdinfo.name[x] != NULL ) + texts[1] = cdinfo.name[x]->str; + else + texts[1] = "(blank)"; + gtk_clist_append (GTK_CLIST (display.teclist), texts); + + /* Initalize the temporary storage */ + if( cdinfo.name[x] != NULL ) + display.tmp_track[x] = g_string_new( cdinfo.name[x]->str ); + else + display.tmp_track[x] = NULL; + } + gtk_clist_thaw( GTK_CLIST( display.teclist ) ); + + gtk_container_border_width (GTK_CONTAINER (display.teclist), 5); + gtk_box_pack_start (GTK_BOX (vbox1), display.teclist, TRUE, TRUE, 0); + gtk_widget_show (display.teclist); + + /* Now we can update the track edit control, since the tclist is setup */ + gtk_signal_connect(GTK_OBJECT(display.teentry), "changed", + GTK_SIGNAL_FUNC(track_entry), + display.teentry); + if( display.tmp_track[0] != NULL ) + gtk_entry_set_text( GTK_ENTRY( display.teentry ), display.tmp_track[0]->str ); + gtk_editable_select_region( GTK_EDITABLE( display.teentry ), 0, -1 ); + + button = gtk_button_new_with_label ("Send To Server"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(send_cddbd), + GTK_OBJECT (display.tewindow)); + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 2); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Save"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(save_tracks), + GTK_OBJECT (display.tewindow)); + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 2); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.tewindow)); + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 2); + gtk_widget_show (button); + + gtk_widget_show( display.tewindow ); + } +} + + + +/* + Handle button press in the display window. + Determine if its a click for a track list or a drag to move the window +*/ +static void display_pressed (GtkWidget *widget, GdkEventButton *event) +{ + CursorOffset *p; + GtkWidget *vbox1, + *button; + int x; + char *texts[3], + text1[255], + text2[255]; + static char *titles[] = + { + "Track #", + "Title", + "Length" + }; + + + /* ignore double and triple click */ + if (event->type != GDK_BUTTON_PRESS) + return; + + /* Right button is move window */ + if( event->button == 3 ) + { + if( ( p = gtk_object_get_user_data (GTK_OBJECT(widget)) ) != NULL ) + { + p->x = (int) event->x; + p->y = (int) event->y; + + gtk_grab_add (widget); + gdk_pointer_grab (widget->window, TRUE, + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK, + NULL, NULL, 0); + } + } else if( event->button == 1 ) { + /* Show the title and the tracks, using a clist */ + if (!display.twindow) + { + display.twindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize (display.twindow, 300, 350); + + gtk_signal_connect (GTK_OBJECT (display.twindow), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &display.twindow); + + /* gtk_window_set_title (GTK_WINDOW (display.twindow), cdinfo.title); */ + gtk_container_border_width (GTK_CONTAINER (display.twindow), 4); + gtk_window_set_wmclass(GTK_WINDOW(display.twindow), "XfreeCDt", NULL ); + + /* create a vbox to hold the clist and buttons */ + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (display.twindow), vbox1); + gtk_widget_show (vbox1); + + if( cdinfo.title != NULL ) + sprintf( text1, "%s", cdinfo.title->str ); + else + strcpy( text1, "" ); + display.ttitle = gtk_label_new( text1 ); + gtk_box_pack_start( GTK_BOX( vbox1 ), display.ttitle, FALSE, FALSE, 0 ); + gtk_widget_show( display.ttitle ); + + /* Create the clist */ + display.tclist = gtk_clist_new_with_titles (3, titles); + gtk_clist_set_row_height (GTK_CLIST (display.tclist), 20); + gtk_clist_set_column_width (GTK_CLIST (display.tclist), 0, 45); + gtk_clist_set_column_width (GTK_CLIST (display.tclist), 1, 150); + gtk_clist_set_column_width (GTK_CLIST (display.tclist), 2, 45); + gtk_signal_connect (GTK_OBJECT (display.tclist), + "select_row", + (GtkSignalFunc) select_tclist, + NULL); + +#ifdef GOOBER + gtk_clist_set_selection_mode (GTK_CLIST (display.tclist), GTK_SELECTION_BROWSE); +#endif + gtk_clist_set_policy (GTK_CLIST (display.tclist), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_clist_set_column_justification (GTK_CLIST (display.tclist), 0, GTK_JUSTIFY_CENTER); + gtk_clist_set_column_justification (GTK_CLIST (display.tclist), 1, GTK_JUSTIFY_LEFT); + gtk_clist_set_column_justification (GTK_CLIST (display.tclist), 2, GTK_JUSTIFY_LEFT); + + if( display.status != CDROM_NODISC ) + { + gtk_clist_freeze (GTK_CLIST (display.tclist)); + /* Add the track names */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + sprintf( text1, "%d", x+1 ); + sprintf( text2, "%d:%02d",cdinfo.track[x].length/60,cdinfo.track[x].length%60 ); + texts[0] = text1; + texts[2] = text2; + if( cdinfo.name[x] != NULL ) + texts[1] = cdinfo.name[x]->str; + else + texts[1] = "(blank)"; + gtk_clist_append (GTK_CLIST (display.tclist), texts); + } + gtk_clist_thaw( GTK_CLIST( display.tclist ) ); + } + + gtk_container_border_width (GTK_CONTAINER (display.tclist), 5); + gtk_box_pack_start (GTK_BOX (vbox1), display.tclist, TRUE, TRUE, 0); + gtk_widget_show (display.tclist); + + button = gtk_button_new_with_label ("Edit Info"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(edit_tracks), + GTK_OBJECT (display.twindow)); + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 2); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.twindow)); + + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 2); + /* GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); */ + /* gtk_widget_grab_default (button); */ + gtk_widget_show (button); + gtk_widget_show( display.twindow ); + } + } +} + + +static void display_released (GtkWidget *widget) +{ + gtk_grab_remove (widget); + gdk_pointer_ungrab (0); +} + + +static void display_motion (GtkWidget *widget, GdkEventMotion *event) +{ + gint xp, yp; + CursorOffset * p; + GdkModifierType mask; + + if( ( p = gtk_object_get_user_data (GTK_OBJECT (widget)) ) != NULL ) + { + /* + * Can't use event->x / event->y here + * because I need absolute coordinates. + */ + gdk_window_get_pointer (root_win, &xp, &yp, &mask); + gtk_widget_set_uposition (display.main_window, xp - p->x, yp - p->y); + } +} + + + + +void ff_press (GtkWidget *widget, GdkEventButton *event) +{ + /* Left button pressed */ + if( event->button == 1 ) + { + /* Set the FF down image */ + gtk_pixmap_set( GTK_PIXMAP( ff.wid ), + ff.image.dn_pixmap, + ff.image.dn_mask ); + + /* Tell the CD control to play the next track */ + play_next(); + + + /* Update the state of the play button -- Should be a subroutine */ + if( (display.playbtn != CDROM_PLAYING) && (display.status != CDROM_NODISC)) + { + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playup_pixmap, + display.playup_mask ); + display.playbtn = CDROM_PLAYING; + } + } +} + + +void ff_release (GtkWidget *widget, GdkEventButton *event) +{ + if( (event->button == 1) ) + { + /* Draw the button up image */ + gtk_pixmap_set( GTK_PIXMAP( ff.wid ), + ff.image.up_pixmap, + ff.image.up_mask ); + } +} + + +void rew_press (GtkWidget *widget, GdkEventButton *event) +{ + /* Left button pressed */ + if( event->button == 1 ) + { + /* Draw the down image for REW */ + gtk_pixmap_set( GTK_PIXMAP( rew.wid ), + rew.image.dn_pixmap, + rew.image.dn_mask ); + + /* Tell the CD to play the previous track */ + play_previous(); + + + /* Update the state of the Play button -- should be a subroutine */ + if( (display.playbtn != CDROM_PLAYING) && (display.status != CDROM_NODISC)) + { + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playup_pixmap, + display.playup_mask ); + display.playbtn = CDROM_PLAYING; + } + + } +} + + +void rew_release (GtkWidget *widget, GdkEventButton *event) +{ + if( (event->button == 1) ) + { + /* Draw the up image for the button */ + gtk_pixmap_set( GTK_PIXMAP( rew.wid ), + rew.image.up_pixmap, + rew.image.up_mask ); + } +} + + +void play_press (GtkWidget *widget, GdkEventButton *event) +{ + int x; + + /* Left button press */ + if( event->button == 1 ) + { + /* Depending on the current state of the button, display the correct image */ + switch( display.playbtn ) + { + case CDROM_PLAYING: gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playdn_pixmap, + display.playdn_mask ); + pause_cdrom(); + display.playbtn = CDROM_PAUSED; + break; + + case CDROM_PAUSED: gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playdn_pixmap, + display.playdn_mask ); + resume_cdrom(); + display.playbtn = CDROM_PLAYING; + break; + + case CDROM_NODISC: gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playdn_pixmap, + display.playdn_mask ); + + play_track( 1 ); + update_display(); + display.playbtn = CDROM_PLAYING; + break; + } + } else if( event->button ==3 ) { + /* Stop playing without ejecting the CD */ + switch( display.playbtn ) + { + + case CDROM_PLAYING : + case CDROM_PAUSED : + stop_cdrom(); + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playdn_pixmap, + display.playdn_mask ); + update_display(); + display.playbtn = CDROM_NODISC; + + /* Clear out the track list */ + if( display.twindow != NULL ) + { + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Clear the title */ + gtk_label_set( GTK_LABEL( display.ttitle ), "" ); + } + + /* Erase the title and track names */ + if( cdinfo.title != NULL ) + { + g_string_free( cdinfo.title, 1 ); + cdinfo.title = NULL; + } + + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + if( cdinfo.name[x] != NULL ) + { + g_string_free( cdinfo.name[x], 1 ); + cdinfo.name[x] = NULL; + } + } + + /* Free up dynamically allocated cdinfo strings */ + free_cdinfo(); + break; + + case CDROM_NODISC : + break; + } + } +} + + +void play_release (GtkWidget *widget, GdkEventButton *event) +{ + if( (event->button == 1) || (event->button ==3) ) + { + switch( display.playbtn ) + { + case CDROM_PAUSED: gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.pauseup_pixmap, + display.pauseup_mask ); + break; + + case CDROM_PLAYING: gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playup_pixmap, + display.playup_mask ); + break; + + case CDROM_NODISC: gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.stopup_pixmap, + display.stopup_mask ); + break; + + } + } +} + + +void eject_press (GtkWidget *widget, GdkEventButton *event) +{ + int x; + + if( event->button == 1 ) + { + gtk_pixmap_set( GTK_PIXMAP( eject.wid ), + eject.image.dn_pixmap, + eject.image.dn_mask ); + + + /* + * If we are playing or paused then we will be stopped, so change + * the play button to the stop button + */ + switch( display.status ) + { + case CDROM_PAUSED : + case CDROM_PLAYING : + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.stopup_pixmap, + display.stopup_mask ); + display.playbtn = CDROM_NODISC; + break; + } + eject_cdrom(); + display.playbtn = CDROM_NODISC; + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.nodisc_pixmap, + 0, 0, + 0, 0, 92, 30 ); + + /* Clear out the track list */ + if( display.twindow != NULL ) + { + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Clear the title */ + gtk_label_set( GTK_LABEL( display.ttitle ), "" ); + } + + + /* Erase the title and track names */ + if( cdinfo.title != NULL ) + { + g_string_free( cdinfo.title, 1 ); + cdinfo.title = NULL; + } + + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + if( cdinfo.name[x] != NULL ) + { + g_string_free( cdinfo.name[x], 1 ); + cdinfo.name[x] = NULL; + } + } + + /* Free up the dynamically allocated cdinfo strings */ + free_cdinfo(); + } +} + + +void eject_release (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + gtk_pixmap_set( GTK_PIXMAP( eject.wid ), + eject.image.up_pixmap, + eject.image.up_mask ); + } +} + + +gint ex_timer( gpointer data ) +{ + gtk_timeout_remove( ex.timer ); + + gtk_main_quit(); + + return FALSE; +} + + +void ex_press (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + gtk_pixmap_set( GTK_PIXMAP( ex.wid ), + ex.image.dn_pixmap, + ex.image.dn_mask ); + + /* In 100mS execute the play_next function */ + ex.timer = gtk_timeout_add( 500, ex_timer, NULL ); + + } +} + + +void ex_release (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + gtk_pixmap_set( GTK_PIXMAP( ex.wid ), + ex.image.up_pixmap, + ex.image.up_mask ); + } +} + + +void +destroy_window (GtkWidget *widget, + GtkWidget **window) +{ + *window = NULL; +} + + +void close_setup( GtkWidget *widget, GtkWidget *window) +{ + gtk_widget_destroy( window ); + + /* Write configuration */ + write_config( &config ); + + /* Send the new device to the cd_control process */ + send_device(); +} + + +/* Toggle the state of the cddb button */ +static void toggle_cddb (GtkWidget *checkbutton, + GtkWidget *text) +{ + config.cddb = GTK_TOGGLE_BUTTON(checkbutton)->active; + +#ifdef DEBUG3 + g_print("Toggling cddb = %d\n", config.cddb ); +#endif + + config.saved = 0; /* Needs to be written to disk */ +} + + +#ifdef CHANGER_SUPPORT +/* Toggle the CD changer support button */ +static void toggle_changer (GtkWidget *checkbutton, + GtkWidget *text) +{ + config.changer = GTK_TOGGLE_BUTTON(checkbutton)->active; + +#ifdef DEBUG3 + g_print("Toggling changer = %d\n", config.changer ); +#endif + + config.saved = 0; /* Needs to be written to disk */ +} +#endif + + +/* Toggle the Eject when done playing */ +static void toggle_eject_done(GtkWidget *checkbutton, + GtkWidget *text) +{ + config.done_eject = GTK_TOGGLE_BUTTON(checkbutton)->active; + +#ifdef DEBUG3 + g_print("Toggling done_eject = %d\n", config.done_eject ); +#endif + + config.saved = 0; /* Needs to be written to disk */ +} + + +/* Toggle the Eject at Close */ +static void toggle_eject_exit(GtkWidget *checkbutton, + GtkWidget *text) +{ + config.exit_eject = GTK_TOGGLE_BUTTON(checkbutton)->active; + +#ifdef DEBUG3 + g_print("Toggling exit_eject = %d\n", config.exit_eject ); +#endif + + set_eject( config.exit_eject ); + config.saved = 0; /* Needs to be written to disk */ +} + +static void toggle_startup(GtkWidget *checkbutton, + GtkWidget *text) +{ + config.startup = GTK_TOGGLE_BUTTON(checkbutton)->active; + config.saved = 0; /* Needs to be written to disk */ +} + + +void cddb_servers() +{ + + /* Placeholder for server listing/editing */ +} + + +static void +page_switch (GtkWidget *widget, GtkNotebookPage *page, gint page_num) +{ + GtkNotebookPage *oldpage; + + oldpage = GTK_NOTEBOOK (widget)->cur_page; + + if (page == oldpage) + return; + +} + + +void device_entry(GtkWidget *widget, GtkWidget *entry) +{ + gchar *entry_text; + + entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); + + config.device = realloc( config.device, strlen(entry_text)+1); + strcpy( config.device, entry_text ); + config.saved = 0; /* Needs to be written to disk */ +} + +void cddb_entry(GtkWidget *widget, GtkWidget *entry) +{ + gchar *entry_text; + + entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); + + config.local_cddb = realloc( config.local_cddb, strlen(entry_text)+1); + strcpy( config.local_cddb, entry_text ); + strcpy( cdinfo.local_cddb, entry_text ); + + config.saved = 0; /* Needs to be written to disk */ +} + +void cddb_to_email(GtkWidget *widget, GtkWidget *entry) +{ + gchar *entry_text; + + entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); + + config.to_cddbd = realloc( config.to_cddbd, strlen(entry_text)+1); + strcpy( config.to_cddbd, entry_text ); + + config.saved = 0; /* Needs to be written to disk */ +} + + +void server_entry(GtkWidget *widget, GtkWidget *entry) +{ + gchar *entry_text; + + entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); + + config.current = realloc( config.current, strlen(entry_text)+1); + strcpy( config.current, entry_text ); + config.saved = 0; /* Needs to be written to disk */ +} + + +void refresh_servers() +{ + char buffer[80]; + + /* Need to lock this routine until we complete the last request */ + if( display.cddb_lock == 0 ) + { + /* Get the server list from cddb.cddb.com - DB_SITES */ + /* Tell it to print the diagnostic string */ + cdinfo.cddbd_cmnd = DB_SITES; + + /* Set the server to connect to */ + strncpy( cdinfo.server, "cddb.cddb.com", 80 ); + cdinfo.port = 888; + if( write( cddbd_fd, &cdinfo, sizeof( struct CDINFO ) ) < 0 ) + { + perror("write to cddbd error"); + } + + display.cddb_lock = 1; + + /* Start up a progress dialog */ + display.progress = gtk_dialog_new (); + + sprintf( buffer, "Connecting to %s:%d", cdinfo.server, cdinfo.port ); + + gtk_signal_connect( GTK_OBJECT( display.progress ), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + &display.progress); + + gtk_window_set_title (GTK_WINDOW (display.progress), "CDDBD Status"); + gtk_container_border_width (GTK_CONTAINER (display.progress), 0); + gtk_window_set_wmclass(GTK_WINDOW(display.progress), "XfreeCDp", NULL ); + + display.plabel = gtk_label_new (buffer); + gtk_misc_set_padding (GTK_MISC (display.plabel), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->vbox), + display.plabel, FALSE, FALSE, 0); + gtk_widget_show( display.plabel ); + gtk_widget_show( display.progress ); + } +} + + +/* ----------------------------------------------------------------------- + Display the help/setup dialog box + + All changed info is saved when this dialog is exited. + ----------------------------------------------------------------------- */ +gint help_timer( gpointer data ) +{ + struct SITE *sp; + static GtkWidget *window = NULL; + GtkWidget *notebook, + *text, + *vbox1, + *vbox2, + *label, + *button, + *table, + *hscrollbar, + *vscrollbar, + *edit; + GList *cbitems = NULL; + + + gtk_timeout_remove( help.timer ); + help.timer = 0; + + /* Create the main window for the notebook */ + if( !window ) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &window); + + gtk_window_set_title (GTK_WINDOW (window), "notebook"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + gtk_window_set_title (GTK_WINDOW( window ), "XfreeCD Setup"); + gtk_widget_set_usize (window, 250, 300); + gtk_window_set_wmclass(GTK_WINDOW(window), "XfreeCDs", NULL ); + + /* Create a vbox to hold the notebook */ + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox1); + + /* Create the notebook */ + notebook = gtk_notebook_new (); + gtk_signal_connect (GTK_OBJECT (notebook), "switch_page", + GTK_SIGNAL_FUNC (page_switch), NULL); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + gtk_box_pack_start (GTK_BOX (vbox1), notebook, TRUE, TRUE, 0); + gtk_container_border_width (GTK_CONTAINER (notebook), 10); + gtk_widget_realize (notebook); + + /* Create the about page for the notebook -- Put a text window in it */ + vbox2 = gtk_vbox_new( FALSE, 0 ); + gtk_widget_show( vbox2 ); + + 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 (vbox2), 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 (GTK_TABLE (table), text, 0, 1, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + 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_SHRINK, 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_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + /* Create the label box for the About page */ + label = gtk_label_new ("About"); + + /* Add it to the notebook */ + gtk_notebook_append_page_menu (GTK_NOTEBOOK(notebook), vbox2, label, label ); + + gtk_text_freeze (GTK_TEXT (text)); + + gtk_widget_realize (text); + + /* Add the actual text */ + HELP_TEXT( "XfreeCD v0.7.8\n" ); + HELP_TEXT( "Copyright 1998 Brian C. Lane\n" ); + HELP_TEXT( "<nexus@tatoosh.com>\n" ); + HELP_TEXT( "http://www.tatoosh.com/nexus\n\n" ); + + HELP_TEXT( "Click on the 'SETUP' tab to set the\n" ); + HELP_TEXT( "CD device and some options:\n\n" ); + HELP_TEXT( "AutoPlay will start playing the CD\n" ); + HELP_TEXT( "when XfreeCD is started\n\n" ); + HELP_TEXT( "Eject when done will eject the CD\n" ); + HELP_TEXT( "when it is finished playing if repeat\n" ); + HELP_TEXT( "is not turned on (the button on the\n" ); + HELP_TEXT( "main panel).\n\n" ); + HELP_TEXT( "Eject on Exit will eject the CD if it\n"); + HELP_TEXT( "is not playing when you exit.\n\n" ); + HELP_TEXT( "Click on the 'CDDB' tab to set up\n" ); + HELP_TEXT( "the support for online cd database\n" ); + HELP_TEXT( "support. The Local CDDB Path\n" ); + HELP_TEXT( "should point to a directory where\n" ); + HELP_TEXT( "you have read and write\n"); + HELP_TEXT( "permission. This is where the\n" ); + HELP_TEXT( "track lists for the CDs will be\n"); + HELP_TEXT( "saved.\n\n"); + HELP_TEXT( "The CDDB Submit email field is for\n" ); + HELP_TEXT( "the email address of the CDDB\n"); + HELP_TEXT( "server to submit CD information\n" ); + HELP_TEXT( "to. The send button is located\n" ); + HELP_TEXT( "in the Track Edit window. Please\n" ); + HELP_TEXT( "only submit CDs that do not exist\n"); + HELP_TEXT( "in the database and that have\n" ); + HELP_TEXT( "complete title and track text\n" ); + HELP_TEXT( "entered.\n\n" ); + HELP_TEXT( "The CDDB server is the internet\n" ); + HELP_TEXT( "site where requests for unknown\n" ); + HELP_TEXT( "CDs will be sent to. Initially only\n" ); + HELP_TEXT( "cddb.cddb.com is listed. Click\n"); + HELP_TEXT( "Refresh Server List to download a\n"); + HELP_TEXT( "list of the available servers.\n" ); + HELP_TEXT( "Use the combobox to pick a server\n" ); + HELP_TEXT( "close to you. If you unselect cddb\n" ); + HELP_TEXT( "support the internet server will\n" ); + HELP_TEXT( "not be queried, but the local\n" ); + HELP_TEXT( "database will be used.\n\n" ); + HELP_TEXT( "Right click & drag on the main\n"); + HELP_TEXT( "display window will allow you to\n" ); + HELP_TEXT( "move XfreeCD even when you\n"); + HELP_TEXT( "have title bars and handles. Left\n"); + HELP_TEXT( "Clicking on the display will open\n"); + HELP_TEXT( "up the Track List window.\n\n" ); + HELP_TEXT( "In the Track List window you can\n"); + HELP_TEXT( "click on the title of a track and\n"); + HELP_TEXT( "XfreeCD will jump directly to\n" ); + HELP_TEXT( "that track and play it.\n\n" ); + HELP_TEXT( "Right clicking on the play/pause\n"); + HELP_TEXT( "button will stop playing and\n"); + HELP_TEXT( "turn off the CD player.\n\n"); + HELP_TEXT( "Volume is controlled by left/right\n"); + HELP_TEXT( "clicking on the volume button.\n\n"); + HELP_TEXT( "Thanks to Ti Kan and Steve Scherf\n" ); + HELP_TEXT( "for creating CDDB.\n\n" ); + + gtk_text_thaw (GTK_TEXT (text)); + + /* Add the general setup page */ + vbox2 = gtk_vbox_new( FALSE, 0 ); + gtk_widget_show( vbox2 ); + + /* Add an editable field for the device */ + label = gtk_label_new ("CDROM device:"); + gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + edit = gtk_entry_new_with_max_length(20); + gtk_signal_connect(GTK_OBJECT(edit), "changed", + GTK_SIGNAL_FUNC(device_entry), + edit); + gtk_widget_show( edit ); + +#ifdef DEBUG3 + g_print("config.device = %s\n", config.device ); +#endif + + if( config.device != NULL ) + gtk_entry_set_text( GTK_ENTRY( edit ), config.device ); + gtk_editable_select_region( GTK_EDITABLE( edit ), 0, -1 ); + gtk_box_pack_start( GTK_BOX( vbox2 ), edit, FALSE, FALSE, 0 ); + gtk_widget_show( edit ); + +#ifdef DEBUG3 + g_print("config.startup = %d\n", config.startup ); +#endif + + /* Create a check button for Playing at Startup */ + button = gtk_check_button_new_with_label("AutoPlay"); + gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (config.startup == 1)); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( toggle_startup ), NULL ); + gtk_widget_show( button ); + +#ifdef DEBUG3 + g_print("config.changer = %d\n", config.changer ); +#endif + +#ifdef CHANGER_SUPPORT + /* Create a check button for CD Changer */ + button = gtk_check_button_new_with_label("CD Changer"); + gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (config.changer == 1)); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( toggle_changer ), NULL ); + gtk_widget_show( button ); +#endif + +#ifdef DEBUG3 + g_print("config.done_eject = %d\n", config.done_eject ); +#endif + + /* Create a check button for Eject on Close */ + button = gtk_check_button_new_with_label("Eject when done"); + gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (config.done_eject==1)); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( toggle_eject_done ), NULL ); + gtk_widget_show( button ); + + /* Create a check button for Eject on Exit (and not playing) */ + button = gtk_check_button_new_with_label("Eject on Exit"); + gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (config.exit_eject==1)); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( toggle_eject_exit ), NULL ); + gtk_widget_show( button ); + + + /* Create the label box for the Setup page */ + label = gtk_label_new ("Setup"); + + /* Add it to the notebook */ + gtk_notebook_append_page_menu( GTK_NOTEBOOK( notebook ), vbox2, label, label ); + + + /* Create the CDDB page for the notebook */ + vbox2 = gtk_vbox_new( FALSE, 0 ); + gtk_widget_show( vbox2 ); + + /* Path to the local cddb database */ + label = gtk_label_new( "Local CDDB Path" ); + gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + /* Add an editable field for the local CDDBD database */ + edit = gtk_entry_new_with_max_length( 1023 ); + gtk_signal_connect(GTK_OBJECT(edit), "changed", + GTK_SIGNAL_FUNC(cddb_entry), + edit); + gtk_widget_show( edit ); + +#ifdef DEBUG3 + g_print("config.local_cddb = %s\n", config.local_cddb ); +#endif + + if( config.local_cddb != NULL ) + gtk_entry_set_text( GTK_ENTRY( edit ), config.local_cddb ); + gtk_editable_select_region( GTK_EDITABLE( edit ), 0, -1 ); + gtk_box_pack_start( GTK_BOX( vbox2 ), edit, FALSE, FALSE, 0 ); + gtk_widget_show( edit ); + + /* Email address for submitting to the database */ + label = gtk_label_new( "CDDB Submit Email" ); + gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + /* Add an editable field for the email address */ + edit = gtk_entry_new_with_max_length( 1023 ); + gtk_signal_connect(GTK_OBJECT(edit), "changed", + GTK_SIGNAL_FUNC(cddb_to_email), + edit); + gtk_widget_show( edit ); + +#ifdef DEBUG3 + g_print("config.local_cddb = %s\n", config.local_cddb ); +#endif + + if( config.to_cddbd != NULL ) + gtk_entry_set_text( GTK_ENTRY( edit ), config.to_cddbd ); + gtk_editable_select_region( GTK_EDITABLE( edit ), 0, -1 ); + gtk_box_pack_start( GTK_BOX( vbox2 ), edit, FALSE, FALSE, 0 ); + gtk_widget_show( edit ); + + +#ifdef DEBUG3 + g_print("config.cddb = %d\n", config.cddb ); +#endif + + /* Create a check button for CDDB support */ + button = gtk_check_button_new_with_label("CDDB Support"); + gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (config.cddb == 1)); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( toggle_cddb ), NULL ); + gtk_widget_show( button ); + + + /* Create the list of servers, use a combobox for this */ + label = gtk_label_new( "CDDB Server" ); + gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + /* Walk the list */ + cbitems = NULL; + sp = config.server; + while( sp != NULL ) + { + cbitems = g_list_append(cbitems, sp->name); + sp = sp->next; + } + + display.cb = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (display.cb), cbitems); + + /* Here we should put the selected server into the entry box */ + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO(display.cb)->entry), config.current); + + gtk_signal_connect(GTK_OBJECT(GTK_COMBO(display.cb)->entry), "changed", + GTK_SIGNAL_FUNC(server_entry), + GTK_COMBO(display.cb)->entry); + gtk_editable_select_region (GTK_EDITABLE (GTK_COMBO(display.cb)->entry), + 0, -1); + gtk_box_pack_start (GTK_BOX (vbox2), display.cb, FALSE, FALSE, 0); + gtk_widget_show (display.cb); + + + /* Add a button to refresh the list with */ + button = gtk_button_new_with_label("Refresh Server List"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (refresh_servers), + GTK_OBJECT( window )); + gtk_box_pack_end (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + + /* Create the label box for the CDDB page */ + label = gtk_label_new ("CDDB"); + + /* Add it to the notebook */ + gtk_notebook_append_page_menu( GTK_NOTEBOOK( notebook ), vbox2, label, label ); + + /* Add the close button */ + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (close_setup), + GTK_OBJECT( window )); + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show_all (window); + else + gtk_widget_destroy( window ); + + return FALSE; +} + + +#ifdef GOOBER1 +void old_stuff() +{ + + /* A useful frame with 3 radio buttons in it */ + + /* Create a frame with the Startup options as radio buttons */ + frame = gtk_frame_new("Startup Action"); + gtk_box_pack_start(GTK_BOX(vbox2), frame, FALSE, FALSE, 0); + gtk_widget_show(frame); + + /* Add the general setup page */ + vbox3 = gtk_vbox_new( FALSE, 0 ); + gtk_container_add(GTK_CONTAINER(frame), vbox3); + gtk_container_border_width(GTK_CONTAINER(vbox3), 0); + gtk_widget_show( vbox3 ); + + /* create radio button for Play at startup */ + button = gtk_radio_button_new_with_label( NULL, "Play CD"); + if( config.startup == STARTUP_PLAY ) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + else + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( play_setup ), NULL ); + gtk_box_pack_start(GTK_BOX(vbox3), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + button = gtk_radio_button_new_with_label( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), "Show Tracks"); + if( config.startup == STARTUP_TRACKS ) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + else + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( tracks_setup ), NULL ); + gtk_box_pack_start(GTK_BOX(vbox3), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + button = gtk_radio_button_new_with_label( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), "No Disc"); + if( config.startup == STARTUP_NODISC ) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + else + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE); + gtk_signal_connect( GTK_OBJECT( button ), "toggled", + GTK_SIGNAL_FUNC( nothing_setup ), NULL ); + gtk_box_pack_start(GTK_BOX(vbox3), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + + + + + + + + + GtkWidget *hbox; + GtkWidget *button; + GtkWidget *check; + GtkWidget *separator; + GtkWidget *table; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *text; + + 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), TRUE); + gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + 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_SHRINK, 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_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + "This program will play CDs using an attached ", -1); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + "IDE or SoundBlaster CD player. It currently ", -1); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + "does not work with SCSI drives.\n\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + "The latest version is available from my webpage.", -1); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + "Please email me with any suggestions, problems,", -1); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + "or comments you may have\n\n", -1); + + hbox = gtk_hbutton_box_new (); + gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); + + /* check = gtk_check_button_new_with_label("Editable"); + * gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0); + * gtk_signal_connect (GTK_OBJECT(check), "toggled", + * GTK_SIGNAL_FUNC(text_toggle_editable), text); + * gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE); + * gtk_widget_show (check); + */ + + /* check = gtk_check_button_new_with_label("Wrap Words"); + * gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0); + * gtk_signal_connect (GTK_OBJECT(check), "toggled", + * GTK_SIGNAL_FUNC(text_toggle_word_wrap), text); + * gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE); + * gtk_widget_show (check); + */ + + /* Checkbox for www.cddb.com support */ + check = gtk_check_button_new_with_label("www.cddb.com"); + gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT(check), "toggled", + GTK_SIGNAL_FUNC(about_toggle_cddb), text); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE); + gtk_widget_show (check); + + /* Checkbox for CD Changer support */ + check = gtk_check_button_new_with_label("CD changer"); + gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT(check), "toggled", + GTK_SIGNAL_FUNC(about_toggle_cddb), text); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE); + gtk_widget_show (check); + + gtk_text_set_word_wrap(GTK_TEXT(text), TRUE ); + + 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); + +} +#endif + + +void help_press (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + gtk_pixmap_set( GTK_PIXMAP( help.wid ), + help.image.dn_pixmap, + help.image.dn_mask ); + + /* In XXXmS execute the help dialog window function */ + help.timer = gtk_timeout_add( 500, help_timer, NULL ); + } +} + + +void help_release (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + gtk_pixmap_set( GTK_PIXMAP( help.wid ), + help.image.up_pixmap, + help.image.up_mask ); + } +} + + +void tdisp_press (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + /* Cycle through the time display options */ + switch( display.time ) + { + case TRACK_ELAPSED : display.time = TRACK_REMAIN; + gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.plstrkdn_pixmap, + display.plstrkdn_mask ); + break; + + case TRACK_REMAIN : display.time = CD_ELAPSED; + gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.mnstrkdn_pixmap, + display.mnstrkdn_mask ); + break; + + case CD_ELAPSED : display.time = CD_REMAIN; + gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.plscddn_pixmap, + display.plscddn_mask ); + break; + + case CD_REMAIN : display.time = TRACK_ELAPSED; + gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.mnscddn_pixmap, + display.mnscddn_mask ); + break; + } + } +} + + +void tdisp_release (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + switch( display.time ) + { + case TRACK_ELAPSED : gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.plstrkup_pixmap, + display.plstrkup_mask ); + break; + + case TRACK_REMAIN : gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.mnstrkup_pixmap, + display.mnstrkup_mask ); + break; + + case CD_ELAPSED : gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.plscdup_pixmap, + display.plscdup_mask ); + break; + + case CD_REMAIN : gtk_pixmap_set( GTK_PIXMAP( tdisp.wid ), + display.mnscdup_pixmap, + display.mnscdup_mask ); + break; + } + } +} + + +void rpt_press (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + gtk_pixmap_set( GTK_PIXMAP( rpt.wid ), + rpt.image.dn_pixmap, + rpt.image.dn_mask ); + + if( display.repeat == 0 ) + display.repeat = 1; + else + display.repeat = 0; + } +} + + +void rpt_release (GtkWidget *widget, GdkEventButton *event) +{ + if( event->button == 1 ) + { + if( display.repeat == 0 ) + { + gtk_pixmap_set( GTK_PIXMAP( rpt.wid ), + rpt.image.up_pixmap, + rpt.image.up_mask ); + } else { + gtk_pixmap_set( GTK_PIXMAP( rpt.wid ), + display.rptupact_pixmap, + display.rptupact_mask ); + } + } +} + + +void vol_press (GtkWidget *widget, GdkEventButton *event) +{ + switch( event->button ) + { + case 1 : gtk_pixmap_set( GTK_PIXMAP( vol.wid ), + vol.image.dn_pixmap, + vol.image.dn_mask ); + set_vol( +10 ); + update_display(); + break; + + case 3 : gtk_pixmap_set( GTK_PIXMAP( vol.wid ), + vol.image.dn_pixmap, + vol.image.dn_mask ); + set_vol( -10 ); + update_display(); + break; + + } +} + +void vol_release (GtkWidget *widget, GdkEventButton *event) +{ + if( (event->button == 1) || (event->button == 3) ) + { + gtk_pixmap_set( GTK_PIXMAP( vol.wid ), + vol.image.up_pixmap, + vol.image.up_mask ); + } +} + +/* ----------------------------------------------------------------------------------------- + Show the track title listbox, allow editing of it. Hilight the current track. Show + total time for each track. Show discid for the CD. Allow sending to CDDB. + ----------------------------------------------------------------------------------------- */ +gint show_tracks( ) +{ + + return FALSE; +} + + +/* ----------------------------------------------------------------------- + Redraw the uncovered part of the display + ----------------------------------------------------------------------- */ +static int expose_display( GtkWidget *widget, GdkEventExpose *event ) +{ + switch( display.status ) + { + case CDROM_PLAYING : gdk_draw_pixmap (widget->window, + widget->style->black_gc, + display.null_pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + break; + + case CDROM_NODISC : gdk_draw_pixmap (widget->window, + widget->style->black_gc, + display.nodisc_pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + break; + } + + return FALSE; +} + + + + + +/* ----------------------------------------------------------------------- + Update the cdrom status and the display + + This routine is called once per second to check for the end of the CD + and to update the display. + ----------------------------------------------------------------------- */ +gint update_cdrom( gpointer data ) +{ + /* Get the latest info into cdinfo structure */ + cdrom_status(); + + return TRUE; +} + + +/* ----------------------------------------------------------------------- + Draw the current track # onto the null_pixmap and then copy the + pixmap to the display + ----------------------------------------------------------------------- */ +void draw_track() +{ + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.a_pixmap[display.track/10], + 0, 0, + 2, 2, 11, 22 ); + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.a_pixmap[display.track%10], + 0, 0, + 15, 2, 11, 22 ); + + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.null_pixmap, + 0, 0, + 0, 0, 92, 30 ); +} + + +/* ----------------------------------------------------------------------- + Draw the minute digits onto the null_pixmap and then copy the + pixmap to the display. Also draws the minus sign if needed. + ----------------------------------------------------------------------- */ +void draw_minute() +{ + /* Show or don't show the minus sign */ + if((display.minute<0) || (display.second<0)) + { + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.minus_pixmap, + 0, 0, + 32, 10, 8, 16 ); + } else { + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[10], + 0, 0, + 32, 10, 8, 16 ); + } + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[abs(display.minute)/10], + 0, 0, + 42, 10, 8, 16 ); + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[abs(display.minute)%10], + 0, 0, + 52, 10, 8, 16 ); + + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.null_pixmap, + 0, 0, + 0, 0, 92, 30 ); +} + + +/* ----------------------------------------------------------------------- + Draw the second digits onto the null_pixmap and then copy the + pixmap to the display. + ----------------------------------------------------------------------- */ +void draw_second() +{ + /* Show or don't show the minus sign */ + if((display.minute<0) || (display.second<0)) + { + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.minus_pixmap, + 0, 0, + 32, 10, 8, 16 ); + } else { + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[10], + 0, 0, + 32, 10, 8, 16 ); + } + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[abs(display.second/10)], + 0, 0, + 68, 10, 8, 16 ); + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[abs(display.second%10)], + 0, 0, + 78, 10, 8, 16 ); + + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.null_pixmap, + 0, 0, + 0, 0, 92, 30 ); +} + + +/* ----------------------------------------------------------------------- + Erase the minute digits and the minus sign. This is used by the blink + routine. + ----------------------------------------------------------------------- */ +void erase_minute() +{ + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[10], + 0, 0, + 32, 10, 8, 16 ); + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[10], + 0, 0, + 42, 10, 8, 16 ); + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[10], + 0, 0, + 52, 10, 8, 16 ); + + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.null_pixmap, + 0, 0, + 0, 0, 92, 30 ); +} + + +/* ----------------------------------------------------------------------- + Erase the second digits. This is used by the blink routine. + ----------------------------------------------------------------------- */ +void erase_second() +{ + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[10], + 0, 0, + 68, 10, 8, 16 ); + + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.b_pixmap[10], + 0, 0, + 78, 10, 8, 16 ); + + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.null_pixmap, + 0, 0, + 0, 0, 92, 30 ); +} + + +/* ----------------------------------------------------------------------- + Decide what to show on the display + If there is no disc, then show NO DISC bitmap + If playing then update the display digits + If paused then blink the time + + It keeps track of the previous states of things so only the areas that + have changed get updated each time. An improvement would be to only + update the digits that change (instead of both minute or both second + digits), but it isn't that important. + ----------------------------------------------------------------------- */ +void update_display() +{ + static int curr_track=-1, /* Default to unknown value */ + curr_minute=-1, + curr_second=-1, + curr_status=-1, + curr_volume=-1, + blinking=0, + tclist_track=-1; /* Track selected in tclist */ + + int x; + + /* + * If the volume needs updating then we draw a bargraph, one bar for + * every 17 volume units. 15 bars maximum with the last 5 being red + */ + if( curr_volume != cdinfo.volume ) + { + for( x = 0; x < (cdinfo.volume / 17); x++ ) + { + if( x < 10 ) + { + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.bar_pixmap, + 0, 0, + 30+(x*4), 1, 4, 7 ); + } else { + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.redbar_pixmap, + 0, 0, + 30+(x*4), 1, 4, 7 ); + } + } + for( ; x < 15; x++ ) + { + gdk_draw_pixmap( display.null_pixmap, + display.wid->style->black_gc, + display.nobar_pixmap, + 0, 0, + 30+(x*4), 1, 4, 7 ); + } + + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.null_pixmap, + 0, 0, + 0, 0, 92, 30 ); + + curr_volume = cdinfo.volume; + } + + switch( display.time ) + { + case TRACK_ELAPSED : + display.minute = cdinfo.sc.cdsc_reladdr.msf.minute; + display.second = cdinfo.sc.cdsc_reladdr.msf.second; + break; + + case TRACK_REMAIN : + display.minute = 0 - ( (cdinfo.track[display.track-1].length/60) - cdinfo.sc.cdsc_reladdr.msf.minute); + display.second = 0 - ( (cdinfo.track[display.track-1].length%60) - cdinfo.sc.cdsc_reladdr.msf.second); + break; + + case CD_ELAPSED : + display.minute = cdinfo.sc.cdsc_absaddr.msf.minute; + display.second = cdinfo.sc.cdsc_absaddr.msf.second; + break; + + case CD_REMAIN : + display.minute = 0-cdinfo.cd_remaining/60; + display.second = 0-cdinfo.cd_remaining%60; + break; + } + + + switch( display.status ) + { + case CDROM_PLAYING : if( display.track != curr_track ) + { + draw_track(); + + curr_track = display.track; + } + + if( display.minute != curr_minute ) + { + draw_minute(); + + curr_minute = display.minute; + } + + if( display.second != curr_second ) + { + draw_second(); + + curr_second = display.second; + } + curr_status = display.status; + + if( display.playbtn != CDROM_PLAYING ) + { + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.playup_pixmap, + display.playup_mask ); + + display.playbtn = CDROM_PLAYING; + } + + /* If the track window is open, update selected track */ + if( display.twindow != NULL ) + { + if( tclist_track+1 != curr_track ) + { + if( curr_track > 0 ) + tclist_track = curr_track -1; + else + tclist_track = 0; + gtk_clist_select_row( GTK_CLIST(display.tclist), tclist_track, -1 ); + } + } + + break; + + /* Flash the min/sec digits while paused */ + case CDROM_PAUSED : if( display.track != curr_track ) + { + draw_track(); + + curr_track = display.track; + } + + + if( blinking ) + { + draw_second(); + draw_minute(); + blinking=0; + } else { + erase_second(); + erase_minute(); + curr_second = -1; + curr_minute = -1; + blinking=1; + } + + if( display.playbtn != CDROM_PAUSED ) + { + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.pauseup_pixmap, + display.pauseup_mask ); + display.playbtn = CDROM_PAUSED; + } + break; + + /* Display NO DISC */ + case CDROM_NODISC : if( curr_status != display.status ) + { + gdk_draw_pixmap( display.wid->window, + display.wid->style->black_gc, + display.nodisc_pixmap, + 0, 0, + 0, 0, 92, 30 ); + + curr_status = display.status; + } + + if( display.playbtn != CDROM_NODISC ) + { + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.stopup_pixmap, + display.stopup_mask ); + display.playbtn = CDROM_NODISC; + } + + break; + } + +#ifdef DEBUG4 + g_print( "update called. status = %d remain = %d\n", display.status, cdinfo.cd_remaining ); + g_print( " curr new\n"); + g_print( "track %03d : %03d\n", curr_track, display.track ); + g_print( "minute %03d : %03d\n", curr_minute, display.minute ); + g_print( "second %03d : %03d\n", curr_second, display.second ); + g_print( "volume %03d : %03d\n", curr_volume, cdinfo.volume ); +#endif + +} + + +/* ------------------------------------------------------------------------ + Process data coming back from the cd_control process + + This is a stateless process since it only returns a cdinfo structure + ------------------------------------------------------------------------ */ +void wait_status() +{ + struct CDINFO tmpinfo; + struct SITE *sp; + char buffer[80]; + int x; + char *texts[3], + text1[255], + text2[255]; + + + /* Read the new cdinfo structure from the cd_control process */ + if( read( cd_fd, &tmpinfo, sizeof(struct CDINFO) ) < 0 ) + perror("cdrom_status(read)"); + + /* Copy the useful bits from tmpinfo to cdinfo */ + memcpy( &cdinfo.tochdr, &tmpinfo.tochdr, sizeof(tmpinfo.tochdr) ); + memcpy( &cdinfo.leadout, &tmpinfo.leadout, sizeof(tmpinfo.leadout) ); + memcpy( &cdinfo.volume, &tmpinfo.volume, sizeof(tmpinfo.volume) ); + + /* Copy track length, but not the track name over from the status */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + cdinfo.track[x].te = tmpinfo.track[x].te; + cdinfo.track[x].length = tmpinfo.track[x].length; + cdinfo.track[x].frame_offset = tmpinfo.track[x].frame_offset; + } + + memcpy( &cdinfo.sc, &tmpinfo.sc, sizeof(tmpinfo.sc) ); + memcpy( &cdinfo.ti, &tmpinfo.ti, sizeof(tmpinfo.ti) ); + cdinfo.cd_length = tmpinfo.cd_length; + cdinfo.discid = tmpinfo.discid; + + switch( cdinfo.sc.cdsc_audiostatus ) + { + case CDROM_AUDIO_PLAY : + case CDROM_AUDIO_PAUSED : + if( cdinfo.sc.cdsc_audiostatus == CDROM_AUDIO_PLAY ) + display.status = CDROM_PLAYING; + else + display.status = CDROM_PAUSED; + + /* Update the currently playing track */ + display.track = cdinfo.sc.cdsc_trk; + + /* Update the number of seconds remaining on the CD */ + cdinfo.cd_remaining = cdinfo.cd_length - ((cdinfo.sc.cdsc_absaddr.msf.minute*60)+cdinfo.sc.cdsc_absaddr.msf.second); + + /* Do we need track data? Can we request it? */ + if( (display.cddb_lock == 0) && (cdinfo.revision == -1)) + { + if( config.cddb == 1 ) + { +#ifdef DEBUG9 + g_print("reading cddb info %d\n", cdinfo.revision ); +#endif + /* Try and find a cddb entry in the local CD database */ + if( read_cddb( &cdinfo ) < 0 ) + { + /* Default server to query */ + strcpy( cdinfo.server, "cddb.cddb.com" ); + cdinfo.port = 888; + + /* So here we query the default internet server */ + if( config.current != NULL ) + { + /* Use the current + 888 even if not found in the list */ + strcpy( cdinfo.server, config.current ); + + /* Find the current server in the list */ + sp = config.server; + while( sp != NULL ) + { + if( strcmp( sp->name, config.current ) == 0 ) + { + strcpy( cdinfo.server, sp->name ); + cdinfo.port = sp->port; + sp = NULL; + }else { + sp = sp->next; + } + } + } + /* Send the command to the server - Starts a state machine */ + cdinfo.cddbd_cmnd = DB_READ; + if( write( cddbd_fd, &cdinfo, sizeof( struct CDINFO) ) < 0 ) + { + perror("write to cddbd_fd error"); + if( cdinfo.revision < 0 ) + cdinfo.revision = -2; /* Failed, Don't try again */ + } + /* Lock the use of the internet database */ + display.cddb_lock = 1; + + /* !!!! This could probably be turned into a subroutine + !!!! */ + + /* Start up a progress dialog */ + display.progress = gtk_dialog_new (); + + sprintf(buffer, "Connecting to %s:%d", cdinfo.server, + cdinfo.port ); + + gtk_signal_connect( GTK_OBJECT( display.progress ), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + &display.progress); + + gtk_window_set_title (GTK_WINDOW (display.progress), "CDDBD Status"); + gtk_container_border_width (GTK_CONTAINER (display.progress), 0); + gtk_window_set_wmclass(GTK_WINDOW(display.progress), "XfreeCDp", NULL ); + + display.plabel = gtk_label_new (buffer); + gtk_misc_set_padding (GTK_MISC (display.plabel), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->vbox), + display.plabel, FALSE, FALSE, 0); + gtk_widget_show( display.plabel ); + gtk_widget_show( display.progress ); + } else { + /* Read of local database successful */ +#ifdef DEBUG5 + g_print("Title : %s\n", cdinfo.title->str ); + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + g_print("Track %d : %s\n", x+1, cdinfo.name[x]->str ); + } +#endif + } + } else { + /* Read the data from the local database, or set defaults */ + local_cddb(); + } + + /* If the track list window is open, update the list */ + if( display.twindow != NULL ) + { +#ifdef DEBUG9 + g_print("Updating Track Window revision=%d\n", cdinfo.revision); +#endif + + gtk_clist_freeze (GTK_CLIST (display.tclist)); + + /* Clear out the old list first */ + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Set the new title */ + if( cdinfo.title != NULL ) + sprintf( text1, "%s", cdinfo.title->str ); + else + strcpy( text1, "" ); + gtk_label_set( GTK_LABEL( display.ttitle ), text1 ); + + /* Add the track names */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + sprintf( text1, "%d", x+1 ); + sprintf( text2, "%d:%02d",cdinfo.track[x].length/60,cdinfo.track[x].length%60 ); + texts[0] = text1; + texts[2] = text2; + if( cdinfo.name[x] != NULL ) + texts[1] = cdinfo.name[x]->str; + else + texts[1] = "(blank)"; + gtk_clist_append (GTK_CLIST (display.tclist), texts); + } + gtk_clist_thaw( GTK_CLIST( display.tclist ) ); + gtk_clist_select_row( GTK_CLIST(display.tclist), display.track-1, -1 ); + } + } + break; + +#ifdef OLD_WAY + case CDROM_AUDIO_PAUSED : + display.status = CDROM_PAUSED; + break; +#endif + + case CDROM_AUDIO_NO_STATUS : + /* Only clean things up once */ + if( display.status != CDROM_NODISC ) + { + /* Clear out the track list */ + if( display.twindow != NULL ) + { + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Clear the title */ + gtk_label_set( GTK_LABEL( display.ttitle ), "" ); + } + + /* Free dynamically allocated cdinfo strings */ + free_cdinfo(); + + display.status = CDROM_NODISC; + /* Reset the revision # so next will recall from database*/ + cdinfo.revision = -1; + } + break; + + default: + /* Only cleanup once */ + if( display.status != CDROM_NODISC ) + { + /* Clear out the track list */ + if( display.twindow != NULL ) + { + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Clear the title */ + gtk_label_set( GTK_LABEL( display.ttitle ), "" ); + } + + /* Free dynamically allocated cdinfo strings */ + free_cdinfo(); + + display.status = CDROM_NODISC; + cdinfo.revision = -1; + } + break; + } + + + /* + * If the CD is over then either restart it, or eject it, or show NO DISC + */ + if( (cdinfo.cd_remaining == 0) && (display.status == CDROM_PLAYING) ) + { + /* If repeat is on, start playing the cd over from the start */ + if( display.repeat == 1 ) + { + display.track = cdinfo.tochdr.cdth_trk0; + play_track( cdinfo.tochdr.cdth_trk0 ); + } else { + /* Clear out the track list */ + if( display.twindow != NULL ) + { + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Clear the title */ + gtk_label_set( GTK_LABEL( display.ttitle ), "" ); + } + + /* Free up any dynamically allocated cdinfo strings */ + free_cdinfo(); + + /* Eject when done Playing - only eject if the user has enabled this */ + if( config.done_eject == 1 ) + { + /* All done, eject it for the next disc! */ + eject_cdrom(); + } else { + stop_cdrom(); + } + + gtk_pixmap_set( GTK_PIXMAP( play.wid ), + display.stopup_pixmap, + display.stopup_mask ); + display.playbtn = CDROM_NODISC; + } + } +} + + +/* ------------------------------------------------------------------------- + Process data coming back from the cd_control process + + This is a stateless process since it only returns a cdinfo structure + ------------------------------------------------------------------------- */ +void cd_fd_read( gpointer data, gint source, GdkInputCondition condition) +{ + wait_status(); + + if( display.startup == 0 ) + { + if( config.startup == 1 ) + { + /* If it is already playing, don't restart it */ + if( ( cdinfo.sc.cdsc_audiostatus != CDROM_AUDIO_PLAY ) && + (cdinfo.discid != 0 ) ) + { +#ifdef DEBUG6 + g_print("Starting play of cd. audiostatus = %d\n", cdinfo.sc.cdsc_audiostatus ); +#endif + play_track( 1 ); + } + } + + /* Stop trying after the discid gets set by cd_control process */ + if( cdinfo.discid != 0 ) + display.startup = 1; + } + + update_display(); +} + + +/* ------------------------------------------------------------------------ + this is the signal handler that gets called if GtkList + emits the "selection_changed" signal + ------------------------------------------------------------------------ */ +void inexact_selected( GtkWidget *gtklist, gpointer func_data) +{ + char *p, + buffer[80]; + GList *dlist; + GtkObject *list_item; + gchar *item_data_string; + + + /* fetch the doubly linked list of selected items + * of the GtkList, remember to treat this as read-only! + */ + dlist=GTK_LIST(gtklist)->selection; + + /* if there are no selected items there is nothing more + * to do than just telling the user so + */ + if (dlist) + { + list_item=GTK_OBJECT(dlist->data); + item_data_string=gtk_object_get_data(list_item, + "XfreeCDkey"); + p = strtok( item_data_string, " \n" ); + p = strtok( NULL, " \n" ); + +#ifdef DEBUG3 + g_print("Retrieving data for %s\n", p); +#endif + + /* Change the discid so the new request will work */ + sscanf( p, "%lx", &cdinfo.discid ); + cdinfo.cddbd_cmnd = DB_READ; + if( write( cddbd_fd, &cdinfo, sizeof( struct CDINFO) ) < 0 ) + { + perror("write to cddbd_fd error"); + if( cdinfo.revision < 0 ) + cdinfo.revision = -2; /* Failed, Don't try again */ + } + /* Lock use of the CDDB internet server */ + display.cddb_lock = 1; + + /* Delete the old progress box */ + gtk_widget_destroy( display.progress ); + display.plabel = NULL; + + /* Start up a new progress dialog */ + display.progress = gtk_dialog_new (); + + sprintf(buffer, "Connecting to %s:%d", cdinfo.server, cdinfo.port ); + + gtk_signal_connect( GTK_OBJECT( display.progress ), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + &display.progress); + + gtk_window_set_title (GTK_WINDOW (display.progress), "CDDBD Status"); + gtk_container_border_width (GTK_CONTAINER (display.progress), 0); + gtk_window_set_wmclass(GTK_WINDOW(display.progress), "XfreeCDp", NULL ); + + display.plabel = gtk_label_new (buffer); + gtk_misc_set_padding (GTK_MISC (display.plabel), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->vbox), + display.plabel, FALSE, FALSE, 0); + gtk_widget_show( display.plabel ); + gtk_widget_show( display.progress ); + } else { + gtk_widget_destroy( display.progress ); + display.plabel = NULL; + } +} + + + + +/* ------------------------------------------------------------------------- + Process data coming back from the cddbd process + + This routine processes data from the pipe to the cddbd process. This gets + the track names and site list from the server. + ------------------------------------------------------------------------- */ +void cddbd_fd_read( gpointer data, gint source, GdkInputCondition condition) +{ + struct CDINFO tmpinfo; + int x; + static struct SITE *sp, + *sp_top=NULL, + *sp_end=NULL; + char *p, buffer[80]; + gchar *string; + GtkWidget *button, + *scrolled_win, + *list, + *vbox1, + *label; + static GList *cbitems=NULL; + char *texts[3], + text1[255], + text2[255]; + + + /* Read back the status structure */ + if( read( cddbd_fd, &tmpinfo, sizeof( struct CDINFO ) ) != sizeof( struct CDINFO ) ) + { + perror( "CDDBD status read" ); + close( cd_fd ); + close( cddbd_fd ); + exit(-1); + } + + switch( tmpinfo.cddbd_stat ) + { + case CDDBD_OPEN_OK : +#ifdef DEBUG3 + g_print("Connected to %s ok\n", tmpinfo.server ); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Connected to %s:%d", tmpinfo.server, tmpinfo.port); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + break; + + case CDDBD_DONE_OK : + display.cddb_lock = 0; + + /* Copy the info from the tmpinfo to cdinfo */ +#ifdef DEBUG3 + g_print("Got the new data ok\n"); + g_print("tmpinfo.title->str = 0x%X\n", tmpinfo.title->str ); +#endif + +#ifdef DUMB + if( display.plabel != NULL ) + { + sprintf (buffer, "Retrieved %s", tmpinfo.title->str ); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } +#endif + + gtk_widget_destroy( display.progress ); + display.plabel = NULL; + + /* Read the new data from the database */ + local_cddb(); + + /* If the track list window is open, update the list */ + if( display.twindow != NULL ) + { + gtk_clist_freeze (GTK_CLIST (display.tclist)); + + /* Clear out the old list first */ + gtk_clist_clear( GTK_CLIST( display.tclist ) ); + + /* Set the new title */ + if( cdinfo.title != NULL ) + sprintf( text1, "%s", cdinfo.title->str ); + else + strcpy( text1, "" ); + gtk_label_set( GTK_LABEL( display.ttitle ), text1 ); + + /* Add the track names */ + for( x = 0; x < cdinfo.tochdr.cdth_trk1; x++ ) + { + sprintf( text1, "%d", x+1 ); + sprintf( text2, "%d:%02d",cdinfo.track[x].length/60,cdinfo.track[x].length%60 ); + texts[0] = text1; + texts[2] = text2; + if( cdinfo.name[x] != NULL ) + texts[1] = cdinfo.name[x]->str; + else + texts[1] = "(blank)"; + gtk_clist_append (GTK_CLIST (display.tclist), texts); + } + gtk_clist_thaw( GTK_CLIST( display.tclist ) ); + gtk_clist_select_row( GTK_CLIST(display.tclist), display.track-1, -1 ); + } + break; + + /* Process the line of text */ + case CDDBD_MOTD_LINE : + + if( tmpinfo.line[0] == '.' ) + { + display.cddb_lock = 0; +#ifdef DEBUG3 + g_print("End of MOTD\n"); +#endif + + gtk_widget_destroy( display.progress ); + display.plabel = NULL; + + } else { +#ifdef DEBUG3 + /* Do something with the MOTD, for now print it */ + g_print( "%s", tmpinfo.line ); +#endif + + if( display.plabel != NULL ) + { + gtk_label_set (GTK_LABEL (display.plabel), tmpinfo.line); + } + } + break; + + /* Process the line of text */ + case CDDBD_SITE_LINE : + + if( tmpinfo.line[0] == '.' ) + { + display.cddb_lock = 0; +#ifdef DEBUG3 + g_print("End of Site listing\n"); +#endif + if( display.plabel != NULL ) + { + sprintf (buffer, "Retrieved Site Listing ok" ); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + if( sp_top != NULL ) + { + /* Everything seems okay, erase the old list and add the new one */ + while( config.server != NULL ) + { + sp = config.server; + config.server = config.server->next; + free( sp->name ); + free( sp ); + } + + /* Point config to the new list */ + config.server = sp_top; + sp_top = sp_end = NULL; + + config.saved = 0; /* Need to save this to disk */ + write_config( &config ); /* Write new list to disk */ + strncpy( cdinfo.device, config.device, 80 ); + + /* Need to let the site list in the dialog box be updated if it is + still being shown (user could close it before we finish). + */ + if( display.cb != NULL ) + { + + /* Walk the list */ + cbitems = NULL; + sp = config.server; + while( sp != NULL ) + { + cbitems = g_list_append(cbitems, sp->name); + sp = sp->next; + } + + gtk_combo_set_popdown_strings (GTK_COMBO (display.cb), cbitems); + cbitems = NULL; + } + + } + gtk_widget_destroy( display.progress ); + display.plabel = NULL; + + } else { + /* Do something with the SITE, for now print it */ + /* Need to store in a temp. List until complete, then move to config */ +#ifdef DEBUG3 + g_print( "%s", tmpinfo.line ); +#endif + + if( display.plabel != NULL ) + { + gtk_label_set (GTK_LABEL (display.plabel), tmpinfo.line); + } + + /* Reserve some space for this server, add it to the end of the list */ + if( ( sp = (struct SITE *) malloc( sizeof(struct SITE) ) ) == NULL ) + { + perror("malloc - 1"); + } + bzero( sp, sizeof(struct SITE) ); + + p = strtok( tmpinfo.line, " \n" ); + + /* Reserve space for the name */ + if( ( sp->name = (char *) malloc( strlen(p)+1 ) ) == NULL ) + { + perror("malloc - 2"); + } + strcpy( sp->name, p ); + + p = strtok( NULL, " \n" ); + sp->port = atoi(p); + sp->next = NULL; + + /* Is it the first in the list? */ + if( sp_top == NULL ) + { + /* Yep, First in the list */ + sp_top = sp; + sp_end = sp; + } else { + /* No, add it to the end of the list */ + sp_end->next = sp; + sp_end = sp; + } + } + break; + + + /* Process the line of text inexact matches */ + case CDDBD_INEX_LINE : + + if( tmpinfo.line[0] == '.' ) + { + cdinfo.revision = -2; + display.cddb_lock = 0; + +#ifdef DEBUG3 + g_print("End of Inexact Match listing\n"); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Retrieved inexact matches for discid 0x%08lx", cdinfo.discid ); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + /* Here we want to add a list of the sites to the progress box, + add a cancel button, and add a signal to use one of the inexact + matches in a new search. + */ + if( cbitems != NULL ) + { + /* Add a vbox to hold the list and cancel button */ + vbox1 = gtk_vbox_new( FALSE, 0 ); + gtk_box_pack_start( GTK_BOX (GTK_DIALOG (display.progress)->action_area), + vbox1, FALSE, TRUE, 1 ); + gtk_widget_show( vbox1 ); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_usize( scrolled_win, 250, 100 ); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX( vbox1 ), scrolled_win, FALSE, FALSE, 0); + gtk_widget_show (scrolled_win); + + /* Put a list into the scrolling window */ + list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_SINGLE); + gtk_container_add (GTK_CONTAINER (scrolled_win), list); + gtk_container_set_focus_vadjustment (GTK_CONTAINER (list), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_win))); + gtk_signal_connect(GTK_OBJECT(list), + "selection_changed", + GTK_SIGNAL_FUNC(inexact_selected), + NULL); + gtk_widget_show (list); + + /* Add the list of inexact matches to the list from cbitems */ + gtk_list_append_items( GTK_LIST( list ), cbitems ); + + button = gtk_button_new_with_label ("Cancel"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX( vbox1 ), button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + cbitems = NULL; + } else { + gtk_widget_destroy( display.progress ); + display.plabel = NULL; + } + } else { + /* Need to store in a temp. List until we receive the last line */ +#ifdef DEBUG3 + g_print( "%s", tmpinfo.line ); +#endif + + /* Show the line in the progress box */ + if( display.plabel != NULL ) + { + gtk_label_set (GTK_LABEL (display.plabel), tmpinfo.line); + } + + /* Add it to a list of sites */ + /* Need to detect first line of this type and set cbitems to NULL, or else + set it to null when everything else is finished with it. + */ + if( tmpinfo.line[strlen(tmpinfo.line)-1] == '\n' ) + { + tmpinfo.line[strlen(tmpinfo.line)-1] = 0x00; + } + + button=gtk_list_item_new(); + label=gtk_label_new( tmpinfo.line ); + gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5); + gtk_container_add (GTK_CONTAINER (button), label); + gtk_widget_show (label); + gtk_widget_show(button); + gtk_label_get(GTK_LABEL(label), &string); + gtk_object_set_data(GTK_OBJECT(button), + "XfreeCDkey", + string); + cbitems = g_list_append(cbitems, button); + + } + break; + + + + case CDDBD_MATCH_OK : +#ifdef DEBUG3 + g_print("Got a match for 0x%08lx\n", tmpinfo.discid ); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Retrieving data for id 0x%08lx", tmpinfo.discid); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + break; + + case CDDBD_ENTRY_OK : +#ifdef DEBUG3 + g_print("Reading CDDB Database entry from %s\n", tmpinfo.server ); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Reading CDDB info from %s", tmpinfo.server); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + break; + + case CDDBD_DONE_ERR : + cdinfo.revision = -2; + display.cddb_lock = 0; + + +#ifdef DEBUG3 + g_print("Error reading temporary file\n"); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Error Reading temp. file"); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + break; + + case CDDBD_OPEN_ERR : + cdinfo.revision = -2; + display.cddb_lock = 0; + +#ifdef DEBUG3 + g_print("Failed to connect to %s\n", tmpinfo.server ); + g_print("%s\n", tmpinfo.line ); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Failed to connect to %s", tmpinfo.server ); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + break; + + case CDDBD_READ_ERR : + cdinfo.revision = -2; + display.cddb_lock = 0; + +#ifdef DEBUG3 + g_print("Socket read failed\n"); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Socket Read Failed"); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + break; + + case CDDBD_WRITE_ERR : + cdinfo.revision = -2; + display.cddb_lock = 0; + +#ifdef DEBUG3 + g_print("Socket write failed\n"); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Socket Write Failed"); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + break; + + case CDDBD_TMPF_ERR : + cdinfo.revision = -2; + display.cddb_lock = 0; + +#ifdef DEBUG3 + g_print("Error, cannot create a temporary filename\n"); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Cannot Create temp. file"); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + break; + + case CDDBD_FOPEN_ERR : + cdinfo.revision = -2; + display.cddb_lock = 0; + +#ifdef DEBUG3 + g_print("Error opening temporary file\n"); +#endif + + if( display.plabel != NULL ) + { + sprintf (buffer, "Error opening temp. file"); + gtk_label_set (GTK_LABEL (display.plabel), buffer); + } + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + break; + + default: + cdinfo.revision = -2; + display.cddb_lock = 0; + +#ifdef DEBUG3 + g_print("Server returned %d\n", tmpinfo.cddbd_stat ); +#endif + + if( display.plabel != NULL ) + { + sprintf( buffer, "Server: %s", tmpinfo.line ); + gtk_label_set (GTK_LABEL (display.plabel), buffer ); + } + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (display.progress)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (display.progress)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + break; + } +} + + +/* ----------------------------------------------------------------------- + Get the current status of the cdrom and fill in the display info + + return -1 = error writing + ----------------------------------------------------------------------- */ +int cdrom_status() +{ + /* Get the status of the cd */ + cmnd[0] = CD_STATUS; + cmnd[1] = 0; + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + return(-1); + } + + return 0; +} + + +/* ----------------------------------------------------------------------- + Play a track + ----------------------------------------------------------------------- */ +void play_track( int track ) +{ + /* Start Playing right away */ + cmnd[0] = CD_PLAY; + cmnd[1] = track; + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Play the next track + ----------------------------------------------------------------------- */ +void play_next() +{ + cmnd[0] = CD_PLAY; + cmnd[1] = display.track == cdinfo.tochdr.cdth_trk1 ? display.track = cdinfo.tochdr.cdth_trk0 : ++display.track; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Play the previous track + ----------------------------------------------------------------------- */ +void play_previous() +{ + cmnd[0] = CD_PLAY; + cmnd[1] = display.track == cdinfo.tochdr.cdth_trk0 ? display.track = cdinfo.tochdr.cdth_trk1 : --display.track; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Eject the cd tray if we are currently playing, otherwise start playing. + + This should really be seperated into 2 pieces of code for more positive + control over the cdrom. + ----------------------------------------------------------------------- */ +void eject_cdrom() +{ + cmnd[0] = CD_EJECT; + cmnd[1] = 0; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Pause the cdrom + ----------------------------------------------------------------------- */ +void pause_cdrom() +{ + cmnd[0] = CD_PAUSE; + cmnd[1] = 0; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Resume playing the cdrom + ----------------------------------------------------------------------- */ +void resume_cdrom() +{ + cmnd[0] = CD_RESUME; + cmnd[1] = 0; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Change the volume setting + + amount is +/- amount to adjust by + ----------------------------------------------------------------------- */ +void set_vol( int amount ) +{ + /* Limit the volume setting to 0 to 255 */ + cdinfo.volume += amount; + cdinfo.volume = cdinfo.volume < 0 ? 0 : cdinfo.volume > 255 ? 255 : cdinfo.volume; + + cmnd[0] = CD_VOLUME; + cmnd[1] = (unsigned char) cdinfo.volume; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Stop playing the cdrom + ----------------------------------------------------------------------- */ +void stop_cdrom() +{ + cmnd[0] = CD_STOP; + cmnd[1] = 0; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} + + +/* ----------------------------------------------------------------------- + Set the Eject CD on exit state + ----------------------------------------------------------------------- */ +void set_eject( int state ) +{ + cmnd[0] = CD_SET_EJECT; + cmnd[1] = state; + + if( write( cd_fd, &cmnd, 2 ) < 0 ) + { + perror("write to cd_control error"); + } +} diff --git a/xfreecd.gif b/xfreecd.gif Binary files differ. diff --git a/xfreecd.h b/xfreecd.h @@ -0,0 +1,34 @@ +/* ------------------------------------------------------------------------ + xfreecd include file for XfreeCD + + Copyright 1998 by Brian C. Lane + nexus@tatoosh.com + http://www.tatoosh.com/nexus + + ------------------------------------------------------------------------ */ +#define DEFAULT_CDDB_PATH "~/.cddb" +#define DEFAULT_SERVER "cddb.cddb.com" +#define DEFAULT_DEVICE "/dev/cdrom" +#define DEFAULT_TO_CDDBD "xmcd-cddb@amb.org" +#define MAIL_BINARY "mail" + + +struct SITE { + char *name; + int port; + struct SITE *next; +}; + +struct CONFIG { + char *device; /* CD device to use */ + char *local_cddb; + char *current; /* Current server name */ + char *to_cddbd; /* Server to send to */ + struct SITE *server; + short done_eject; /* Eject when play is finished */ + short exit_eject; /* Eject on Exit when not playing */ + short startup; /* What should we do at startup? See STARTUP_* */ + short cddb; /* Is cddb support enabled? */ + short changer; /* Is IDE CD changer support enabled? */ + short saved; /* Saved state. 1 = saved, 0 = needs to be saved */ +}; diff --git a/xfreecd.lsm b/xfreecd.lsm @@ -0,0 +1,21 @@ + +Begin3 +Title: XfreeCD +Version: 0.7.8 +Entered-date: 02DEC98 +Description: XfreeCD is a CD player for X written with GTK+ + It supports CDDB database info, and can submit new CD + info to the CDDB database. +Keywords: XfreeCD,CD player,Audio,CDROM,sound,X,GTK+ +Author: nexus@tatoosh.com (Brian Lane) +Maintained-by: nexus@tatoosh.com (Brian Lane) +Primary-site: ftp.tatoosh.com /linux + 669 xfreecd-0.7.8.lsm + 120464 xfreecd-0.7.8.tar.gz + 54867 xfreecd-0.7.8-1.i386.rpm + 121588 xfreecd-0.7.8-1.src.rpm +Alternate-site: sunsite.unc.edu /pub/Linux/X11/utils +Original-site: +Platforms: GTK+ v1.0.2 or later +Copying-policy: GPL +End diff --git a/xfreecd.sig b/xfreecd.sig Binary files differ. diff --git a/xfreecd.spec b/xfreecd.spec @@ -0,0 +1,36 @@ +Summary: Xfreecd, a CD player with CDDB features +Name: xfreecd +Version: 0.7.8 +Release: 1 +Copyright: GPL +Group: X11/Utilities +Source: http://www.tatoosh.com/nexus/linux/xfreecd-0.7.8.tar.gz +URL: http://www.tatoosh.com/nexus/xfreecd.shtml +Packager: nexus@tatoosh.com +Icon: xfreecd.gif +Prefix: /usr/local +Buildroot: /var/tmp/xfreecd-0.7.8 +Requires: libm.so.5 + +%description + XfreeCD is a X windows program written using GTK+ that looks like the +frontpanel of a cd player. It also supports the CDDB database of CD track +information, and is certified for submitting new CD information to the +database. At 137x90 it takes up a small amount of screen space. + +%prep +%setup + +%build +make + +%install +install -d -m 755 -o 0 -g 0 $RPM_BUILD_ROOT/usr/local/bin/ +install -s -m 755 -o 0 -g 0 xfreecd $RPM_BUILD_ROOT/usr/local/bin/ +install -d -m 755 -o 0 -g 0 $RPM_BUILD_ROOT/etc/X11/wmconfig/ +install -m 644 -o 0 -g 0 xfreecd.wmconfig $RPM_BUILD_ROOT/etc/X11/wmconfig/xfreecd + +%files +%doc COPYING README HISTORY xfreecd.xpm xfreecd.gif +/usr/local/bin/xfreecd +/etc/X11/wmconfig/xfreecd diff --git a/xfreecd.wmconfig b/xfreecd.wmconfig @@ -0,0 +1,4 @@ +xfreecd name "XFreeCD" +xfreecd description "CD Player" +xfreecd exec "xfreecd &" +xfreecd group Utilities/Sound diff --git a/xfreecd.xpm b/xfreecd.xpm @@ -0,0 +1,341 @@ +/* XPM */ +static char * xfreecd_xpm[] = { +"48 48 290 2", +" c None", +". c #50E5F8", +"+ c #56E5F8", +"@ c #61E6F8", +"# c #65E5F8", +"$ c #6BE5F8", +"% c #6DE5F8", +"& c #64E5F8", +"* c #59E5F8", +"= c #47E4F8", +"- c #3FE4F8", +"; c #3CE4F7", +"> c #38E3F7", +", c #35E3F7", +"' c #24E1F7", +") c #1FE1F7", +"! c #1CE1F7", +"~ c #19E1F7", +"{ c #18E1F7", +"] c #63E6F8", +"^ c #71E6F8", +"/ c #78E6F8", +"( c #9DE7F8", +"_ c #A3E8F8", +": c #76E6F8", +"< c #68E5F8", +"[ c #5BE5F8", +"} c #45E4F8", +"| c #3EE4F8", +"1 c #3AE4F7", +"2 c #37E3F7", +"3 c #33E3F7", +"4 c #25E1F7", +"5 c #1BE1F7", +"6 c #8AE6F8", +"7 c #8EE7F8", +"8 c #9AE7F8", +"9 c #A0E8F8", +"0 c #99E7F8", +"a c #8AE7F8", +"b c #86E6F8", +"c c #4BE5F8", +"d c #41E4F8", +"e c #20E1F7", +"f c #A7E8F8", +"g c #BEEBF9", +"h c #C8EDF9", +"i c #BCEBF9", +"j c #A4E8F8", +"k c #74E6F8", +"l c #60E5F8", +"m c #51E5F8", +"n c #44E4F8", +"o c #3DE4F7", +"p c #39E3F7", +"q c #1AE1F7", +"r c #DFF0FA", +"s c #EFF5FB", +"t c #97E7F8", +"u c #66E5F8", +"v c #55E5F8", +"w c #36E3F7", +"x c #32E3F7", +"y c #9FE8F8", +"z c #C7EDF9", +"A c #FFFEFE", +"B c #9DE8F8", +"C c #48E4F8", +"D c #2EE2F7", +"E c #31E3F7", +"F c #2CE2F7", +"G c #26E2F7", +"H c #2FE2F7", +"I c #2AE2F7", +"J c #24E2F7", +"K c #27E2F7", +"L c #22E1F7", +"M c #29E2F7", +"N c #3FE4F7", +"O c #34E3F7", +"P c #2FE3F7", +"Q c #2BE2F7", +"R c #25E2F7", +"S c #21E1F7", +"T c #1DE1F7", +"U c #22E2F7", +"V c #1EE1F7", +"W c #23E2F7", +"X c #2DE2F7", +"Y c #32E2F7", +"Z c #30E3F7", +"` c #28E2F7", +" . c #30E2F7", +".. c #45E4F7", +"+. c #2CE1F7", +"@. c #2BE1F7", +"#. c #4AF1FA", +"$. c #000000", +"%. c #17DFF4", +"&. c #17DFF5", +"*. c #17E0F6", +"=. c #14C7DA", +"-. c #0A646D", +";. c #0C747F", +">. c #17DAF0", +",. c #17DDF3", +"'. c #17DEF4", +"). c #32E1F5", +"!. c #30E0F5", +"~. c #1F281B", +"{. c #17DDF2", +"]. c #11AABC", +"^. c #17DCF2", +"/. c #14C4D8", +"(. c #11ACBD", +"_. c #77F5F9", +":. c #2ADEF3", +"<. c #1E8087", +"[. c #150B00", +"}. c #1A0E00", +"|. c #17DBF1", +"1. c #109CAB", +"2. c #0F909F", +"3. c #17D9EF", +"4. c #11A9BA", +"5. c #02181B", +"6. c #074850", +"7. c #0F92A0", +"8. c #1D1000", +"9. c #2297A0", +"0. c #37DDF0", +"a. c #21281B", +"b. c #241500", +"c. c #17D9EE", +"d. c #16D5EA", +"e. c #15CADD", +"f. c #042F33", +"g. c #16D6EB", +"h. c #043034", +"i. c #07484F", +"j. c #0F909E", +"k. c #1C0F00", +"l. c #120A00", +"m. c #33DAED", +"n. c #180E00", +"o. c #201200", +"p. c #16D4E9", +"q. c #16CFE3", +"r. c #16D2E7", +"s. c #07464D", +"t. c #0E8D9B", +"u. c #36D7E9", +"v. c #372100", +"w. c #16D1E5", +"x. c #15C6D9", +"y. c #010A0B", +"z. c #15CDE1", +"A. c #07454B", +"B. c #16D0E4", +"C. c #2ED2E4", +"D. c #29D1E3", +"E. c #142019", +"F. c #1C1706", +"G. c #091D13", +"H. c #17CCDF", +"I. c #15C8DB", +"J. c #14C3D6", +"K. c #04292D", +"L. c #15C5D8", +"M. c #074349", +"N. c #15CADE", +"O. c #12B3C5", +"P. c #30CDDE", +"Q. c #246462", +"R. c #091D17", +"S. c #1DCBDA", +"T. c #0B6C76", +"U. c #08525A", +"V. c #14C1D4", +"W. c #14BFD2", +"X. c #042A2E", +"Y. c #063F45", +"Z. c #12AEBF", +"`. c #042B30", +" + c #064148", +".+ c #11AEC0", +"++ c #021618", +"@+ c #02090B", +"#+ c #09297B", +"$+ c #16C1D4", +"%+ c #0D7E8A", +"&+ c #050100", +"*+ c #1C7B81", +"=+ c #08020D", +"-+ c #06000B", +";+ c #100C03", +">+ c #13B7C9", +",+ c #14BCCF", +"'+ c #13BACC", +")+ c #10A4B4", +"!+ c #021517", +"~+ c #031F22", +"{+ c #11A8B9", +"]+ c #063F46", +"^+ c #0D7F8C", +"/+ c #14BED1", +"(+ c #14BDD0", +"_+ c #000005", +":+ c #171C05", +"<+ c #101608", +"[+ c #178282", +"}+ c #114D41", +"|+ c #070E00", +"1+ c #040008", +"2+ c #110E05", +"3+ c #14BBCE", +"4+ c #13B8CA", +"5+ c #13B6C8", +"6+ c #13B4C6", +"7+ c #13B4C5", +"8+ c #10A0AF", +"9+ c #0D8693", +"0+ c #11A2B1", +"a+ c #13B9CB", +"b+ c #10A5B5", +"c+ c #0E919F", +"d+ c #16B5C7", +"e+ c #28BCC6", +"f+ c #1CB7C3", +"g+ c #1AB4C0", +"h+ c #1AB2BE", +"i+ c #19A7B0", +"j+ c #12AFC1", +"k+ c #13B5C7", +"l+ c #13B3C4", +"m+ c #12B0C1", +"n+ c #12AFC0", +"o+ c #13B2C3", +"p+ c #22B6C4", +"q+ c #1BB5C0", +"r+ c #19B1BE", +"s+ c #18AFBC", +"t+ c #17ACB9", +"u+ c #17ABB8", +"v+ c #12ADBE", +"w+ c #11A5B5", +"x+ c #11A7B8", +"y+ c #12B1C2", +"z+ c #21B2C0", +"A+ c #1DB3BD", +"B+ c #1AB1BC", +"C+ c #18AEBA", +"D+ c #14AAB9", +"E+ c #13A7B7", +"F+ c #14A7B5", +"G+ c #148A92", +"H+ c #12ACBD", +"I+ c #17ADBE", +"J+ c #16ACBF", +"K+ c #1CB3BC", +"L+ c #1AAFBA", +"M+ c #16ABB9", +"N+ c #13A8B8", +"O+ c #11A5B6", +"P+ c #13A5B4", +"Q+ c #16A5B2", +"R+ c #0F95A3", +"S+ c #11A6B6", +"T+ c #21B0BE", +"U+ c #1DB3BC", +"V+ c #1AB0BB", +"W+ c #18ADB9", +"X+ c #17A8B4", +"Y+ c #148083", +"Z+ c #14C3D7", +"`+ c #0F8E9B", +" @ c #1DB2C3", +".@ c #19B2BF", +"+@ c #1BB2BD", +"@@ c #19B0BC", +"#@ c #18AEBB", +"$@ c #18ACB8", +"%@ c #1AA7AF", +"&@ c #1AB3C7", +"*@ c #1EB8C2", +"=@ c #1AB3BF", +"-@ c #1AB1BD", +";@ c #1BB2BC", +">@ c #1EB3BB", +",@ c #0C717C", +" ", +" ", +" ", +" ", +" . + @ # $ % $ & * . = - ; > , ' ) ! ~ { { { { { { { { { ", +" ] ^ / ( _ ( : < [ . } | 1 2 3 4 ) 5 ~ { { { { { { { { ", +" % 6 7 8 9 0 a b < * c d ; > , e 5 ~ { { { { { { { { ", +" / 7 f g h i j a k l m n o p , ) q { { { { { { { { ", +" 8 g r s r i t 8 u v = | 1 w x e q { { { { { { { { ", +" y z s A s z B 9 < + C - 1 w x ~ { { { { { { { { ", +" t i r s r i t 8 u v = | 1 w x D { { { { { { { { ", +" j i z i j a k l m n o p , x D { { { { { { { ", +" a t B t a b < * c d ; > , E F G { { { { { { ", +" 8 9 8 k < [ . } | 1 2 3 H I J { { { { { ", +" u < u l * . = - ; > , x F K L { { { { ", +" v + v m c } - ; p w 3 D M J ) 5 { { { { ", +" C = n d | N p 2 O P Q R S T ~ { { { ", +" - | o ; 1 > w 3 P Q G U V 5 { { { { ", +" 1 p > 2 , x P Q K W ) ! ~ { { { ", +" w , , 3 E X I Y W ) ! ~ { { { { ", +" x Z D Q ` ...+.! q { { { { { ", +" F I ` G W e @.! ~ { { { { { { ", +" G J U e ) T 5 ~ { { { { { { { { ", +" ) V ! 5 ~ { { #.{ { { { { { { ", +" 5 q ~ { { { { { { { { { { { { { ", +" { { { { { { { { { { { { { { { ", +" $.$.$. %.&.&.*.*.*.*.{ { { { { =.-.$.;.$.$. $.$.$. $.$. ", +" $.$.$.$. >.,.'.'.'.&.&.&.&.&.).!.~.$.$.{.$.$. $.$.$. $.$.$. ", +" $.$.$. ].^.^.,./.(./.(._.:.<.[.}.$.|. $. $.$.$. $.$.$.$. ", +" $.$.$.$.$. $.$. $.$. 1.$.$. $.2.3.4.5.6.7.8.9.0.a.b.[.8.c.d. $.$.$. $.$.$.$. ", +" $.$. $.$. $.$.e.f.$.$. $.$.g.h.$.i.j.k.l.m.n.o.l.k.d.p. $.$.$. $.$.$.$. ", +" $.$. $.$. q.$.$.$. $.$.r.$.$.s.t.8.[.u.o.v.[.8.w.q.x. $.$.$. $.$.$.$. ", +" $.$. $.$. e.$.$.y. z.$.$.A.q.B.C.D.E.[.F.G.H.e.I. $.$.$. $.$.$.$. ", +" $.$. $.$. J./.$.$.K. L.$.$.M.N.N.O.P.Q.8.G.R.S./.T.U. $.$.$. $.$.$.$. ", +" $.$. $.$. V.W.X.$.Y. $.Z.`.$. +/./. +/..+++@+#+$+%+&+*+ =+-+=+ ;+&+$. ", +" $.$. $.$. >+,+'+)+K.!+~+$. {+X.!+]+]+^+/+(+{+X._+)+:+<+[+}+|+$.$.$.$.1+2+ ", +" 3+4+5+6+7+8+9+ 0+a+b+c+'+'+a+4+>+5+d+e+f+g+h+i+ ", +" j+a+k+l+m+n+n+m+ 6+k+k+k+6+6+7+l+o+p+q+r+s+t+u+ ", +" 3+>+l+m+n+v+v+Z.w+ x+o+o+o+y+y+m+n+z+A+B+C+D+E+F+G+ ", +" v+3+5+l+m+Z.H+H+H+v+ m+m+n+n+n+Z.I+J+K+L+M+N+O+P+Q+ ", +" V.,+4+7+y+n+Z.v+Z.Z.R+ S+m+n+n+n+Z.T+H+U+V+W+D+E+F+X+Y+ ", +" n+Z+/+'+5+7+o+y+m+m+y+y+ `+o+o+y+m+m+ @n+.@+@@@#@t+t+$@%@ ", +" I.x.V.(+'+>+5+6+6+6+6+k+7. y+6+6+7+l+&@l+o+*@q+g+=@-@;@>@,@ ", +" ", +" ", +" ", +" ", +" "}; diff --git a/xpm_button.c b/xpm_button.c @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------- + xpm button routines for XfreeCD + + Copyright 1998 by Brian C. Lane + ----------------------------------------------------------------------- */ +#include <gtk/gtk.h> +#include "xpm_button.h" + +/* Create a button with 2 xpm pixmaps for pressed and unpressed states */ +GtkWidget *xpm_button( GtkWidget *parent, struct _pbutton *pb ) +{ + GtkWidget *event_box; + GtkWidget *hbox; + GtkStyle *style; + + /* get style of button.. I assume it's to get the background color. + * if someone knows the real reason, please enlighten me. */ + style = gtk_widget_get_style( parent ); + + /* Make a hbox to hold the image */ + hbox = gtk_hbox_new( FALSE, 0 ); + gtk_container_border_width( GTK_CONTAINER( hbox ), 0 ); + + /* now on to the xpm stuff.. load xpm */ + pb->image.up_pixmap = gdk_pixmap_create_from_xpm_d (parent->window, + &pb->image.up_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) pb->up_xpm); + + pb->image.dn_pixmap = gdk_pixmap_create_from_xpm_d (parent->window, + &pb->image.dn_mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) pb->dn_xpm); + + /* Start with the up image */ + pb->wid = gtk_pixmap_new (pb->image.up_pixmap, pb->image.up_mask); + + gtk_box_pack_start (GTK_BOX (hbox), pb->wid, FALSE, FALSE, 0); + + gtk_widget_show(pb->wid); + + /* Create the event box that will hold the image and callbacks */ + event_box = gtk_event_box_new(); +/* gtk_container_add (GTK_CONTAINER(parent), event_box); + * gtk_widget_show (event_box); + */ + + /* Add the box containing the image to the button */ + gtk_container_add (GTK_CONTAINER (event_box), hbox); + + /* Make sure that the image is visible */ + gtk_widget_show( hbox ); + + /* Set the clipping size (this should come from the pixmap somehow) */ +/* gtk_widget_set_usize (hbox, 29, 30); */ + + /* Add the callback functions */ + gtk_widget_set_events( event_box, GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK ); + + gtk_signal_connect (GTK_OBJECT (event_box), "button_press_event", + GTK_SIGNAL_FUNC (pb->press), NULL ); + gtk_signal_connect (GTK_OBJECT (event_box), "button_release_event", + GTK_SIGNAL_FUNC (pb->release), NULL ); + + return( event_box ); +} diff --git a/xpm_button.h b/xpm_button.h @@ -0,0 +1,24 @@ +/* XPM Pushbutton structures */ + +struct _bstate +{ + GdkPixmap *up_pixmap; + GdkBitmap *up_mask; + GdkPixmap *dn_pixmap; + GdkBitmap *dn_mask; +}; + + +struct _pbutton +{ + GtkWidget *wid; /* Button's Widget ID */ + struct _bstate image; /* up and down images */ + int timer; + void (*press) (GtkWidget *widget, GdkEventButton *event); + void (*release) (GtkWidget *widget, GdkEventButton *event); + void (*clicked) (GtkWidget *widget, GdkEventButton *event); + gchar *up_xpm; + gchar *dn_xpm; +}; + +GtkWidget *xpm_button( GtkWidget *parent, struct _pbutton *pb );