# HG changeset patch # User leo_sobral # Date 1158792335 -3600 # Node ID ffdf467315ec951e1a30d48a902bb0fb20cb1538 # Parent 20b1f3062855fef06a97f16546cefd9c410ca70b [svn r2] imported to sf repository diff -r 20b1f3062855 -r ffdf467315ec gmyth/COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/COPYING Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -r 20b1f3062855 -r ffdf467315ec gmyth/ChangeLog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/ChangeLog Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,24 @@ +2006-08-17 Rosfran Borges + * Added the correct gstreamer-base package (GSTBASE) at the configure.ac; + GSTBASE_CFLAGS and GSTBASE_LIBS variables had the same values from + the GST_CFLAGS/GST_LIBS. + +2006-08-16 Rosfran Borges + * Fixed some installation issues, regarding lib-installing to the + correct directory, and copying the header files to the destination + dir (make install). + * Put 'pkg-config' resource to the Maemo Myth library. The name of the + PKG-CONFIG resource is 'maemo-myth', plus the minor and major version. + Actually, the version is '0.1', so the library config file is: + 'maemo-myth-0.1.pc'. You can type: 'pkg-config --cflags --libs + maemo-myth-0.1'. + * Many adjustments in the automake/autoconf configuration files + (configure.ac, Makefile.am) - some autotools misusage fixed. + * Added the MythURI structure, and the URI parsing utility functions + (missing in the GLib). + * Some functions were exported (myth_socket, mmyth_context), that's + why many ther modules need to use them. + * Fixed some library dependencies. + * Prepared to be used inside the GStreamer (linking with the MythTV + plug-in). + diff -r 20b1f3062855 -r ffdf467315ec gmyth/INSTALL --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/INSTALL Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff -r 20b1f3062855 -r ffdf467315ec gmyth/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/Makefile.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,23 @@ +SUBDIRS= src pixmaps + +### all of the standard pc files we need to generate +pcfiles = gmyth-@GMYTH_MAJORMINOR@.pc + +all-local: $(pcfiles) + +### how to generate pc files +%-@GMYTH_MAJORMINOR@.pc: %.pc + cp $< $@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcfiles) + +include aminclude.am + +EXTRA_DIST = \ + autogen.sh \ + gmyth.pc.in \ + AUTHORS \ + COPYING \ + README + diff -r 20b1f3062855 -r ffdf467315ec gmyth/aminclude.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/aminclude.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,186 @@ +# Copyright (C) 2004 Oren Ben-Kiki +# This file is distributed under the same terms as the Automake macro files. + +# Generate automatic documentation using Doxygen. Goals and variables values +# are controlled by the various DX_COND_??? conditionals set by autoconf. +# +# The provided goals are: +# doxygen-doc: Generate all doxygen documentation. +# doxygen-run: Run doxygen, which will generate some of the documentation +# (HTML, CHM, CHI, MAN, RTF, XML) but will not do the post +# processing required for the rest of it (PS, PDF, and some MAN). +# doxygen-man: Rename some doxygen generated man pages. +# doxygen-ps: Generate doxygen PostScript documentation. +# doxygen-pdf: Generate doxygen PDF documentation. +# +# Note that by default these are not integrated into the automake goals. If +# doxygen is used to generate man pages, you can achieve this integration by +# setting man3_MANS to the list of man pages generated and then adding the +# dependency: +# +# $(man3_MANS): doxygen-doc +# +# This will cause make to run doxygen and generate all the documentation. +# +# The following variable is intended for use in Makefile.am: +# +# DX_CLEANFILES = everything to clean. +# +# This is usually added to MOSTLYCLEANFILES. + +## --------------------------------- ## +## Format-independent Doxygen rules. ## +## --------------------------------- ## + +if DX_COND_doc + +## ------------------------------- ## +## Rules specific for HTML output. ## +## ------------------------------- ## + +if DX_COND_html + +DX_CLEAN_HTML = @DX_DOCDIR@/html + +endif DX_COND_html + +## ------------------------------ ## +## Rules specific for CHM output. ## +## ------------------------------ ## + +if DX_COND_chm + +DX_CLEAN_CHM = @DX_DOCDIR@/chm + +if DX_COND_chi + +DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi + +endif DX_COND_chi + +endif DX_COND_chm + +## ------------------------------ ## +## Rules specific for MAN output. ## +## ------------------------------ ## + +if DX_COND_man + +DX_CLEAN_MAN = @DX_DOCDIR@/man + +endif DX_COND_man + +## ------------------------------ ## +## Rules specific for RTF output. ## +## ------------------------------ ## + +if DX_COND_rtf + +DX_CLEAN_RTF = @DX_DOCDIR@/rtf + +endif DX_COND_rtf + +## ------------------------------ ## +## Rules specific for XML output. ## +## ------------------------------ ## + +if DX_COND_xml + +DX_CLEAN_XML = @DX_DOCDIR@/xml + +endif DX_COND_xml + +## ----------------------------- ## +## Rules specific for PS output. ## +## ----------------------------- ## + +if DX_COND_ps + +DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps + +DX_PS_GOAL = doxygen-ps + +doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps + +@DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag + cd @DX_DOCDIR@/latex; \ + rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ + $(DX_LATEX) refman.tex; \ + $(MAKEINDEX_PATH) refman.idx; \ + $(DX_LATEX) refman.tex; \ + countdown=5; \ + while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ + refman.log > /dev/null 2>&1 \ + && test $$countdown -gt 0; do \ + $(DX_LATEX) refman.tex; \ + countdown=`expr $$countdown - 1`; \ + done; \ + $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi + +endif DX_COND_ps + +## ------------------------------ ## +## Rules specific for PDF output. ## +## ------------------------------ ## + +if DX_COND_pdf + +DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf + +DX_PDF_GOAL = doxygen-pdf + +doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf + +@DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag + cd @DX_DOCDIR@/latex; \ + rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ + $(DX_PDFLATEX) refman.tex; \ + $(DX_MAKEINDEX) refman.idx; \ + $(DX_PDFLATEX) refman.tex; \ + countdown=5; \ + while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ + refman.log > /dev/null 2>&1 \ + && test $$countdown -gt 0; do \ + $(DX_PDFLATEX) refman.tex; \ + countdown=`expr $$countdown - 1`; \ + done; \ + mv refman.pdf ../@PACKAGE@.pdf + +endif DX_COND_pdf + +## ------------------------------------------------- ## +## Rules specific for LaTeX (shared for PS and PDF). ## +## ------------------------------------------------- ## + +if DX_COND_latex + +DX_CLEAN_LATEX = @DX_DOCDIR@/latex + +endif DX_COND_latex + +.PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL) + +.INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) + +doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag + +doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) + +@DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS) + rm -rf @DX_DOCDIR@ + $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG) + +DX_CLEANFILES = \ + @DX_DOCDIR@/@PACKAGE@.tag \ + -r \ + $(DX_CLEAN_HTML) \ + $(DX_CLEAN_CHM) \ + $(DX_CLEAN_CHI) \ + $(DX_CLEAN_MAN) \ + $(DX_CLEAN_RTF) \ + $(DX_CLEAN_XML) \ + $(DX_CLEAN_PS) \ + $(DX_CLEAN_PDF) \ + $(DX_CLEAN_LATEX) + +endif DX_COND_doc diff -r 20b1f3062855 -r ffdf467315ec gmyth/autogen.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/autogen.sh Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,99 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +DIE=0 +package=gmyth +srcfile=configure.ac + +# a quick cvs co if necessary to alleviate the pain - may remove this +# when developers get a clue ;) +if test ! -d common; +then + echo "+ getting common/ from svn" + svn co common +fi + +# source helper functions +if test ! -f common/autogen-helper.sh; +then + echo There is something wrong with your source tree. + echo You are missing common/autogen-helper.sh + exit 1 +fi +. common/autogen-helper.sh + +CONFIGURE_DEF_OPT='--enable-maintainer-mode' + +autogen_options + +echo -n "+ check for build tools" +if test ! -z "$NOCHECK"; then echo " skipped"; else echo; fi +version_check "autoconf" "$AUTOCONF autoconf autoconf-2.54 autoconf-2.53" \ + "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 53 || DIE=1 +version_check "automake" "$AUTOMAKE automake automake-1.9 automake-1.8 automake-1.7 automake-1.6" \ + "ftp://ftp.gnu.org/pub/gnu/automake/" 1 6 || DIE=1 +version_check "libtoolize" "$LIBTOOLIZE libtoolize" \ + "ftp://ftp.gnu.org/pub/gnu/libtool/" 1 5 0 || DIE=1 +version_check "pkg-config" "" \ + "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 + +die_check $DIE + +aclocal_check || DIE=1 +autoheader_check || DIE=1 + +die_check $DIE + +# if no arguments specified then this will be printed +if test -z "$*"; then + echo "+ checking for autogen.sh options" + echo " This autogen script will automatically run ./configure as:" + echo " ./configure $CONFIGURE_DEF_OPT" + echo " To pass any additional options, please specify them on the $0" + echo " command line." +fi + +toplevel_check $srcfile + +tool_run "$aclocal" "-I m4 $ACLOCAL_FLAGS" +tool_run "$libtoolize" "--copy --force" +tool_run "$autoheader" + +# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -- wingo +echo timestamp > stamp-h.in 2> /dev/null + +tool_run "$autoconf" +tool_run "$automake" "-a -c" + +# if enable exists, add an -enable option for each of the lines in that file +if test -f enable; then + for a in `cat enable`; do + CONFIGURE_FILE_OPT="--enable-$a" + done +fi + +# if disable exists, add an -disable option for each of the lines in that file +if test -f disable; then + for a in `cat disable`; do + CONFIGURE_FILE_OPT="$CONFIGURE_FILE_OPT --disable-$a" + done +fi + +test -n "$NOCONFIGURE" && { + echo "+ skipping configure stage for package $package, as requested." + echo "+ autogen.sh done." + exit 0 +} + +echo "+ running configure ... " +test ! -z "$CONFIGURE_DEF_OPT" && echo " ./configure default flags: $CONFIGURE_DEF_OPT" +test ! -z "$CONFIGURE_EXT_OPT" && echo " ./configure external flags: $CONFIGURE_EXT_OPT" +test ! -z "$CONFIGURE_FILE_OPT" && echo " ./configure enable/disable flags: $CONFIGURE_FILE_OPT" +echo + +./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT $CONFIGURE_FILE_OPT || { + echo " configure failed" + exit 1 +} + +echo "Now type 'make' to compile $package." diff -r 20b1f3062855 -r ffdf467315ec gmyth/common/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/common/Makefile.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,1 @@ +EXTRA_DIST = autogen-helper.sh diff -r 20b1f3062855 -r ffdf467315ec gmyth/common/autogen-helper.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/common/autogen-helper.sh Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,302 @@ +# a silly hack that generates autoregen.sh but it's handy +echo "#!/bin/sh" > autoregen.sh +echo "./autogen.sh $@ \$@" >> autoregen.sh +chmod +x autoregen.sh + +# helper functions for autogen.sh + +debug () +# print out a debug message if DEBUG is a defined variable +{ + if test ! -z "$DEBUG" + then + echo "DEBUG: $1" + fi +} + +version_check () +# check the version of a package +# first argument : package name (executable) +# second argument : optional path where to look for it instead +# third argument : source download url +# rest of arguments : major, minor, micro version +# all consecutive ones : suggestions for binaries to use +# (if not specified in second argument) +{ + PACKAGE=$1 + PKG_PATH=$2 + URL=$3 + MAJOR=$4 + MINOR=$5 + MICRO=$6 + + # for backwards compatibility, we let PKG_PATH=PACKAGE when PKG_PATH null + if test -z "$PKG_PATH"; then PKG_PATH=$PACKAGE; fi + debug "major $MAJOR minor $MINOR micro $MICRO" + VERSION=$MAJOR + if test ! -z "$MINOR"; then VERSION=$VERSION.$MINOR; else MINOR=0; fi + if test ! -z "$MICRO"; then VERSION=$VERSION.$MICRO; else MICRO=0; fi + + debug "major $MAJOR minor $MINOR micro $MICRO" + + for SUGGESTION in $PKG_PATH; do + COMMAND="$SUGGESTION" + + # don't check if asked not to + test -z "$NOCHECK" && { + echo -n " checking for $COMMAND >= $VERSION ... " + } || { + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + } + + debug "checking version with $COMMAND" + ($COMMAND --version) < /dev/null > /dev/null 2>&1 || + { + echo "not found." + continue + } + # strip everything that's not a digit, then use cut to get the first field + pkg_version=`$COMMAND --version|head -n 1|sed 's/^[^0-9]*//'|cut -d' ' -f1` + debug "pkg_version $pkg_version" + # remove any non-digit characters from the version numbers to permit numeric + # comparison + pkg_major=`echo $pkg_version | cut -d. -f1 | sed s/[a-zA-Z\-].*//g` + pkg_minor=`echo $pkg_version | cut -d. -f2 | sed s/[a-zA-Z\-].*//g` + pkg_micro=`echo $pkg_version | cut -d. -f3 | sed s/[a-zA-Z\-].*//g` + test -z "$pkg_major" && pkg_major=0 + test -z "$pkg_minor" && pkg_minor=0 + test -z "$pkg_micro" && pkg_micro=0 + debug "found major $pkg_major minor $pkg_minor micro $pkg_micro" + + #start checking the version + debug "version check" + + # reset check + WRONG= + + if [ ! "$pkg_major" -gt "$MAJOR" ]; then + debug "major: $pkg_major <= $MAJOR" + if [ "$pkg_major" -lt "$MAJOR" ]; then + debug "major: $pkg_major < $MAJOR" + WRONG=1 + elif [ ! "$pkg_minor" -gt "$MINOR" ]; then + debug "minor: $pkg_minor <= $MINOR" + if [ "$pkg_minor" -lt "$MINOR" ]; then + debug "minor: $pkg_minor < $MINOR" + WRONG=1 + elif [ "$pkg_micro" -lt "$MICRO" ]; then + debug "micro: $pkg_micro < $MICRO" + WRONG=1 + fi + fi + fi + + if test ! -z "$WRONG"; then + echo "found $pkg_version, not ok !" + continue + else + echo "found $pkg_version, ok." + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + fi + done + + echo "not found !" + echo "You must have $PACKAGE installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at $URL" + return 1; +} + +aclocal_check () +{ + # normally aclocal is part of automake + # so we expect it to be in the same place as automake + # so if a different automake is supplied, we need to adapt as well + # so how's about replacing automake with aclocal in the set var, + # and saving that in $aclocal ? + # note, this will fail if the actual automake isn't called automake* + # or if part of the path before it contains it + if [ -z "$automake" ]; then + echo "Error: no automake variable set !" + return 1 + else + aclocal=`echo $automake | sed s/automake/aclocal/` + debug "aclocal: $aclocal" + if [ "$aclocal" != "aclocal" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-aclocal=$aclocal" + fi + if [ ! -x `which $aclocal` ]; then + echo "Error: cannot execute $aclocal !" + return 1 + fi + fi +} + +autoheader_check () +{ + # same here - autoheader is part of autoconf + # use the same voodoo + if [ -z "$autoconf" ]; then + echo "Error: no autoconf variable set !" + return 1 + else + autoheader=`echo $autoconf | sed s/autoconf/autoheader/` + debug "autoheader: $autoheader" + if [ "$autoheader" != "autoheader" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoheader=$autoheader" + fi + if [ ! -x `which $autoheader` ]; then + echo "Error: cannot execute $autoheader !" + return 1 + fi + fi + +} + +autoconf_2_52d_check () +{ + # autoconf 2.52d has a weird issue involving a yes:no error + # so don't allow it's use + test -z "$NOCHECK" && { + ac_version=`$autoconf --version|head -n 1|sed 's/^[a-zA-Z\.\ ()]*//;s/ .*$//'` + if test "$ac_version" = "2.52d"; then + echo "autoconf 2.52d has an issue with our current build." + echo "We don't know who's to blame however. So until we do, get a" + echo "regular version. RPM's of a working version are on the gstreamer site." + exit 1 + fi + } + return 0 +} + +die_check () +{ + # call with $DIE + # if set to 1, we need to print something helpful then die + DIE=$1 + if test "x$DIE" = "x1"; + then + echo + echo "- Please get the right tools before proceeding." + echo "- Alternatively, if you're sure we're wrong, run with --nocheck." + exit 1 + fi +} + +autogen_options () +{ + if test "x$1" = "x"; then + return 0 + fi + + while test "x$1" != "x" ; do + optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + case "$1" in + --noconfigure) + NOCONFIGURE=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --noconfigure" + echo "+ configure run disabled" + shift + ;; + --nocheck) + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --nocheck" + NOCHECK=defined + echo "+ autotools version check disabled" + shift + ;; + --debug) + DEBUG=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --debug" + echo "+ debug output enabled" + shift + ;; + --prefix=*) + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$optarg" + echo "+ passing --prefix=$optarg to configure" + shift + ;; + --prefix) + shift + echo "DEBUG: $1" + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$1" + echo "+ passing --prefix=$1 to configure" + shift + ;; + -h|--help) + echo "autogen.sh (autogen options) -- (configure options)" + echo "autogen.sh help options: " + echo " --noconfigure don't run the configure script" + echo " --nocheck don't do version checks" + echo " --debug debug the autogen process" + echo " --prefix will be passed on to configure" + echo + echo " --with-autoconf PATH use autoconf in PATH" + echo " --with-automake PATH use automake in PATH" + echo + echo "to pass options to configure, put them as arguments after -- " + exit 1 + ;; + --with-automake=*) + AUTOMAKE=$optarg + echo "+ using alternate automake in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-automake=$AUTOMAKE" + shift + ;; + --with-autoconf=*) + AUTOCONF=$optarg + echo "+ using alternate autoconf in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoconf=$AUTOCONF" + shift + ;; + --disable*|--enable*|--with*) + echo "+ passing option $1 to configure" + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $1" + shift + ;; + --) shift ; break ;; + *) echo "- ignoring unknown autogen.sh argument $1"; shift ;; + esac + done + + for arg do CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $arg"; done + if test ! -z "$CONFIGURE_EXT_OPT" + then + echo "+ options passed to configure: $CONFIGURE_EXT_OPT" + fi +} + +toplevel_check () +{ + srcfile=$1 + test -f $srcfile || { + echo "You must run this script in the top-level $package directory" + exit 1 + } +} + + +tool_run () +{ + tool=$1 + options=$2 + run_if_fail=$3 + echo "+ running $tool $options..." + $tool $options || { + echo + echo $tool failed + eval $run_if_fail + exit 1 + } +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/configure.ac --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/configure.ac Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,224 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.50) + +AC_INIT([gmyth],[0.1]) + +dnl AC_CONFIG_SRCDIR([src/mmyth_main.c]) +AC_CONFIG_HEADER(config.h) + +dnl when going to/from release please set the nano (fourth number) right ! +dnl releases only do Wall, SVN and prerelease does Werror too +AS_VERSION(gmyth, GMYTH, 0, 1, 0, 3, GMYTH_SVN="no", GMYTH_SVN="yes") + +GMYTH_MAJORMINOR=$GMYTH_MAJOR_VERSION.$GMYTH_MINOR_VERSION + +AC_SUBST(GMYTH_MAJORMINOR) + +dnl AM_MAINTAINER_MODE provides the option to enable maintainer mode +AM_MAINTAINER_MODE +dnl make aclocal work in maintainer mode +AC_SUBST(ACLOCAL_AMFLAGS, "-I m4") + +# Checks for programs. +# check for tools +# Make sure CFLAGS is defined to stop AC_PROC_CC adding -g +CFLAGS="$CFLAGS -Wall" +AC_PROG_CC +AC_PROG_LIBTOOL + +dnl Generate doxygen documentation +DX_HTML_FEATURE(ON) +DX_CHM_FEATURE(OFF) +DX_CHI_FEATURE(OFF) +DX_MAN_FEATURE(OFF) +DX_RTF_FEATURE(OFF) +DX_XML_FEATURE(OFF) +DX_PDF_FEATURE(OFF) +DX_PS_FEATURE(OFF) +DX_INIT_DOXYGEN(gmyth, doxygen.cfg, docs) + + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_STRUCT_TM + +# Checks for library functions. +AC_FUNC_FORK +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MALLOC +AC_FUNC_MKTIME +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([memset socket stime strstr strtoul]) + +AM_INIT_AUTOMAKE($PACKAGE, $VERSION) + +# Checks required packages + +dnl Test if --disable-debug given +AC_ARG_ENABLE(debug, + [AC_HELP_STRING([--disable-debug], [disable debugging mode])], + enable_debug="$enableval", + enable_debug=yes) + +if test "x$enable_debug" = "xyes" ; then + CFLAGS="$CFLAGS -g" +else + AC_DEFINE( NDEBUG, 1, [disable debug messages] ) + CFLAGS="$CFLAGS -O2 -DG_DISABLE_CHECKS -DNDEBUG" +fi + +AM_CONDITIONAL( NDEBUG, test "x$enable_debug" = "xyes" ) + +# Check for pkgconfig +AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, yes, no) +# Give error and exit if we don't have pkgconfig +if test "x$HAVE_PKGCONFIG" = "xno"; then + AC_MSG_ERROR(you need to have pkgconfig installed !) +fi + +# Check for Glib2.0 +PKG_CHECK_MODULES(GLIB, glib-2.0, HAVE_GLIB=yes,HAVE_GLIB=no) + +# Give error and exit if we don't have glib +if test "x$HAVE_GLIB" = "xno"; then + AC_MSG_ERROR(you need glib-2.0 installed) +fi + +# make GLIB_CFLAGS and GLIB_LIBS available +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) + +# Check for GObject2.0 +PKG_CHECK_MODULES(GOBJECT, + gobject-2.0, + HAVE_GOBJECT=yes, HAVE_GOBJECT=no) + +# Give error and exit if we don't have gobject +if test "x$HAVE_GOBJECT" = "xno"; then + AC_MSG_ERROR(you need gobject-2.0 installed) +fi + +# make GOBJECT_CFLAGS and GOBJECT_LIBS available +AC_SUBST(GOBJECT_CFLAGS) +AC_SUBST(GOBJECT_LIBS) + +# Check for GTK+-2.0 +PKG_CHECK_MODULES(GTK, gtk+-2.0, HAVE_GTK=yes,HAVE_GTK=no) + +# Give error and exit if we don't have gtk +if test "x$HAVE_GTK" = "xyes"; then + AC_DEFINE(WITH_GTK, 1, [build with GTK+ related stuff]) + dnl AC_MSG_ERROR(you need gtk+-2.0 installed) +else + AC_MSG_RESULT(no) +fi + +AM_CONDITIONAL(WITH_GTK, test "x$HAVE_GTK" = "xyes" ) + +# make GTK_CFLAGS and GTK_LIBS available +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) + +dnl ========== Check for Hildon Libraries +PKG_CHECK_MODULES(HILDON, + hildon-lgpl libosso hildon-status-bar-lib libhildonmenu hildon-base-lib hildon-control-panel hildon-libs, + HAVE_HILDON=yes, HAVE_HILDON=no) + +if test "x$HAVE_HILDON" = "xyes"; then + AC_DEFINE(MAEMO_PLATFORM, 1, [build with hildon libs]) + HILDON_CFLAGS="$HILDON_CFLAGS -DMAEMO_PLATFORM=1" +else + AC_MSG_RESULT(no) +fi + +AM_CONDITIONAL(MAEMO_PLATFORM, test "x$HAVE_HILDON" = "xyes") + +dnl make HILDON_CFLAGS and HILDON_LIBS available +AC_SUBST(HILDON_CFLAGS) +AC_SUBST(HILDON_LIBS) + +# Check for libxml-2.0 +PKG_CHECK_MODULES(LIBXML, libxml-2.0, HAVE_LIBXML=yes,HAVE_LIBXML=no) + +# Give error and exit if we don't have gtk +if test "x$HAVE_LIBXML" = "xno"; then + AC_MSG_ERROR(you need libxml-2.0 installed) +fi + +# make LIBXML_CFLAGS and LIBXML_LIBS available +AC_SUBST(LIBXML_CFLAGS) +AC_SUBST(LIBXML_LIBS) + + +# check for gstreamer development files +GST_REQUIRED=0.10 +GST_MAJORMINOR=0.10 +PKG_CHECK_MODULES(GST, \ + gstreamer-$GST_MAJORMINOR >= $GST_REQUIRED, + HAVE_GST=yes, HAVE_GST=no) + +# Give error and exit if we don't have gstreamer +if test "x$HAVE_GST" = "xno"; then + AC_MSG_ERROR(you need gstreamer development packages installed !) +fi + +# make GST_CFLAGS and GST_LIBS available +AC_SUBST(GST_CFLAGS) +AC_SUBST(GST_LIBS) + +# check for gstreamer-base plugins (xoverlay interface) +GSTBASE_REQUIRED=0.10 +GSTBASE_MAJORMINOR=0.10 +PKG_CHECK_MODULES(GSTBASE, \ + gstreamer-base-$GSTBASE_MAJORMINOR >= $GSTBASE_REQUIRED, + HAVE_GSTBASE=yes, HAVE_GSTBASE=no) + +# Give error and exit if we don't have gstreamer base libraries +if test "x$HAVE_GSTBASE" = "xno"; then + AC_MSG_ERROR(you need gstreamer base development packages installed !) +fi + +# make GSTBASE_CFLAGS and GSTBASE_LIBS available +AC_SUBST(GSTBASE_CFLAGS) +AC_SUBST(GSTBASE_LIBS) + + +# make GST_MAJORMINOR available in Makefile.am +AC_SUBST(GST_MAJORMINOR) + +# +# mysql libraries +# +AC_CHECK_PROG(MYSQL_CFLAGS,mysql_config,`mysql_config --cflags`) +if test -z "$MYSQL_CFLAGS"; then + AC_MSG_ERROR([Could not find mysql_config script. Make sure the mysql client libraries are installed]) +fi +AC_SUBST(MYSQL_CFLAGS) + + +AC_CHECK_PROG(MYSQL_LIBS,mysql_config,`mysql_config --libs`) +if test -z "$MYSQL_LIBS"; then + AC_MSG_ERROR([Could not find mysql_config script. Make sure the mysql client libraries are installed]) +fi +AC_SUBST(MYSQL_LIBS) + +#dnl Enable gtk-doc +#GTK_DOC_CHECK(1.4) + + +AC_CONFIG_FILES([Makefile + pixmaps/Makefile + src/Makefile + src/libgmyth/Makefile + src/gui/Makefile + gmyth.pc]) +AC_OUTPUT diff -r 20b1f3062855 -r ffdf467315ec gmyth/data/settings/history.dat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/data/settings/history.dat Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,3 @@ +# MIPTV history file +# Stores the last network frequency used +602000000 diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/changelog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/changelog Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,6 @@ +mmyth (0.1-indt1) unstable; urgency=low + + * Initial Maemo Package. + + -- Hallyson Melo Fri, 15 Sep 2006 10:26:16 -0300 + diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/compat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/compat Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,1 @@ +4 diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/control Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,17 @@ +Source: mmyth +Section: user/accessories +Priority: optional +Maintainer: Hallyson Melo +Build-Depends: debhelper, libgtk2.0-dev (>= 2.4.0), + libosso-dev, hildon-libs-dev, hildon-fm-dev +Standards-Version: 3.6.2 + +Package: mmyth +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, maemo-select-menu-location +Provides: MythTV +Description: MythTV frontend + NONONONONONONONONONONONONONONONONO + NONONONONONONONONONONo + . + NONNONONONON diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/control.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/control.in Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,17 @@ +Source: mmyth +Section: user/accessories +Priority: optional +Maintainer: Hallyson Melo +Build-Depends: debhelper, libgtk2.0-dev (>= 2.4.0), + libosso-dev, hildon-libs-dev, hildon-fm-dev +Standards-Version: 3.6.2 + +Package: mmyth +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, maemo-select-menu-location +Provides: MythTV +Description: MythTV frontend + NONONONONONONONONONONONONONONONONO + NONONONONONONONONONONo + . + NONNONONONON diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/mmyth.desktop --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/mmyth.desktop Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Version=0.1 +Type=Application +Name=Maemo Myth +Exec=/usr/bin/mmyth +Terminal=false +X-HildonDesk-ShowInToolbar=true +X-Osso-Type=application/x-executable +StartupWMClass=mmyth diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/mmyth.dirs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/mmyth.dirs Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,3 @@ +usr/share/pixmaps +usr/share/applications/hildon +usr/share/dbus-1/services diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/mmyth.postinst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/mmyth.postinst Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,5 @@ +#! /bin/sh + +maemo-select-menu-location mmyth.desktop tana_fi_extras + +exit 0 diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/mmyth.service --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/mmyth.service Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=com.nokia.xournal +Exec=/usr/bin/xournal diff -r 20b1f3062855 -r ffdf467315ec gmyth/debian/rules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/debian/rules Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,15 @@ +#!/usr/bin/make -f +# -*- mode: makefile; coding: utf-8 -*- + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/gnome.mk +include /usr/share/cdbs/1/rules/simple-patchsys.mk +include /usr/share/gnome-pkg-tools/1/rules/uploaders.mk + +DEB_CONFIGURE_EXTRA_FLAGS := --prefix=/usr + +binary-install/mmyth:: +# /usr/bin/install -p -m 644 debian/mmyth.png `pwd`/debian/mmyth/usr/share/pixmaps + /usr/bin/install -p -m 644 debian/mmyth.desktop `pwd`/debian/mmyth/usr/share/applications/hildon +# /usr/bin/install -p -m 644 debian/mmyth.service `pwd`/debian/mmyth/usr/share/dbus-1/services + diff -r 20b1f3062855 -r ffdf467315ec gmyth/doxygen.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/doxygen.cfg Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,212 @@ +# Doxyfile 1.4.2 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = $(PROJECT)-$(VERSION) +PROJECT_NUMBER = +OUTPUT_DIRECTORY = $(DOCDIR) +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +STRIP_FROM_INC_PATH = $(SRCDIR)/src/libgmyth +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(SRCDIR)/src/libgmyth +SHORT_NAMES = YES +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = $(SRCDIR)/src/libgmyth +FILE_PATTERNS = *.c *.h +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = $(SRCDIR)/src/gui +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = $(GENERATE_HTML) +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = $(GENERATE_CHM) +CHM_FILE = ../$(PROJECT).chm +HHC_LOCATION = $(HHC_PATH) +GENERATE_CHI = $(GENERATE_CHI) +BINARY_TOC = YES +TOC_EXPAND = YES +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = $(GENERATE_LATEX) +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = $(PAPER_SIZE) +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = YES +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = $(GENERATE_RTF) +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = $(GENERATE_MAN) +MAN_OUTPUT = man +MAN_EXTENSION = .1 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = $(GENERATE_XML) +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = $(DOCDIR)/$(PROJECT).tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = $(PERL_PATH) +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = $(HAVE_DOT) +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = $(DOT_PATH) +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff -r 20b1f3062855 -r ffdf467315ec gmyth/gmyth.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/gmyth.pc.in Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gmyth +Description: Myth TV library based upon GLib/GObject paradigm +Version: @VERSION@ +Requires: gobject-2.0 glib-2.0 gtk+-2.0 + +Libs: @MYSQL_LIBS@ -L${libdir} -lgmyth +Cflags: @MYSQL_CFLAGS@ -I${includedir}/gmyth diff -r 20b1f3062855 -r ffdf467315ec gmyth/m4/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/m4/Makefile.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,7 @@ +EXTRA_DIST = \ + ac_doxygen.m4 \ + as-compiler-flag.m4 \ + as-expand.m4 \ + as-version.m4 \ + as-gtk-doc.m4 + diff -r 20b1f3062855 -r ffdf467315ec gmyth/m4/ac_doxygen.m4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/m4/ac_doxygen.m4 Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,312 @@ +# This file is part of Autoconf. -*- Autoconf -*- + +# Copyright (C) 2004 Oren Ben-Kiki +# This file is distributed under the same terms as the Autoconf macro files. + +# Generate automatic documentation using Doxygen. Works in concert with the +# aminclude.m4 file and a compatible doxygen configuration file. Defines the +# following public macros: +# +# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature. +# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics, +# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI' +# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF', +# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment +# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide' +# paper size. +# +# By default, HTML, PDF and PS documentation is generated as this seems to be +# the most popular and portable combination. MAN pages created by Doxygen are +# usually problematic, though by picking an appropriate subset and doing some +# massaging they might be better than nothing. CHM and RTF are specific for MS +# (note that you can't generate both HTML and CHM at the same time). The XML is +# rather useless unless you apply specialized post-processing to it. +# +# The macro mainly controls the default state of the feature. The use can +# override the default by specifying --enable or --disable. The macros ensure +# that contradictory flags are not given (e.g., --enable-doxygen-html and +# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.) +# Finally, each feature will be automatically disabled (with a warning) if the +# required programs are missing. +# +# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with +# the following parameters: a one-word name for the project for use as a +# filename base etc., an optional configuration file name (the default is +# 'Doxyfile', the same as Doxygen's default), and an optional output directory +# name (the default is 'doxygen-doc'). + +## ----------## +## Defaults. ## +## ----------## + +DX_ENV="" +AC_DEFUN([DX_FEATURE_doc], ON) +AC_DEFUN([DX_FEATURE_dot], ON) +AC_DEFUN([DX_FEATURE_man], OFF) +AC_DEFUN([DX_FEATURE_html], ON) +AC_DEFUN([DX_FEATURE_chm], OFF) +AC_DEFUN([DX_FEATURE_chi], OFF) +AC_DEFUN([DX_FEATURE_rtf], OFF) +AC_DEFUN([DX_FEATURE_xml], OFF) +AC_DEFUN([DX_FEATURE_pdf], ON) +AC_DEFUN([DX_FEATURE_ps], ON) + +## --------------- ## +## Private macros. ## +## --------------- ## + +# DX_ENV_APPEND(VARIABLE, VALUE) +# ------------------------------ +# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen. +AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])]) + +# DX_DIRNAME_EXPR +# --------------- +# Expand into a shell expression prints the directory part of a path. +AC_DEFUN([DX_DIRNAME_EXPR], + [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']]) + +# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF) +# ------------------------------------- +# Expands according to the M4 (static) status of the feature. +AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])]) + +# DX_REQUIRE_PROG(VARIABLE, PROGRAM) +# ---------------------------------- +# Require the specified program to be found for the DX_CURRENT_FEATURE to work. +AC_DEFUN([DX_REQUIRE_PROG], [ +AC_PATH_TOOL([$1], [$2]) +if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then + AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION]) + AC_SUBST([DX_FLAG_[]DX_CURRENT_FEATURE], 0) +fi +]) + +# DX_TEST_FEATURE(FEATURE) +# ------------------------ +# Expand to a shell expression testing whether the feature is active. +AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) + +# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE) +# ------------------------------------------------- +# Verify that a required features has the right state before trying to turn on +# the DX_CURRENT_FEATURE. +AC_DEFUN([DX_CHECK_DEPEND], [ +test "$DX_FLAG_$1" = "$2" \ +|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, + requires, contradicts) doxygen-DX_CURRENT_FEATURE]) +]) + +# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) +# ---------------------------------------------------------- +# Turn off the DX_CURRENT_FEATURE if the required feature is off. +AC_DEFUN([DX_CLEAR_DEPEND], [ +test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_[]DX_CURRENT_FEATURE], 0) +]) + +# DX_FEATURE_ARG(FEATURE, DESCRIPTION, +# CHECK_DEPEND, CLEAR_DEPEND, +# REQUIRE, DO-IF-ON, DO-IF-OFF) +# -------------------------------------------- +# Parse the command-line option controlling a feature. CHECK_DEPEND is called +# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND), +# otherwise CLEAR_DEPEND is called to turn off the default state if a required +# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional +# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and +# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature. +AC_DEFUN([DX_ARG_ABLE], [ + AC_DEFUN([DX_CURRENT_FEATURE], [$1]) + AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2]) + AC_ARG_ENABLE(doxygen-$1, + [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1], + [--enable-doxygen-$1]), + DX_IF_FEATURE([$1], [don't $2], [$2]))], + [ +case "$enableval" in +#( +y|Y|yes|Yes|YES) + AC_SUBST([DX_FLAG_$1], 1) + $3 +;; #( +n|N|no|No|NO) + AC_SUBST([DX_FLAG_$1], 0) +;; #( +*) + AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1]) +;; +esac +], [ +AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)]) +$4 +]) +if DX_TEST_FEATURE([$1]); then + $5 + : +fi +if DX_TEST_FEATURE([$1]); then + AM_CONDITIONAL(DX_COND_$1, :) + $6 + : +else + AM_CONDITIONAL(DX_COND_$1, false) + $7 + : +fi +]) + +## -------------- ## +## Public macros. ## +## -------------- ## + +# DX_XXX_FEATURE(DEFAULT_STATE) +# ----------------------------- +AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])]) +AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])]) +AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])]) +AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])]) +AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])]) +AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])]) +AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) +AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) +AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])]) +AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])]) + +# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR]) +# --------------------------------------------------------- +# PROJECT also serves as the base name for the documentation files. +# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc". +AC_DEFUN([DX_INIT_DOXYGEN], [ + +# Files: +AC_SUBST([DX_PROJECT], [$1]) +AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])]) +AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])]) + +# Environment variables used inside doxygen.cfg: +DX_ENV_APPEND(SRCDIR, $srcdir) +DX_ENV_APPEND(PROJECT, $DX_PROJECT) +DX_ENV_APPEND(DOCDIR, $DX_DOCDIR) +DX_ENV_APPEND(VERSION, $PACKAGE_VERSION) + +# Doxygen itself: +DX_ARG_ABLE(doc, [generate any doxygen documentation], + [], + [], + [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen) + DX_REQUIRE_PROG([DX_PERL], perl)], + [DX_ENV_APPEND(PERL_PATH, $DX_PERL)]) + +# Dot for graphics: +DX_ARG_ABLE(dot, [generate graphics for doxygen documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_DOT], dot)], + [DX_ENV_APPEND(HAVE_DOT, YES) + DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])], + [DX_ENV_APPEND(HAVE_DOT, NO)]) + +# Man pages generation: +DX_ARG_ABLE(man, [generate doxygen manual pages], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [], + [DX_ENV_APPEND(GENERATE_MAN, YES)], + [DX_ENV_APPEND(GENERATE_MAN, NO)]) + +# RTF file generation: +DX_ARG_ABLE(rtf, [generate doxygen RTF documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [], + [DX_ENV_APPEND(GENERATE_RTF, YES)], + [DX_ENV_APPEND(GENERATE_RTF, NO)]) + +# XML file generation: +DX_ARG_ABLE(xml, [generate doxygen XML documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [], + [DX_ENV_APPEND(GENERATE_XML, YES)], + [DX_ENV_APPEND(GENERATE_XML, NO)]) + +# (Compressed) HTML help generation: +DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_HHC], hhc)], + [DX_ENV_APPEND(HHC_PATH, $DX_HHC) + DX_ENV_APPEND(GENERATE_HTML, YES) + DX_ENV_APPEND(GENERATE_HTMLHELP, YES)], + [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)]) + +# Seperate CHI file generation. +DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file], + [DX_CHECK_DEPEND(chm, 1)], + [DX_CLEAR_DEPEND(chm, 1)], + [], + [DX_ENV_APPEND(GENERATE_CHI, YES)], + [DX_ENV_APPEND(GENERATE_CHI, NO)]) + +# Plain HTML pages generation: +DX_ARG_ABLE(html, [generate doxygen plain HTML documentation], + [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)], + [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)], + [], + [DX_ENV_APPEND(GENERATE_HTML, YES)], + [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)]) + +# PostScript file generation: +DX_ARG_ABLE(ps, [generate doxygen PostScript documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_LATEX], latex) + DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) + DX_REQUIRE_PROG([DX_DVIPS], dvips) + DX_REQUIRE_PROG([DX_EGREP], egrep)]) + +# PDF file generation: +DX_ARG_ABLE(pdf, [generate doxygen PDF documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex) + DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) + DX_REQUIRE_PROG([DX_EGREP], egrep)]) + +# LaTeX generation for PS and/or PDF: +if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then + AM_CONDITIONAL(DX_COND_latex, :) + DX_ENV_APPEND(GENERATE_LATEX, YES) +else + AM_CONDITIONAL(DX_COND_latex, false) + DX_ENV_APPEND(GENERATE_LATEX, NO) +fi + +# Paper size for PS and/or PDF: +AC_ARG_VAR(DOXYGEN_PAPER_SIZE, + [a4wide (default), a4, letter, legal or executive]) +case "$DOXYGEN_PAPER_SIZE" in +#( +"") + AC_SUBST(DOXYGEN_PAPER_SIZE, "") +;; #( +a4wide|a4|letter|legal|executive) + DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE) +;; #( +*) + AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE']) +;; +esac + +#For debugging: +#echo DX_FLAG_doc=$DX_FLAG_doc +#echo DX_FLAG_dot=$DX_FLAG_dot +#echo DX_FLAG_man=$DX_FLAG_man +#echo DX_FLAG_html=$DX_FLAG_html +#echo DX_FLAG_chm=$DX_FLAG_chm +#echo DX_FLAG_chi=$DX_FLAG_chi +#echo DX_FLAG_rtf=$DX_FLAG_rtf +#echo DX_FLAG_xml=$DX_FLAG_xml +#echo DX_FLAG_pdf=$DX_FLAG_pdf +#echo DX_FLAG_ps=$DX_FLAG_ps +#echo DX_ENV=$DX_ENV +]) diff -r 20b1f3062855 -r ffdf467315ec gmyth/m4/as-compiler-flag.m4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/m4/as-compiler-flag.m4 Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,33 @@ +dnl as-compiler-flag.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flags + +dnl David Schleef + +dnl $Id: as-compiler-flag.m4,v 1.1.1.1 2005/08/26 00:42:44 andrunko Exp $ + +dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + diff -r 20b1f3062855 -r ffdf467315ec gmyth/m4/as-expand.m4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/m4/as-expand.m4 Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,40 @@ +dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) +dnl +dnl example +dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) +dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local + +AC_DEFUN([AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var"="x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) diff -r 20b1f3062855 -r ffdf467315ec gmyth/m4/as-version.m4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/m4/as-version.m4 Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,59 @@ +dnl version.m4 0.0.5 +dnl autostars m4 macro for versioning +dnl thomas@apestaart.org +dnl +dnl AS_VERSION(PACKAGE, PREFIX, MAJOR, MINOR, MICRO, NANO, ACTION_IF_NO_NANO, ACTION_IF_NANO) +dnl example +dnl AS_VERSION(gstreamer, GST_VERSION, 0, 3, 2,) +dnl for a 0.3.2 release version +dnl +dnl this macro +dnl - defines [$PREFIX]_MAJOR, MINOR and MICRO +dnl - if NANO is empty, then we're in release mode, else in cvs/dev mode +dnl - defines [$PREFIX], VERSION, and [$PREFIX]_RELEASE +dnl - executes the relevant action +dnl - AC_SUBST's PACKAGE, VERSION, [$PREFIX] and [$PREFIX]_RELEASE +dnl as well as the little ones +dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents +dnl maintainer mode from running ok +dnl +dnl don't forget to put #undef [$2] and [$2]_RELEASE in acconfig.h + +AC_DEFUN([AS_VERSION], +[ + PACKAGE=[$1] + [$2]_MAJOR_VERSION=[$3] + [$2]_MINOR_VERSION=[$4] + [$2]_MICRO_VERSION=[$5] + NANO=[$6] + [$2]_NANO_VERSION=$NANO + if test "x$NANO" = "x" || test "x$NANO" = "x0"; + then + AC_MSG_NOTICE(configuring [$1] for release) + VERSION=[$3].[$4].[$5] + [$2]_RELEASE=1 + dnl execute action + ifelse([$7], , :, [$7]) + else + AC_MSG_NOTICE(configuring [$1] for development with nano $NANO) + VERSION=[$3].[$4].[$5].$NANO + [$2]_RELEASE=`date +%Y%m%d_%H%M%S` + dnl execute action + ifelse([$8], , :, [$8]) + fi + + [$2]_VERSION=$VERSION + AC_DEFINE_UNQUOTED([$2]_VERSION, "$[$2]_VERSION", [Define the version]) + AC_SUBST([$2]_VERSION) + + AC_SUBST([$2]_RELEASE) + + AC_SUBST([$2]_MAJOR_VERSION) + AC_SUBST([$2]_MINOR_VERSION) + AC_SUBST([$2]_MICRO_VERSION) + AC_SUBST([$2]_NANO_VERSION) + AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Define the package name]) + AC_SUBST(PACKAGE) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Define the version]) + AC_SUBST(VERSION) +]) diff -r 20b1f3062855 -r ffdf467315ec gmyth/pixmaps/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/pixmaps/Makefile.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,11 @@ +# Adding the application icon +#icondir = $(datadir)/miptv/pixmaps +#icon_DATA = \ +# miptv.png + + +# Adding the application resources +pixmapdir = $(pkgdatadir)/pixmaps +pixmap_DATA = mmyth_logo.png + +EXTRA_DIST = $(pixmap_DATA) diff -r 20b1f3062855 -r ffdf467315ec gmyth/pixmaps/main_logo.gif Binary file gmyth/pixmaps/main_logo.gif has changed diff -r 20b1f3062855 -r ffdf467315ec gmyth/pixmaps/mmyth_logo.png Binary file gmyth/pixmaps/mmyth_logo.png has changed diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/Makefile.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,29 @@ +SUBDIRS = libgmyth gui . + +bin_PROGRAMS = mmyth + +mmyth_SOURCES = mmyth_main.c + +mmyth_CFLAGS = \ + $(GTK_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GST_CFLAGS) \ + $(MYSQL_CFLAGS) \ + -g3 -O0 \ + -I$(top_srcdir)/src/libgmyth \ + -I$(top_srcdir)/src/gui \ + -DDATA_DIR=\""$(pkgdatadir)"\" \ + -DPIX_DIR=\""$(pkgdatadir)/pixmaps/"\" \ + -DESG_DIR=\""$(pkgdatadir)/pixmaps/"\" \ + -DICON_DIR=\""$(pkgdatadir)/pixmaps/"\" + +mmyth_LDFLAGS = + +mmyth_LDADD = \ + $(GTK_LIBS) \ + $(GLIB_LIBS) \ + $(GST_LIBS) \ + $(GSTBASE_LIBS) \ + $(HILDON_LIBS) \ + $(top_srcdir)/src/libgmyth/libgmyth.la \ + $(top_srcdir)/src/gui/libmmythgui.la diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/Makefile.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,29 @@ +noinst_LTLIBRARIES = libmmythgui.la + +libmmythgui_la_SOURCES = \ + mmyth_ui.c \ + mmyth_uicommon.c \ + mmyth_epg_grid_view.c \ + mmyth_epg_grid_widget.c \ + mmyth_recordui.c \ + mmyth_uisettings.c \ + mmyth_schedulerui.c + +libmmythgui_la_CFLAGS = \ + $(GTK_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GST_CFLAGS) \ + $(MYSQL_CFLAGS) \ + -I$(top_srcdir)/src/libgmyth \ + -I$(top_srcdir)/src \ + -DDATA_DIR=\""$(pkgdatadir)"\" \ + -DPIX_DIR=\""$(pkgdatadir)/pixmaps/"\" \ + -DICON_DIR=\""$(datadir)/pixmaps/"\" \ + -g3 -O0 + +libmmythgui_la_LIBADD = \ + $(top_srcdir)/src/libgmyth/libgmyth.la + +libmmythgui_la_LDFLAGS = -export-dynamic + + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_epg_grid_view.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_epg_grid_view.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include + +#include "mmyth_epg_grid_view.h" +#include "mmyth_epg_grid_widget.h" + +/* Service genre */ +#define GENRE_MIN 0 +#define GENRE_MAX 10 +#define GENRE_UNDEFINED 0 +#define GENRE_MOVIE 1 +#define GENRE_NEWS 2 +#define GENRE_SHOW 3 +#define GENRE_SPORTS 4 +#define GENRE_CHILDREN 5 +#define GENRE_MUSIC 6 +#define GENRE_CULTURE 7 +#define GENRE_SOCIAL 8 +#define GENRE_EDUCATION 9 +#define GENRE_LEISURE 10 + +#define NRO_HOURS 3 + +/* Function prototypes*/ +static void update_service_details(MMythEpgGridWidget *object, + gpointer arg1, gpointer user_data); +static gboolean key_press_epg_grid_view(GtkWidget * widget, + GdkEventKey * event, + gpointer user_data); + +static GtkWidget *mmyth_epg_grid_widget = NULL; + +/* is a GtkEventBox */ +static GtkWidget *program_details_area = NULL; +static GtkWidget *details_main_hbox = NULL; +static GtkWidget *details_vbox = NULL; +static GtkWidget *details_logo_vbox = NULL; + +/* update signal callback from MMythEpgGridWidget */ +static void +update_service_details(MMythEpgGridWidget *object, gpointer arg1, gpointer user_data) +{ + g_return_if_fail(arg1 != NULL); + + EpgGridItem *epg_grid_item = (EpgGridItem *) arg1; + + gchar sel_prog_desc[100] = ""; + gchar time_buffer[50]; + + /* FIXME: get first content from content_list*/ + GMythProgramInfo *proginfo = (GMythProgramInfo *) epg_grid_item->proginfo; + + if(proginfo) { + GString *prog_name = proginfo->title; + GString *service_name = proginfo->chanid; + + if(details_vbox != NULL) + gtk_container_remove (GTK_CONTAINER (details_main_hbox), details_vbox); + + /* update service description */ + strcat(sel_prog_desc, service_name->str); + strcat(sel_prog_desc, ""); + + GtkWidget *fst_line_lbl = gtk_label_new(NULL); + gtk_misc_set_alignment (GTK_MISC(fst_line_lbl), 0.0, 0.0); + gtk_label_set_markup(GTK_LABEL(fst_line_lbl), sel_prog_desc); + + /* freeing char[] */ + sel_prog_desc[0] = 0; + strcat(sel_prog_desc, "\t"); + strcat(sel_prog_desc, prog_name->str); + + struct tm loctime_start, loctime_end; + + // Convert it to local time representation. + /* FIXME: conversion from time to localtime is different + in different machines */ + long int schedule_start_time = proginfo->startts; + long int schedule_end_time = proginfo->endts; + + if (localtime_r(&schedule_start_time, &loctime_start) == NULL) { + g_warning ("localtime_r error in mmyth_epg_grid_view!\n"); + } + + #if 0 + fprintf (stderr, asctime (loctime_start)); + #endif + + strftime (time_buffer, 100, " %H:%M - ", &loctime_start); + strcat(sel_prog_desc, time_buffer ); + + if (localtime_r(&schedule_end_time, &loctime_end) == NULL) { + g_warning ("localtime_r error in mmyth_epg_grid_view!\n"); + } + + #if 0 + fprintf (stderr, asctime (loctime_end)); + #endif + + strftime (time_buffer, 100, "%H:%M\n", &loctime_end); + strcat(sel_prog_desc, time_buffer ); + + GtkWidget *snd_line_lbl = gtk_label_new(NULL); + gtk_misc_set_alignment (GTK_MISC(snd_line_lbl), 0.0, 0.0); + gtk_label_set_markup(GTK_LABEL(snd_line_lbl), sel_prog_desc); + + // add the current selected program description to the label + details_vbox = gtk_vbox_new(FALSE, 0); + GtkWidget *fst_line_hbox = gtk_hbox_new(FALSE, 0); + + gtk_box_pack_start (GTK_BOX (fst_line_hbox), + fst_line_lbl, FALSE, FALSE, 6); + gtk_box_pack_start (GTK_BOX (details_vbox), + fst_line_hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (details_vbox), + snd_line_lbl, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (details_main_hbox), + details_vbox, FALSE, FALSE, 0); + + gtk_widget_show_all(details_main_hbox); + } +} + +/* Callback for hardware keys */ +static gboolean +key_press_epg_grid_view(GtkWidget * widget, + GdkEventKey * event, gpointer user_data) +{ + MMythEpgGridWidget *mmyth_epg_grid_widget = (MMythEpgGridWidget *) user_data; + + return mmyth_epg_grid_widget_key_press(mmyth_epg_grid_widget, widget, event); +} + +GtkWidget * +epg_grid_view_new (MMythUi* mmyth_ui) +{ + GtkWidget *scrolled_window; + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + gtk_widget_modify_bg(scrolled_window, GTK_STATE_NORMAL, &main_bg_color); + + GtkWidget *main_vbox = gtk_vbox_new (FALSE, 0); + //gtk_container_set_border_width(main_vbox, 4); + + GtkWidget *details_event_box = gtk_event_box_new(); + gtk_widget_modify_bg(details_event_box, GTK_STATE_NORMAL, &main_bg_color); + + program_details_area = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (details_event_box), + program_details_area); + gtk_container_set_border_width(GTK_CONTAINER (program_details_area), 4); + + details_main_hbox = gtk_hbox_new (FALSE, 10); + + gtk_box_pack_start (GTK_BOX (program_details_area), + details_main_hbox, FALSE, FALSE, 0); + + details_logo_vbox = gtk_vbox_new (FALSE, 0); + + GtkWidget *details_desc_vbox = gtk_vbox_new (FALSE, 0); + + gtk_box_pack_start (GTK_BOX (details_main_hbox), + details_desc_vbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (details_main_hbox), + details_logo_vbox, FALSE, FALSE, 0); + + gtk_widget_set_size_request (program_details_area, -1, 120); + + mmyth_epg_grid_widget = mmyth_epg_grid_widget_new(); + g_signal_connect(mmyth_epg_grid_widget, "selection_updated", + G_CALLBACK (update_service_details), NULL); + + /* select by default the first service */ + /* depends on mount services */ + if (MMYTH_EPG_GRID_WIDGET(mmyth_epg_grid_widget)->epg_view_model) { + GList *fst_service = (GList *) + MMYTH_EPG_GRID_WIDGET(mmyth_epg_grid_widget)->epg_view_model->data; + mmyth_epg_grid_widget_update_service(MMYTH_EPG_GRID_WIDGET(mmyth_epg_grid_widget), + fst_service); + } + + gtk_box_pack_start (GTK_BOX (main_vbox), + details_event_box, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (main_vbox), + gtk_hseparator_new(), FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (main_vbox), + mmyth_epg_grid_widget, FALSE, FALSE, 0); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), + main_vbox); + + /* Add hardware button listener to application */ + g_signal_connect(mmyth_ui->main_window, "key_press_event", + G_CALLBACK (key_press_epg_grid_view), mmyth_epg_grid_widget); + + gtk_widget_show_all (scrolled_window); + + return scrolled_window; +} + +/* +DVBHScheduleEvent * +mmyth_epg_grid_view_get_selected_schedule() +{ + return mmyth_epg_grid_get_selected_schedule + (MMYTH_EPG_GRID_WIDGET(mmyth_epg_grid_widget)); +} +*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_epg_grid_view.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_epg_grid_view.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,8 @@ +#ifndef MMYTH_ESG_GRID_VIEW_H_ +#define MMYTH_ESG_GRID_VIEW_H_ + +#include "mmyth_ui.h" + +GtkWidget *epg_grid_view_new(MMythUi * mmyth_ui); + +#endif /* MMYTH_ESG_GRID_VIEW_H_ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_epg_grid_widget.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_epg_grid_widget.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,622 @@ +#include +#include +#include + +#include "mmyth_uicommon.h" +#include "mmyth_epg_grid_widget.h" + +#include "gmyth_util.h" +#include "gmyth_epg.h" + +#define PIXELS_HOUR 105 +#define PROGRAM_SEPARATION 2 + +enum { + SELECTION_UPDATED_SIGNAL, + LAST_SIGNAL +}; + +struct _MMythEpgGridWidgetPrivate { + /* private widget components */ + GtkWidget *epg_channels_vbox; + GtkWidget *epg_programs_vbox; + + GHashTable *service_model_hash; + + /* guidegrid attributes */ + gboolean show_favorites; + gint current_start_channel_id; + + time_t current_start_time; + time_t current_end_time; + + guint selected_channel_index; + + /* GList of ProgramInfo for each Channel */ + GList * program_list[MAX_DISPLAY_CHANS]; + GList * channel_list; + + GMythEPG *mmyth_epg; + + gint DISPLAY_CHANS; +}; + +static void mmyth_epg_grid_widget_class_init (MMythEpgGridWidgetClass *klass); +static void mmyth_epg_grid_widget_init (MMythEpgGridWidget *object); +static void mmyth_epg_grid_widget_private_init (MMythEpgGridWidgetPrivate *private); +static void mmyth_epg_grid_widget_mount_services (MMythEpgGridWidget *object, + int start_time, int end_time); +static void mmyth_epg_grid_widget_mount_header (MMythEpgGridWidget *object); +static void mmyth_epg_grid_widget_clicked (GtkWidget* widget, + GdkEventExpose *event, + gpointer data); +static GtkWidget *create_event_box_lbl (gchar *str, int width, + const GdkColor *bg_color, + const GdkColor *fg_color); + +static void mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate *private); +static void mmyth_epg_grid_widget_fill_program_row_infos( + MMythEpgGridWidgetPrivate *private, + unsigned int chanNum, unsigned int row); + +static gint mmyth_epg_grid_widget_signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(MMythEpgGridWidget, mmyth_epg_grid_widget, GTK_TYPE_EVENT_BOX) + +static void +mmyth_epg_grid_widget_class_init (MMythEpgGridWidgetClass *klass) +{ + g_type_class_add_private (klass, sizeof (MMythEpgGridWidgetPrivate)); + + mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL] = g_signal_new ( + "selection_updated", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); +} + +static void +mmyth_epg_grid_widget_private_init (MMythEpgGridWidgetPrivate *private) +{ + time_t cur_time; + + g_return_if_fail(private != NULL); + + private->epg_channels_vbox = NULL; + private->epg_programs_vbox = NULL; + private->service_model_hash = NULL; + + private->show_favorites = FALSE; + private->current_start_channel_id = -1; + + /* Selected the first diplayable channel initially */ + private->selected_channel_index = 0; + + /* TODO fix the current start/end time */ + private->current_start_time = time(&cur_time); + private->current_end_time = time(&cur_time) + 10800; + + private->DISPLAY_CHANS = MAX_DISPLAY_CHANS; + + // TODO: Close the epg and unref it in dispose call + private->mmyth_epg = gmyth_epg_new (); + if (!gmyth_epg_connect (private->mmyth_epg)) { + g_warning ("[%s] Could not connect mysql handler to db", __FUNCTION__); + g_object_unref (private->mmyth_epg); + private->mmyth_epg = NULL; + } +} + +static void +mmyth_epg_grid_widget_init (MMythEpgGridWidget *mmyth_epg_grid_widget) +{ + MMythEpgGridWidgetPrivate *private = + MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); + + /* init private fields */ + mmyth_epg_grid_widget_private_init(private); + + mmyth_epg_grid_widget->epg_view_model = NULL; + mmyth_epg_grid_widget->selected_grid_item = NULL; + + GtkWidget *epg_event_box = GTK_WIDGET(mmyth_epg_grid_widget); + gtk_widget_modify_bg(epg_event_box, GTK_STATE_NORMAL, &main_bg_color); + gtk_widget_set_size_request (epg_event_box, 0, 125); + + GtkWidget *epg_main_hbox = gtk_hbox_new (FALSE, 10); + gtk_container_set_border_width(GTK_CONTAINER (epg_main_hbox), 10); + + gtk_container_add (GTK_CONTAINER (epg_event_box), + epg_main_hbox); + + /* channels vbox */ + GtkWidget *epg_channels_vbox = gtk_vbox_new (FALSE, 3); + private->epg_channels_vbox = epg_channels_vbox; + + /* programs vbox */ + GtkWidget *epg_programs_vbox = gtk_vbox_new (FALSE, 3); + private->epg_programs_vbox = epg_programs_vbox; + + /* packing start */ + gtk_box_pack_start (GTK_BOX (epg_main_hbox), + epg_channels_vbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (epg_main_hbox), + epg_programs_vbox, FALSE, FALSE, 0); + + /* table header (first line) */ + mmyth_epg_grid_widget_mount_header(mmyth_epg_grid_widget); + + /* service programs */ + /* mount service programs with current time */ + mmyth_epg_grid_widget_mount_services(mmyth_epg_grid_widget, + private->current_start_time, + private->current_end_time); +} + +GtkWidget* +mmyth_epg_grid_widget_new () +{ + return GTK_WIDGET ( gtk_type_new (mmyth_epg_grid_widget_get_type ())); +} + +static void +mmyth_epg_grid_widget_mount_services(MMythEpgGridWidget *mmyth_epg_grid_widget, + int start_time, int end_time) +{ + GList *proglist; + GList *channel_list = NULL; + GMythChannelInfo *channel_info; + + int chanid; + MMythEpgGridWidgetPrivate *private = + MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); + + // update view_model + /* FIXME shallow free or recursive? */ + if(mmyth_epg_grid_widget->epg_view_model != NULL) { + g_list_free(mmyth_epg_grid_widget->epg_view_model); + mmyth_epg_grid_widget->epg_view_model = NULL; + } + + if(private->service_model_hash != NULL) { + g_hash_table_destroy(private->service_model_hash); + } + + private->service_model_hash = g_hash_table_new(NULL, NULL); + + /* fill program infos from db */ + mmyth_epg_grid_widget_fill_programinfos(private); + + channel_list = private->channel_list; + + /* for each channel get_programs() */ + for (chanid=0; channel_list && + chanid < private->DISPLAY_CHANS; chanid++) { + proglist = (GList *) private->program_list[chanid]; + + channel_info = (GMythChannelInfo *) channel_list->data; + channel_list = g_list_next(channel_list); + + /* Service Title*/ + GString *name = NULL; + if (channel_info->channel_name) + name = g_string_new (channel_info->channel_name->str); + + GdkColor title_bg_color; + title_bg_color.red = 5000; + title_bg_color.green = 9000; + title_bg_color.blue = 40000; + + GdkColor title_fg_color; + title_fg_color.red = 60000; + title_fg_color.green = 60000; + title_fg_color.blue = 60000; + + GtkWidget *event_box_channel = create_event_box_lbl( + name->str, 90, + &title_bg_color, + &title_fg_color); + + gtk_box_pack_start (GTK_BOX (private->epg_channels_vbox), + event_box_channel, FALSE, FALSE, 0); + + GtkWidget *epg_line_hbox = gtk_hbox_new (FALSE, 0); + + GdkColor bg_color; + bg_color.red = 5000; + bg_color.green = 30000; + bg_color.blue = 60000; + + GdkColor fg_color; + fg_color.red = 60000; + fg_color.green = 60000; + fg_color.blue = 60000; + + /* Content parsing */ + GList *epg_grid_list = NULL; + + GMythProgramInfo *proginfo; + int pixel_count = 0; + for (; proglist; proglist = proglist->next) { + proginfo = (GMythProgramInfo *) proglist->data; + + GString *content_name = proginfo->title; + + int initial_time, last_time, duration; + + int schedule_start_time = proginfo->startts; + int schedule_end_time = proginfo->endts; + + initial_time = + (schedule_start_time < start_time) ? start_time : schedule_start_time; + last_time = (schedule_end_time > end_time) ? end_time : schedule_end_time; + duration = last_time - initial_time; + + // Verify program time + #if 0 + g_debug ("ServiceID: %d, ScheduleID: %d\n", service->id, schedule->id); + fprintf (stderr, "program time\nfrom = %d, to = %d\n", + schedule->validFrom, schedule->validTo); + + struct tm loctime; + + /* Convert it to local time representation. */ + if (localtime_r((time_t *)&schedule->validFrom, &loctime) == NULL) { + g_warning ("localtime_r error in mmyth_epg_grid_widget!\n"); + return NULL; + } + fprintf (stderr, asctime (&loctime)); + + if (localtime_r((time_t *)&schedule->validTo, &loctime) == NULL) { + g_warning ("localtime_r error in mmyth_epg_grid_widget!\n"); + return NULL; + } + fprintf (stderr, asctime (&loctime)); + #endif + + /* fprintf(stderr, "duration = %d\n", duration); */ + double duration_hour = duration / (double) 3600.0; + /* fprintf(stderr, "duration_hour = %lf\n", duration_hour); */ + + int size = PIXELS_HOUR * duration_hour; + + /* complete hour */ + /* FIXME: UGLY WRONG HACK TO ALIGN PROGRAM TIME!!!*/ + if(last_time%3600 != 0) { + size -= PROGRAM_SEPARATION; + } + if(initial_time%3600 != 0) { + size -= PROGRAM_SEPARATION; + } + + pixel_count += size + PROGRAM_SEPARATION; + GtkWidget *event_box = create_event_box_lbl(content_name->str, + size, &bg_color, + &fg_color); + gtk_widget_add_events(event_box, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + + /* create EpgGridItem */ + EpgGridItem *epg_grid_item = g_new(EpgGridItem, 1); + epg_grid_item->proginfo = proginfo; + epg_grid_item->event_box = event_box; + epg_grid_item->object = mmyth_epg_grid_widget; + + epg_grid_list = g_list_prepend(epg_grid_list, (gpointer) epg_grid_item); + + gtk_box_pack_start (GTK_BOX (epg_line_hbox), + event_box, FALSE, FALSE, PROGRAM_SEPARATION); + + g_signal_connect (G_OBJECT (event_box), "button-press-event", + G_CALLBACK (mmyth_epg_grid_widget_clicked), + (gpointer*) epg_grid_list); + } +#if 0 + printf("chaind = %d!!!!" chanid);fflush(stdout); +#endif + + if(!epg_grid_list) { + /* No programs for current channel */ + /* FIXME: size HARDCODED */ + GtkWidget *event_box = create_event_box_lbl("No program list available", + PIXELS_HOUR * 3, &bg_color, + &fg_color); + gtk_widget_add_events(event_box, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + + /* create EpgGridItem */ + EpgGridItem *epg_grid_item = g_new(EpgGridItem, 1); + epg_grid_item->proginfo = NULL; + epg_grid_item->event_box = event_box; + epg_grid_item->object = mmyth_epg_grid_widget; + + epg_grid_list = g_list_prepend(epg_grid_list, (gpointer) epg_grid_item); + + gtk_box_pack_start (GTK_BOX (epg_line_hbox), + event_box, FALSE, FALSE, PROGRAM_SEPARATION); + + g_signal_connect (G_OBJECT (event_box), "button-press-event", + G_CALLBACK (mmyth_epg_grid_widget_clicked), + (gpointer*) epg_grid_list); + } + + epg_grid_list = g_list_reverse(epg_grid_list); + mmyth_epg_grid_widget->epg_view_model = + g_list_append(mmyth_epg_grid_widget->epg_view_model, epg_grid_list); + + gtk_box_pack_start (GTK_BOX (private->epg_programs_vbox), + epg_line_hbox, FALSE, FALSE, 0); + } +} + +static void +mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget *mmyth_epg_grid_widget) +{ + MMythEpgGridWidgetPrivate *private = + MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); + + struct tm hour_tm; + const gchar name_title[] = "Today"; + GtkWidget * lbl_title = gtk_label_new(name_title); + + gtk_misc_set_alignment (GTK_MISC(lbl_title), 0.0, 0.5); + + gtk_box_pack_start (GTK_BOX (private->epg_channels_vbox), + lbl_title, FALSE, FALSE, 0); + + /* hours title line */ + GtkWidget *epg_programs_hours_hbox = gtk_hbox_new (TRUE, 0); + + if (localtime_r((time_t *)&private->current_start_time, &hour_tm) == NULL) { + g_warning ("localtime_r error in mmyth_epg_grid_widget!\n"); + return NULL; + } + + if (hour_tm.tm_min>30) { + hour_tm.tm_min = 30; + } else if (hour_tm.tm_min>0) { + hour_tm.tm_min = 0; + } + + gchar hour1_str[10]; + strftime(hour1_str, 8, "%H:%M", &hour_tm); + GtkWidget * lbl_hour1 = gtk_label_new(hour1_str); + gtk_misc_set_alignment (GTK_MISC(lbl_hour1), 0.0, 0.5); + + hour_tm.tm_hour++; + gchar hour2_str[10]; + strftime(hour2_str, 8, "%H:%M", &hour_tm); + GtkWidget * lbl_hour2 = gtk_label_new(hour2_str); + gtk_misc_set_alignment (GTK_MISC(lbl_hour2), 0.0, 0.5); + + hour_tm.tm_hour++; + gchar hour3_str[10]; + strftime(hour3_str, 8, "%H:%M", &hour_tm); + GtkWidget * lbl_hour3 = gtk_label_new(hour3_str); + gtk_misc_set_alignment (GTK_MISC(lbl_hour3), 0.0, 0.5); + + gtk_box_pack_start (GTK_BOX (epg_programs_hours_hbox), + lbl_hour1, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (epg_programs_hours_hbox), + lbl_hour2, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (epg_programs_hours_hbox), + lbl_hour3, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (private->epg_programs_vbox), + epg_programs_hours_hbox, FALSE, FALSE, 0); +} + +/****************************************************************************** + * INTERNAL CALLBACKS FOR STATE CHANGE * + *****************************************************************************/ +static void +mmyth_epg_grid_widget_deselect_service(MMythEpgGridWidget *mmyth_epg_grid_widget) +{ + EpgGridItem *epg_grid_item; + + /* deselect*/ + if(mmyth_epg_grid_widget->selected_grid_item != NULL) { + epg_grid_item = + (EpgGridItem*) mmyth_epg_grid_widget->selected_grid_item->data; + gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box), GTK_STATE_NORMAL); + } +} + +static void +mmyth_epg_grid_widget_clicked (GtkWidget* widget, + GdkEventExpose *event, gpointer data) +{ + g_return_if_fail(data != NULL); + + GList *epg_grid_item_list = (GList *) data; + EpgGridItem *epg_grid_item = (EpgGridItem *) epg_grid_item_list->data; + + /* update the selected service */ + mmyth_epg_grid_widget_update_service( epg_grid_item->object, (GList*) data ); +} + +void +mmyth_epg_grid_widget_update_service(MMythEpgGridWidget * object, + GList *selected_grid_list) +{ + g_return_if_fail(object != NULL); + g_return_if_fail(selected_grid_list != NULL); + + EpgGridItem *epg_grid_item = (EpgGridItem *) selected_grid_list->data; + + mmyth_epg_grid_widget_deselect_service(epg_grid_item->object); + + /* updating current selected schedule_item and schedule_list*/ + object->selected_grid_item = selected_grid_list; + + /* set state of the event box */ + gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box), GTK_STATE_SELECTED); + /* emit update signal for listeners */ + g_signal_emit(object, + mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL], + 0, + (gpointer) epg_grid_item); +} + +static GtkWidget * +create_event_box_lbl(gchar *str, int width, const GdkColor *bg_color, + const GdkColor *fg_color) +{ + GtkWidget *event_box = gtk_event_box_new(); + GtkWidget *lbl = gtk_label_new(str); + gtk_label_set_ellipsize(GTK_LABEL(lbl), PANGO_ELLIPSIZE_END); + + gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, bg_color); + gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, fg_color); + + /* selected colors are const*/ + GdkColor selected_bg_color; + selected_bg_color.red = 100; + selected_bg_color.green = 40000; + selected_bg_color.blue = 100; + + GdkColor selected_fg_color; + selected_fg_color.red = 100; + selected_fg_color.green = 100; + selected_fg_color.blue = 100; + + gtk_widget_modify_bg(event_box, GTK_STATE_SELECTED, &selected_bg_color); + gtk_widget_modify_fg(lbl, GTK_STATE_SELECTED, &selected_fg_color); + + gtk_misc_set_alignment (GTK_MISC(lbl), 0.0, 0.5); + gtk_container_add (GTK_CONTAINER (event_box), + lbl); + gtk_widget_set_size_request(event_box, width, -1); + + return event_box; +} + +/****************************************************************************** + * METHODS * + *****************************************************************************/ + +/* Callback for hardware keys */ +gboolean +mmyth_epg_grid_widget_key_press (MMythEpgGridWidget * object, + GtkWidget * widget, GdkEventKey * event) +{ + MMythEpgGridWidgetPrivate *private = + MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(object); + + EpgGridItem *epg_grid_item; + GList *tmp; + + /* List of selected_grid_item */ + GList *selected_view_model; + + gint channel_index; + + if(object->selected_grid_item == NULL) { + g_warning ("No program selected"); + return FALSE; + } + + epg_grid_item = (EpgGridItem*) object->selected_grid_item->data; + + channel_index = private->selected_channel_index; + + switch (event->keyval) { + case GDK_Up: + selected_view_model = g_list_nth( object->epg_view_model, channel_index - 1 ); + if(selected_view_model != NULL) { + private->selected_channel_index = channel_index - 1; + tmp = (GList *) selected_view_model->data; + /* TODO: select a better centralized item + currently is picking the 1st or last item */ + if(g_list_next(object->selected_grid_item) == NULL && + g_list_previous(object->selected_grid_item) != NULL) { + /* in this case the new selected will be the last */ + tmp = g_list_last(tmp); + } + + /* update the selected service */ + mmyth_epg_grid_widget_update_service( object, tmp ); + } + return TRUE; + case GDK_Down: + selected_view_model = g_list_nth( object->epg_view_model, channel_index + 1 ); + if(selected_view_model != NULL) { + private->selected_channel_index = channel_index + 1; + tmp = (GList *) selected_view_model->data; + /* TODO: select a better centralized item + currently is picking the 1st or last item */ + if(g_list_next(object->selected_grid_item) == NULL && + g_list_previous(object->selected_grid_item) != NULL) { + /* in this case the new selected will be the last */ + tmp = g_list_last(tmp); + } + + /* update the selected service */ + mmyth_epg_grid_widget_update_service( object, tmp ); + } + return TRUE; + case GDK_Left: + tmp = g_list_previous( object->selected_grid_item ); + if(tmp != NULL) { + /* update the selected service */ + mmyth_epg_grid_widget_update_service( object, tmp ); + } + return TRUE; + case GDK_Right: + tmp = g_list_next( object->selected_grid_item ); + if(tmp != NULL) { + /* update the selected service */ + mmyth_epg_grid_widget_update_service( object, tmp ); + } + return TRUE; + default: + return TRUE; + } + + return FALSE; +} + +static void +mmyth_epg_grid_widget_fill_programinfos (MMythEpgGridWidgetPrivate *private) +{ + GList *channels_list = NULL; + int y; + + if ((private->mmyth_epg != NULL) && + (gmyth_epg_get_channel_list (private->mmyth_epg, &channels_list) < 0 )) { + private->channel_list = NULL; + return; + } + + private->channel_list = channels_list; + + for (y = 0; y < private->DISPLAY_CHANS && channels_list; y++) { + GMythChannelInfo *channel_info = (GMythChannelInfo *) channels_list->data; + + mmyth_epg_grid_widget_fill_program_row_infos( + private, channel_info->channel_ID, y); + + channels_list = g_list_next (channels_list); + } +} + +static void +mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate *private, + guint chanNum, guint row) +{ + gint res = gmyth_epg_get_program_list (private->mmyth_epg, + &(private->program_list[row]), + chanNum, private->current_start_time, + private->current_end_time); + + if (res < 0) { + g_warning ("[%s] Error while retrieving epg programs", __FUNCTION__); + } +} + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_epg_grid_widget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_epg_grid_widget.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,74 @@ +#ifndef __MMYTH_EPG_GRID_WIDGET_H__ +#define __MMYTH_EPG_GRID_WIDGET_H__ + +#include +#include +#include +#include + +#include "gmyth_common.h" + +#define MAX_DISPLAY_CHANS 4 + +#define G_BEGIN_DECLS + +#define MMYTH_EPG_GRID_WIDGET_TYPE (mmyth_epg_grid_widget_get_type ()) +#define MMYTH_EPG_GRID_WIDGET(obj) (GTK_CHECK_CAST ((obj), MMYTH_EPG_GRID_WIDGET_TYPE, MMythEpgGridWidget)) +#define MMYTH_EPG_GRID_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), MMYTH_EPG_GRID_WIDGET_TYPE, MMythEpgGridWidgetClass)) +#define IS_MMYTH_EPG_GRID_WIDGET(obj) (GTK_CHECK_TYPE ((obj), MMYTH_EPG_GRID_WIDGET_TYPE)) +#define IS_MMYTH_EPG_GRID_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), MMYTH_EPG_GRID_WIDGET_TYPE)) +#define MMYTH_EPG_GRID_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MMYTH_EPG_GRID_WIDGET_TYPE, MMythEpgGridWidgetClass)) +#define MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MMYTH_EPG_GRID_WIDGET_TYPE, MMythEpgGridWidgetPrivate)) + + +typedef struct _MMythEpgGridWidget MMythEpgGridWidget; +typedef struct _MMythEpgGridWidgetClass MMythEpgGridWidgetClass; +typedef struct _MMythEpgGridWidgetPrivate MMythEpgGridWidgetPrivate; + +struct _MMythEpgGridWidgetClass +{ + GtkEventBoxClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _MMythEpgGridWidget +{ + GtkEventBox event_box; + + /* Selected Widgets Logic*/ + /* List os Service Model in the current view + * the data of this list are GList for the programs + * of each service */ + GList *epg_view_model; + + /* Selected Schedule Item*/ + GList *selected_grid_item; +}; + + +GType mmyth_epg_grid_widget_get_type (void); +GtkWidget* mmyth_epg_grid_widget_new (void); +/*DVBHScheduleEvent* mmyth_epg_grid_get_selected_schedule (MMythEpgGridWidget * object);*/ +void mmyth_epg_grid_widget_update_service (MMythEpgGridWidget * object, + GList *epg_grid_item_node); +gboolean mmyth_epg_grid_widget_key_press (MMythEpgGridWidget * object, + GtkWidget * widget, + GdkEventKey * event); + +typedef struct _EpgGridItem EpgGridItem; + +/* FIXME: auxiliary struct */ +struct _EpgGridItem { + + GMythProgramInfo *proginfo; + GtkWidget *event_box; + + /* for callback purposes */ + MMythEpgGridWidget *object; +}; + +#define G_END_DECLS + +#endif /* __MMYTH_EPG_GRID_WIDGET_H__ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_recordui.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_recordui.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,332 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mmyth_ui.h" +#include "mmyth_recordui.h" + +/* GMyth library includes */ +#include "gmyth_scheduler.h" +#include "gmyth_util.h" + +enum { + START_DATE_COLUMN = 0, + TITLE_COLUMN, + CHAN_ID_COLUMN, + END_TIME_COLUMN, + RECORD_ID_COLUMN, + BASENAME_COLUMN, + N_COLUMNS +}; + +gboolean +mmyth_recordui_reload_all (MMythRecordUI *recordui) +{ + gboolean res = FALSE; + + res = mmyth_recordui_reload_schedule (recordui); + + res = res & mmyth_recordui_reload_record (recordui); + + + if (!res) + g_warning ("[%s] Error while reloading schedule and recording content", __FUNCTION__); + + return res; +} + +gboolean +mmyth_recordui_reload_schedule (MMythRecordUI *recordui) +{ + gint new_row = 0; + ScheduleInfo *schedule_info; + GList *schedule_list; + GtkTreeIter iter; + GString *start_date_time = NULL; + GString *end_date_time = NULL; + GString *str_aux = g_string_new(""); + gint res; + + gtk_tree_store_clear(recordui->sch_tree_store); + + res = gmyth_scheduler_get_schedule_list(recordui->scheduler, &(schedule_list)); + if (res < 0) { + g_warning ("[%s] Retrieved NULL list of scheduled data from database", + __FUNCTION__); + return FALSE; + } + + for ( ; schedule_list; schedule_list = schedule_list->next) { + schedule_info = (ScheduleInfo*) schedule_list->data; + + gtk_tree_store_insert(recordui->sch_tree_store, &iter, NULL, new_row++); + + start_date_time = gmyth_util_time_to_string(schedule_info->start_time); + end_date_time = gmyth_util_time_to_string(schedule_info->end_time); + + g_string_printf(str_aux, "%d", schedule_info->channel_id); + + gtk_tree_store_set(recordui->sch_tree_store, &iter, + START_DATE_COLUMN, start_date_time->str, + TITLE_COLUMN, schedule_info->title->str, + CHAN_ID_COLUMN, str_aux->str, + END_TIME_COLUMN, end_date_time->str, //It doesn't appear + RECORD_ID_COLUMN, schedule_info->record_id, + -1); //the last line is a hidden item to be used in searching tasks + } + + g_debug ("[%s] %d lines added to schedule list UI", __FUNCTION__, new_row); + + /* free allocated memory */ + if(!start_date_time) + g_string_free(start_date_time, FALSE); + if(!end_date_time) + g_string_free(end_date_time, FALSE); + g_string_free(str_aux, FALSE); + + return TRUE; +} + +gboolean +mmyth_recordui_reload_record (MMythRecordUI *recordui) +{ + gint new_row = 0; + RecordedInfo *recorded_info; + GList *record_list = NULL; + GtkTreeIter iter; + GString *start_date_time = NULL; + GString *end_date_time = NULL; + GString *str_aux = g_string_new(""); + gint res; + + gtk_tree_store_clear(recordui->rec_tree_store); + + res = gmyth_scheduler_get_recorded_list(recordui->scheduler, &record_list); + if (res < 0) { + g_warning ("[%s] Retrieved NULL list of recorded data from database", __FUNCTION__); + return FALSE; + } + + for (; record_list; record_list = record_list->next) { + recorded_info = (RecordedInfo*) record_list->data; + + gtk_tree_store_insert(recordui->rec_tree_store, &iter, NULL, new_row++); + + start_date_time = gmyth_util_time_to_string(recorded_info->start_time); + end_date_time = gmyth_util_time_to_string(recorded_info->end_time); + + g_string_printf(str_aux, "%d", recorded_info->channel_id); + + gtk_tree_store_set(recordui->rec_tree_store, &iter, + START_DATE_COLUMN, start_date_time->str, + TITLE_COLUMN, recorded_info->title->str, + CHAN_ID_COLUMN, str_aux->str, + END_TIME_COLUMN, end_date_time->str, //It doesn't appear + RECORD_ID_COLUMN, recorded_info->record_id, + BASENAME_COLUMN, recorded_info->basename->str, -1); + //the last line is a hidden item to be used in searching tasks + } + + g_debug ("[%s] %d lines added to record list UI", __FUNCTION__, new_row); + + return TRUE; +} + + +MMythRecordUI* +mmyth_recordui_new(void) +{ + MMythRecordUI *recordui = g_new0 (MMythRecordUI, 1); + + recordui->scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (recordui->scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + recordui->viewport = gtk_viewport_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (recordui->scrolled_window), recordui->viewport); + + recordui->notebook = gtk_notebook_new (); + gtk_container_set_border_width (GTK_CONTAINER (recordui->notebook), 1); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (recordui->notebook), TRUE); + gtk_notebook_popup_enable (GTK_NOTEBOOK (recordui->notebook)); + gtk_container_add (GTK_CONTAINER (recordui->viewport), recordui->notebook); + gtk_notebook_popup_disable(GTK_NOTEBOOK (recordui->notebook)); + + /* Schedule tab */ + recordui->sch_scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (recordui->notebook), recordui->sch_scrolled_window); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (recordui->sch_scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (recordui->sch_scrolled_window), + GTK_SHADOW_IN); + + /* The basename column in the sched_tree_store is not being used*/ + recordui->sch_tree_store = + gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING ); + + recordui->sch_treeview = + gtk_tree_view_new_with_model(GTK_TREE_MODEL(recordui->sch_tree_store)); + gtk_container_add (GTK_CONTAINER (recordui->sch_scrolled_window), + recordui->sch_treeview); + recordui->sch_renderer = gtk_cell_renderer_text_new(); + //g_object_set(G_OBJECT(renderer1), "foreground", "green", "background", "black", NULL); + recordui->sch_column1 = + gtk_tree_view_column_new_with_attributes("Start time", recordui->sch_renderer, + "text", START_DATE_COLUMN, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->sch_treeview), + recordui->sch_column1); + recordui->sch_column2 = + gtk_tree_view_column_new_with_attributes("Title", recordui->sch_renderer, + "text", TITLE_COLUMN, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->sch_treeview), + recordui->sch_column2); + recordui->sch_column3 = + gtk_tree_view_column_new_with_attributes("Channel", recordui->sch_renderer, + "text", CHAN_ID_COLUMN, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->sch_treeview), + recordui->sch_column3); + gtk_tree_view_column_set_resizable(recordui->sch_column1, TRUE); + gtk_tree_view_column_set_resizable(recordui->sch_column2, TRUE); + gtk_tree_view_column_set_resizable(recordui->sch_column3, TRUE); + gtk_tree_view_column_set_reorderable(recordui->sch_column1, TRUE); + gtk_tree_view_column_set_reorderable(recordui->sch_column2, TRUE); + gtk_tree_view_column_set_reorderable(recordui->sch_column3, TRUE); +// recordui->sch_column4 = +// gtk_tree_view_column_new_with_attributes("", recordui->sch_renderer, "text", END_TIME_COLUMN, NULL); +// gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->sch_treeview), +// recordui->sch_column4); + + recordui->sch_label = gtk_label_new (("Schedule")); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (recordui->notebook), + gtk_notebook_get_nth_page ( + GTK_NOTEBOOK (recordui->notebook), 0), + recordui->sch_label); + + // Record items tab + // g_object_set(G_OBJECT(renderer2), "foreground", "blue", NULL); + recordui->rec_scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (recordui->notebook), + recordui->rec_scrolled_window); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (recordui->rec_scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (recordui->rec_scrolled_window), + GTK_SHADOW_IN); + + recordui->rec_tree_store = + gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING); + recordui->rec_treeview = + gtk_tree_view_new_with_model(GTK_TREE_MODEL(recordui->rec_tree_store)); + gtk_container_add (GTK_CONTAINER (recordui->rec_scrolled_window), + recordui->rec_treeview); + recordui->rec_renderer = gtk_cell_renderer_text_new(); + //g_object_set(G_OBJECT(renderer1), "foreground", "green", "background", "black", NULL); + + recordui->rec_column1 = + gtk_tree_view_column_new_with_attributes("Start time", recordui->rec_renderer, + "text", START_DATE_COLUMN, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->rec_treeview), + recordui->rec_column1); + recordui->rec_column2 = + gtk_tree_view_column_new_with_attributes("Title", recordui->rec_renderer, + "text", TITLE_COLUMN, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->rec_treeview), + recordui->rec_column2); + recordui->rec_column3 = + gtk_tree_view_column_new_with_attributes("Channel", recordui->rec_renderer, + "text", CHAN_ID_COLUMN, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->rec_treeview), + recordui->rec_column3); + gtk_tree_view_column_set_resizable(recordui->rec_column1, TRUE); + gtk_tree_view_column_set_resizable(recordui->rec_column2, TRUE); + gtk_tree_view_column_set_resizable(recordui->rec_column3, TRUE); + gtk_tree_view_column_set_reorderable(recordui->rec_column1, TRUE); + gtk_tree_view_column_set_reorderable(recordui->rec_column2, TRUE); + gtk_tree_view_column_set_reorderable(recordui->rec_column3, TRUE); +// recordui->rec_column4 = gtk_tree_view_column_new_with_attributes("", recordui->rec_renderer, "text", END_TIME_COLUMN, NULL); +// gtk_tree_view_append_column(GTK_TREE_VIEW(recordui->rec_treeview), recordui->rec_column4); + + recordui->rec_label = gtk_label_new (("Recorded")); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (recordui->notebook), + gtk_notebook_get_nth_page ( + GTK_NOTEBOOK (recordui->notebook), 1), + recordui->rec_label); + + // Gets the mmyth scheduler manager + recordui->scheduler = gmyth_scheduler_new (); + + /* init connection to the backend */ + gmyth_scheduler_connect (recordui->scheduler); + + return recordui; +} + +void +mmyth_recordui_free (MMythRecordUI *recordui) +{ + // FIXME: Release memory here! + /* close connection to the backend */ + gmyth_scheduler_disconnect (recordui->scheduler); +} + +void +mmyth_recordui_delete_selected (GtkButton *button, MMythRecordUI *recordui) +{ + GtkTreeSelection *selection; + GtkTreeModel *list_store; + GtkTreeIter iter; + int index; + int curr_page = 0; + + curr_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(recordui->notebook)); + + if ( curr_page == 0) { + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(recordui->sch_treeview)); + if (selection != NULL) { + gtk_tree_selection_get_selected(selection, &list_store, &iter); + gtk_tree_model_get(list_store, &iter, RECORD_ID_COLUMN, &index, -1); + gmyth_scheduler_delete_schedule(recordui->scheduler, index); + mmyth_recordui_reload_schedule (recordui); + return; + } + + } else if (curr_page == 1) { + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(recordui->rec_treeview)); + if (selection != NULL) { + gtk_tree_selection_get_selected(selection, &list_store, &iter); + gtk_tree_model_get(list_store, &iter, RECORD_ID_COLUMN, &index, -1); + gmyth_scheduler_delete_recorded(recordui->scheduler, index); + mmyth_recordui_reload_record (recordui); + return; + } + } + + g_warning ("[%s] None element was removed from the list", __FUNCTION__); +} + +/* FIXME: change this function name, it is returning the + * basename_column that represents the nuv filename of + * the recorded content */ +gchar* +mmyth_recordui_get_selected_recorded (MMythRecordUI *recordui) +{ + GtkTreeSelection *selection = NULL; + GtkTreeModel *list_store = NULL; + GtkTreeIter iter; + gchar *path = NULL; + + /* returning nuv filename, basename_column */ + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(recordui->rec_treeview)); + if (gtk_tree_selection_get_selected (selection, &list_store, &iter)) { + gtk_tree_model_get(list_store, &iter, BASENAME_COLUMN, &path, -1); + } + + // FIXME: MOVE THIS TO OTHER PLACE + return path; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_recordui.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_recordui.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,48 @@ +#ifndef MMYTH_RECORD_H_ +#define MMYTH_RECORD_H_ + +#include "gmyth_scheduler.h" + +typedef struct _MMythRecordUI +{ + GtkWidget *scrolled_window; + GtkWidget *viewport; + GtkWidget *notebook; + + GtkWidget *rec_scrolled_window; + GtkWidget *sch_scrolled_window; + GtkWidget *rec_treeview; + GtkWidget *sch_treeview; + GtkWidget *rec_label; + GtkWidget *sch_label; + + GtkTreeViewColumn *rec_column1; + GtkTreeViewColumn *rec_column2; + GtkTreeViewColumn *rec_column3; + GtkTreeViewColumn *rec_column4; + GtkTreeViewColumn *sch_column1; + GtkTreeViewColumn *sch_column2; + GtkTreeViewColumn *sch_column3; + GtkTreeViewColumn *sch_column4; + + GtkCellRenderer *rec_renderer; + GtkCellRenderer *sch_renderer; + + GtkTreeStore *sch_tree_store; + GtkTreeStore *rec_tree_store; + + GMythScheduler *scheduler; + +} MMythRecordUI; + +MMythRecordUI* mmyth_recordui_new(void); +void mmyth_recordui_free (MMythRecordUI *recordui); + +void mmyth_recordui_delete_selected (GtkButton *button, MMythRecordUI *recordui); +gboolean mmyth_recordui_reload_all (MMythRecordUI *recordui); +gboolean mmyth_recordui_reload_schedule (MMythRecordUI *recordui); +gboolean mmyth_recordui_reload_record (MMythRecordUI *recordui); + +gchar* mmyth_recordui_get_selected_recorded (MMythRecordUI *recordui); + +#endif /*MMYTH_RECORD_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_schedulerui.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_schedulerui.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mmyth_ui.h" +#include "mmyth_uicommon.h" +#include "mmyth_recordui.h" +#include "mmyth_schedulerui.h" + +/* GMyth library includes */ +#include "gmyth_scheduler.h" +#include "gmyth_common.h" +#include "gmyth_epg.h" + +static void run_calendar_dialog (GtkButton *button, gpointer data); + +static void add_channel_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox); +static void add_time_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox); +static void add_date_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox); +static void add_duration_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox); +static void add_frequency_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox); +static void add_title_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox); + +MMythSchedulerUI* +mmyth_schedulerui_new (void) +{ + GtkWidget *scrolledwindow; + GtkWidget *viewport; + GtkWidget *head_hbox; + GtkWidget *fields_vbox; + GtkWidget *hseparator; + GtkWidget *label; + + MMythSchedulerUI *scheduler_ui = g_new0 (MMythSchedulerUI, 1); + + scrolledwindow = gtk_scrolled_window_new (NULL, NULL); + scheduler_ui->main_widget = scrolledwindow; + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + //Is this needed? + viewport = gtk_viewport_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolledwindow), viewport); + + //Is this needed? + head_hbox = gtk_hbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (viewport), head_hbox); + + fields_vbox = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (head_hbox), fields_vbox, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (fields_vbox), 10); + + label = gtk_label_new_with_mnemonic (("Manual Schedule Recording")); + gtk_box_pack_start (GTK_BOX (fields_vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (fields_vbox), hseparator, FALSE, TRUE, 0); + + add_channel_field (scheduler_ui, fields_vbox); + add_time_field (scheduler_ui, fields_vbox); + add_date_field (scheduler_ui, fields_vbox); + add_duration_field (scheduler_ui, fields_vbox); + add_frequency_field (scheduler_ui, fields_vbox); + add_title_field (scheduler_ui, fields_vbox); + + return scheduler_ui; +} + +static void +set_date_from_calendar (GtkCalendar *calendar, gpointer data) +{ + char sched_date[24]; + + MMythSchedulerUI *scheduler_ui = (MMythSchedulerUI*) data; + + // FIXME: Change this, save another value instead of month_temp, day_temp, ... + gtk_calendar_get_date(GTK_CALENDAR(calendar), + &(scheduler_ui->year_temp), &(scheduler_ui->month_temp), &(scheduler_ui->day_temp)); + + sched_date[23]='\0'; + g_sprintf(sched_date, "%04d %02d %02d (yyyy mm dd)", + scheduler_ui->year_temp, scheduler_ui->month_temp+1, scheduler_ui->day_temp); + + gtk_button_set_label(GTK_BUTTON(scheduler_ui->date_button), sched_date); + + gtk_widget_destroy(scheduler_ui->calendar_dialog); + scheduler_ui->calendar_dialog = NULL; + scheduler_ui->calendar = NULL; +} + +//calendar +static void +run_calendar_dialog (GtkButton *button, gpointer data) +{ + + GtkWidget *dialog_vbox; + MMythSchedulerUI *scheduler_ui = (MMythSchedulerUI*) data; + + // calendar_dialog and calendar are been released at set_date_from_calendar () + scheduler_ui->calendar_dialog = gtk_dialog_new (); + gtk_container_set_border_width (GTK_CONTAINER (scheduler_ui->calendar_dialog), 1); + gtk_window_set_title (GTK_WINDOW (scheduler_ui->calendar_dialog), "Select starting date"); + gtk_window_set_position (GTK_WINDOW (scheduler_ui->calendar_dialog), GTK_WIN_POS_CENTER); + gtk_window_set_decorated (GTK_WINDOW (scheduler_ui->calendar_dialog), FALSE); + + dialog_vbox = GTK_DIALOG (scheduler_ui->calendar_dialog)->vbox; + + scheduler_ui->calendar = gtk_calendar_new (); + + gtk_box_pack_start (GTK_BOX (dialog_vbox), scheduler_ui->calendar, TRUE, TRUE, 0); + gtk_calendar_display_options (GTK_CALENDAR (scheduler_ui->calendar), + GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES); + + gtk_widget_show_all (scheduler_ui->calendar_dialog); + + g_signal_connect (G_OBJECT (scheduler_ui->calendar), "day-selected-double-click", + G_CALLBACK (set_date_from_calendar), data); +} + + +gboolean +mmyth_schedulerui_save (MMythSchedulerUI *scheduler_ui) +{ + GMythScheduler *scheduler; + ScheduleInfo *schedule_info; + GMythChannelInfo *channel_info; + + GList *clist; + gint index, duration; + gint frequency; + struct tm start_tm; + + schedule_info = g_new0(ScheduleInfo, 1); + if(schedule_info == NULL) { + g_warning ("Error allocating memory"); + return FALSE; + } + + clist = scheduler_ui->channel_list; + + index = gtk_combo_box_get_active(GTK_COMBO_BOX(scheduler_ui->channel_combobox)); + + if (clist != NULL) + clist = g_list_nth(clist, index); + + if (clist) { + g_debug ("[%s] New schedule: %d", __FUNCTION__, index); + } else { + g_warning ("[%s] Error when adding new schedule", __FUNCTION__); + return FALSE; + } + + channel_info = clist->data; + + /* initialize schedule_info */ + schedule_info->channel_id = channel_info->channel_ID; + + start_tm.tm_hour = + (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(scheduler_ui->hour_spinbutton)); + start_tm.tm_min = + (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(scheduler_ui->min_spinbutton)); + start_tm.tm_sec = 0; + + start_tm.tm_mday = (gint)scheduler_ui->day_temp; + start_tm.tm_mon = (gint)scheduler_ui->month_temp; + start_tm.tm_year = (gint)scheduler_ui->year_temp - 1900; //years since 1900 + + schedule_info->start_time = timelocal(&start_tm); + if (schedule_info->start_time == (time_t)(-1)) { + g_warning ("timelocal error!\n"); + return FALSE; + } + + duration = (gint) gtk_spin_button_get_value( + GTK_SPIN_BUTTON(scheduler_ui->duration_spinbutton)); + schedule_info->end_time = schedule_info->start_time + (duration*60); + + /* TODO: frequency is not implemented yet */ + frequency = gtk_combo_box_get_active(GTK_COMBO_BOX(scheduler_ui->freq_combobox)); + + schedule_info->title = g_string_new(""); + g_string_printf(schedule_info->title, "%s", + gtk_entry_get_text(GTK_ENTRY(scheduler_ui->title_entry))); + + /* FIXME: Architecture change to reuse the scheduler created in the recordui! */ + scheduler = gmyth_scheduler_new (); + + gmyth_scheduler_connect(scheduler); + + /* FIXME: set record_id = -1 to add a new schedule */ + schedule_info->record_id = -1; + gmyth_scheduler_add_schedule (scheduler, schedule_info); + + gmyth_scheduler_disconnect(scheduler); + + /* free allocated memory */ + g_object_unref (scheduler); + g_free (schedule_info); + + return TRUE; +} + +static GtkWidget* +add_line (GtkWidget *vbox, const gchar *str) +{ + GtkWidget *label; + GtkWidget *hbox = gtk_hbox_new (FALSE, 0); + + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 3); + + label = gtk_label_new (str); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + return hbox; +} + +static void +add_channel_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox) +{ + GtkWidget *combobox; + + GtkWidget *hbox = add_line (vbox, "Channel: "); + + combobox = gtk_combo_box_new_text (); + + scheduler_ui->channel_combobox = combobox; + gtk_box_pack_start (GTK_BOX (hbox), combobox, FALSE, FALSE, 0); + + GMythEPG *mmyth_epg = gmyth_epg_new (); + if (!gmyth_epg_connect (mmyth_epg)) { + // FIXME: Without this list the scheduler UI should not be shown! + g_warning ("[%s] Error when getting list of channels", __FUNCTION__); + } + + if (gmyth_epg_get_channel_list (mmyth_epg, &(scheduler_ui->channel_list)) < 0) { + g_debug ("[%s] Error while trying to retrieve channel list", __FUNCTION__); + } else { + GList *clist = scheduler_ui->channel_list; + GMythChannelInfo *channel_info; + + while (clist != NULL) { + channel_info = clist->data; + clist = clist->next; + gtk_combo_box_append_text (GTK_COMBO_BOX (scheduler_ui->channel_combobox), + (channel_info->channel_name->str)); + } + + gtk_combo_box_set_active(GTK_COMBO_BOX (scheduler_ui->channel_combobox), 0); + } +} + +static void +add_time_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox) +{ + GtkWidget *label; + GtkObject *spinbutton_adj; + GtkWidget *hbox = add_line (vbox, "Time: "); + + time_t real_time; + struct tm sched_time; + + time(&real_time); + + if (localtime_r((time_t *)&real_time, &sched_time) == NULL) { + g_warning ("localtime_r error in mmyth_epg_grid_view!\n"); + return NULL; + } + + if (sched_time.tm_min>30){ + sched_time.tm_hour = sched_time.tm_hour+1; + sched_time.tm_min = 0; + } else if (sched_time.tm_min>0) { + sched_time.tm_min = 30; + } + + scheduler_ui->year_temp = (guint)sched_time.tm_year + 1900; + scheduler_ui->month_temp = (guint)sched_time.tm_mon; + scheduler_ui->day_temp = (guint)sched_time.tm_mday; + + //hour entry + spinbutton_adj = gtk_adjustment_new (sched_time.tm_hour, 00, 23, 1, 10, 10); + scheduler_ui->hour_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_adj), 1, 0); + gtk_box_pack_start (GTK_BOX (hbox), scheduler_ui->hour_spinbutton, FALSE, FALSE, 0); + + label = gtk_label_new ((" : ")); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + //minute entry + spinbutton_adj = gtk_adjustment_new (sched_time.tm_min, 0, 59, 1, 10, 10); + scheduler_ui->min_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_adj), 1, 0); + gtk_box_pack_start (GTK_BOX (hbox), scheduler_ui->min_spinbutton, FALSE, FALSE, 0); + + label = gtk_label_new ((" (hh:mm)")); + + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + +} + +static void +add_date_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox) +{ + char sched_date[24]; + GtkWidget *hbox = add_line (vbox, "Date: "); + + //sched_date = ctime(&real_time); + g_sprintf (sched_date, "%04d %02d %02d (yyyy mm dd)", scheduler_ui->year_temp, scheduler_ui->month_temp+1, scheduler_ui->day_temp); + sched_date[23]='\0'; + + scheduler_ui->date_button = gtk_button_new_with_label (sched_date); + gtk_box_pack_start (GTK_BOX (hbox), scheduler_ui->date_button, FALSE, FALSE, 0); + gtk_button_set_relief (GTK_BUTTON (scheduler_ui->date_button), GTK_RELIEF_NONE); + + g_signal_connect (G_OBJECT (scheduler_ui->date_button), "clicked", + G_CALLBACK (run_calendar_dialog), scheduler_ui); + +} + +static void +add_duration_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox) +{ + GtkWidget *hbox = add_line (vbox, "Duration: "); + GtkWidget *label; + GtkObject *spinbutton_adj; + + spinbutton_adj = gtk_adjustment_new (60, 5, 360, 5, 60, 60); + scheduler_ui->duration_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton_adj), 1, 0); + gtk_box_pack_start (GTK_BOX (hbox), scheduler_ui->duration_spinbutton, FALSE, TRUE, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (scheduler_ui->duration_spinbutton), TRUE); + + label = gtk_label_new ((" (minutes) ")); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); +} + +static void +add_frequency_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox) +{ + + GtkWidget *hbox = add_line (vbox, "Frequency: "); + + scheduler_ui->freq_combobox = gtk_combo_box_new_text (); + gtk_box_pack_start (GTK_BOX (hbox), scheduler_ui->freq_combobox, FALSE, FALSE, 0); + gtk_combo_box_append_text (GTK_COMBO_BOX (scheduler_ui->freq_combobox), ("Only this day ")); + gtk_combo_box_append_text (GTK_COMBO_BOX (scheduler_ui->freq_combobox), ("Daily ")); + gtk_combo_box_append_text (GTK_COMBO_BOX (scheduler_ui->freq_combobox), ("Weekly ")); + gtk_combo_box_set_active(GTK_COMBO_BOX (scheduler_ui->freq_combobox), 0); + +} + +static void +add_title_field (MMythSchedulerUI *scheduler_ui, GtkWidget *vbox) +{ + GtkWidget *hbox = add_line (vbox, "Title: "); + + scheduler_ui->title_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (hbox), scheduler_ui->title_entry, FALSE, FALSE, 0); + gtk_entry_set_text (GTK_ENTRY (scheduler_ui->title_entry), "(Optional)"); + +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_schedulerui.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_schedulerui.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,45 @@ +#ifndef MMYTH_SCHEDULERECORDING_H_ +#define MMYTH_SCHEDULERECORDING_H_ + +#include + +typedef struct _MMythSchedulerUI { + + GList *channel_list; + + GtkWidget *main_widget; + + GtkWidget *channel_combobox; + GtkWidget *freq_combobox; + GtkWidget *hour_spinbutton; + GtkWidget *min_spinbutton; + GtkWidget *duration_spinbutton; + GtkWidget *title_entry; + GtkWidget *date_button; + + GtkWidget *calendar_dialog; + GtkWidget *calendar; + + guint year_temp, month_temp, day_temp; +} MMythSchedulerUI; + +typedef struct { + long int channel_id; + + struct tm start_tm; + + int duration; + int frequency; + + GString *title; + +} ScheduleEntry; + +MMythSchedulerUI* mmyth_schedulerui_new (void); + +gboolean mmyth_schedulerui_save (MMythSchedulerUI *scheduler_ui); + +void mmyth_schedulerui_cb_schedule_button (GtkButton * button, gpointer user_data); + + +#endif /*MMYTH_SCHEDULERECORDING_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_ui.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_ui.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,814 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mmyth_ui.h" +#include "mmyth_uicommon.h" +#include "mmyth_schedulerui.h" +#include "mmyth_recordui.h" +#include "mmyth_uisettings.h" +#include "mmyth_epg_grid_view.h" + +/* GMyth library includes */ +#include "gmyth_context.h" +#include "gmyth_tvplayer.h" + +#ifndef MAEMO_PLATFORM +static gint button_press_handler (GtkWidget *widget, GdkEvent *event); +#endif + +static MMythUiCommon *create_main_view (MMythUi * mmyth_ui); +static MMythUiCommon *create_video_view (MMythUi * mmyth_ui); +static MMythUiCommon *create_epg_grid_view (MMythUi * mmyth_ui); +static MMythUiCommon *create_record_view (MMythUi * mmyth_ui); +static MMythUiCommon *create_schedule_view (MMythUi * mmyth_ui); + +static void cb_video_close_button (GtkButton * button, gpointer user_data); +static void cb_record_button (GtkButton * button, gpointer user_data); +static void cb_menu_item_settings (GtkMenuItem *menuitem, gpointer user_data); + +/* main box from button box separator*/ +static GtkWidget *main_vseparator = NULL; + +GdkPixbuf *icon_sports, *icon_news, + *icon_movies, *icon_shows, *icon_default; + +#ifndef MAEMO_PLATFORM +/* FIXME: */ +static MMythUi *popup_mmyth_ui; +#endif + +MMythUi * +mmyth_ui_initialize ( +#ifdef MAEMO_PLATFORM + HildonProgram *program, +#endif + GtkWidget * main_window) +{ + MMythUi *mmyth_ui; + + mmyth_ui = g_new0 (MMythUi, 1); + + mmyth_ui->main_window = main_window; + mmyth_ui->videow = NULL; + mmyth_ui->mmyth_recordui = NULL; + mmyth_ui->mmyth_schedulerui = NULL; + + /* Horizontal box that divides the view into control and video area */ + mmyth_ui->main_hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (mmyth_ui->main_hbox); + g_object_ref (mmyth_ui->main_hbox); + + main_bg_color.red = 65000; + main_bg_color.green = 65000; + main_bg_color.blue = 65000; + + +#ifndef MAEMO_PLATFORM + /* Popup menu */ + popup_mmyth_ui = mmyth_ui; + g_signal_connect (G_OBJECT (mmyth_ui->main_hbox), "event", + G_CALLBACK (button_press_handler), + G_OBJECT (mmyth_ui->main_hbox)); + +#else // #ifdef MAEMO + + mmyth_ui->main_menu = GTK_MENU(gtk_menu_new()); + hildon_program_set_common_menu(program, mmyth_ui->main_menu); + + mmyth_ui->menu_setup = gtk_menu_item_new_with_label("Setup"); + gtk_widget_set_size_request (GTK_WIDGET (mmyth_ui->menu_setup), 150, 40); + gtk_menu_append(mmyth_ui->main_menu, mmyth_ui->menu_setup); + + g_signal_connect(G_OBJECT(mmyth_ui->menu_setup), "activate", G_CALLBACK(cb_menu_item_settings), mmyth_ui); + + gtk_widget_show_all (GTK_WIDGET (mmyth_ui->main_menu)); +#endif + + // Main widget is mmyth_ui->main_hbox + mmyth_ui->main_uicommon = create_main_view (mmyth_ui); + + gtk_container_add (GTK_CONTAINER (mmyth_ui->main_window), + mmyth_ui->main_hbox); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); + + return mmyth_ui; +} + +void +mmyth_ui_finalize (MMythUi * mmyth_ui) +{ + if (mmyth_ui != NULL) { + if (mmyth_ui->main_uicommon) + mmyth_uicommon_free (mmyth_ui->main_uicommon); + if (mmyth_ui->video_uicommon) + mmyth_uicommon_free (mmyth_ui->video_uicommon); + if (mmyth_ui->epg_grid_uicommon) + mmyth_uicommon_free (mmyth_ui->epg_grid_uicommon); + if (mmyth_ui->record_uicommon) + mmyth_uicommon_free (mmyth_ui->record_uicommon); + if (mmyth_ui->schedule_uicommon) + mmyth_uicommon_free (mmyth_ui->schedule_uicommon); + + g_free (mmyth_ui); + } +} + +void +mmyth_ui_set_widget (MMythUi * mmyth_ui, MMythUiCommon * new_uicommon) +{ + if (new_uicommon == NULL) { + g_warning ("MMythUI setting a NULL UI_Common as current display\n"); + return; + } + + if (mmyth_ui->current_uicommon) { + if (mmyth_ui->current_uicommon == mmyth_ui->video_uicommon) { + gtk_widget_hide (mmyth_ui->current_uicommon->main_widget); + gtk_widget_hide (mmyth_ui->videow); + } + else { + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->main_widget); + } + + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->event_box); + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + main_vseparator); + + } + + if (new_uicommon->main_widget == mmyth_ui->video_alignment) { + //gst_player_video_show (GST_PLAYER_VIDEO(mmyth_ui->videow)); + gtk_widget_show (mmyth_ui->video_alignment); + gtk_widget_show (mmyth_ui->videow); + } + else { + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->video_alignment != NULL) + gtk_widget_hide (mmyth_ui->video_alignment); + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->videow != NULL) + gtk_widget_hide (mmyth_ui->videow); + + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + new_uicommon->main_widget, TRUE, TRUE, 0); + } + + if(main_vseparator == NULL) { + /* FIXME: should free this variable*/ + main_vseparator = gtk_vseparator_new(); + g_object_ref (main_vseparator); + } + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + main_vseparator, FALSE, FALSE, 0); + gtk_widget_show (main_vseparator); + + gtk_box_pack_end (GTK_BOX (mmyth_ui->main_hbox), new_uicommon->event_box, FALSE, + FALSE, 0); + + mmyth_ui->current_uicommon = new_uicommon; + +} + +/* The close callback is the same for all windows*/ +static void +cb_not_impl_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + GtkWidget *msg_dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "Feature not implemented"); + gtk_widget_set_size_request (msg_dialog, 350, 120); + + gtk_dialog_run (GTK_DIALOG (msg_dialog)); + + gtk_widget_destroy(GTK_WIDGET(msg_dialog)); +} + +/****************************************************************************** + * POPUP MENU WIDGET METHODS * + *****************************************************************************/ + +static void +cb_menu_item_settings (GtkMenuItem *menuitem, + gpointer user_data) +{ + + MMythUi *mmyth_ui = (MMythUi*) user_data; + + if (mmyth_uisettings_run (GTK_WINDOW (mmyth_ui->main_window))) { + // If user changes the settings, we restart the context + g_debug ("[%s] Restarting mmyth_context to new settings", __FUNCTION__); + gmyth_context_initialize(); + } +} + +#ifndef MAEMO_PLATFORM + +static void +detacher (GtkWidget *attach_widget,GtkMenu *menu) +{ + +} + +static void +do_popup_menu (GtkWidget *my_widget, GdkEventButton *event) +{ + GtkWidget *popup; + + int button, event_time; + + GtkWidget *item_general; + GtkWidget *image; + + popup = gtk_menu_new (); + + item_general = gtk_image_menu_item_new_with_mnemonic ("Setup"); + gtk_widget_show (item_general); + gtk_container_add (GTK_CONTAINER (popup), item_general); + + image = gtk_image_new_from_stock ("gtk-edit", GTK_ICON_SIZE_MENU); + gtk_widget_show (image); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item_general), image); + + g_signal_connect (G_OBJECT(item_general), "activate", G_CALLBACK (cb_menu_item_settings), popup_mmyth_ui); + + if (event) { + button = event->button; + event_time = event->time; + } else { + button = 0; + event_time = gtk_get_current_event_time (); + } + + gtk_menu_attach_to_widget (GTK_MENU (popup), my_widget, detacher); + gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, + button, event_time); + gtk_widget_show_all(popup); +} + +/* Respond to a button-press by posting a menu passed in as widget. + * + * Note that the "widget" argument is the menu being posted, NOT + * the button that was pressed. + */ +static gint +button_press_handler (GtkWidget *widget, GdkEvent *event) +{ + + if (event->type == GDK_BUTTON_PRESS) { + GdkEventButton *bevent = (GdkEventButton *) event; + /* Ignore double-clicks and triple-clicks */ + if (bevent->button == 3) + { + do_popup_menu (widget, bevent); + return TRUE; + } + } + + /* Tell calling code that we have not handled this event; pass it on. */ + return FALSE; +} +#endif + +/****************************************************************************** + * MAIN APP VIEW METHODS * + *****************************************************************************/ + +static void +cb_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + +static void +cb_watch_tv_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + gboolean res = FALSE; + + if (!(mmyth_ui->video_uicommon)) + mmyth_ui->video_uicommon = create_video_view (mmyth_ui); + + // Creates the tv player that will retrieve the mythtv content, decode and show it + mmyth_ui->tvplayer = gmyth_tvplayer_new (); + /* choose here if this is a LiveTV session */ + mmyth_ui->tvplayer->is_livetv = TRUE; + + res = gmyth_tvplayer_initialize (mmyth_ui->tvplayer); + + if (!res) { + g_warning ("[%s] Could not initialize tvplayer", __FUNCTION__); + + g_object_unref (mmyth_ui->tvplayer); + mmyth_ui->tvplayer = NULL; + + GtkWidget *dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "MMyth found errors while starting TV Player, please check " + "the GStreamer installation"); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return; + } + //res = mmyth_tvplayer_livetv_setup (mmyth_ui->tvplayer); + // + if (mmyth_ui && mmyth_ui->tvplayer && res) { + gmyth_tvplayer_set_widget (mmyth_ui->tvplayer, mmyth_ui->videow); + gmyth_tvplayer_start_playing (mmyth_ui->tvplayer); + } else { + // TODO: Show Alert with error description! + g_warning ("[%s] MMythUI can't initialize tv_player", __FUNCTION__); + g_object_unref (mmyth_ui->tvplayer); + mmyth_ui->tvplayer = NULL; + // FIXME: Show the exact error that happened + GtkWidget *dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Error while starting TV Player, please check if the backend" + " is running properly and a tv card is available!"); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + return; + } + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->video_uicommon); + +} + +static void +cb_epg_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + if (!(mmyth_ui->epg_grid_uicommon)) + mmyth_ui->epg_grid_uicommon = create_epg_grid_view(mmyth_ui); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->epg_grid_uicommon); +} + +static MMythUiCommon * +create_main_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + GtkWidget *main_widget; + GtkWidget *image; + + g_debug ("Creating Main UI Common"); + + // FIXME: file path +#ifdef MMYTH_DEV + image = gtk_image_new_from_file ("../pixmaps/mmyth_logo.png"); +#else + image = gtk_image_new_from_file ( PIX_DIR "mmyth_logo.png"); +#endif + + main_widget = gtk_event_box_new(); + + gtk_container_add (GTK_CONTAINER (main_widget), + image); + + + gtk_widget_show_all (main_widget); + g_object_ref (main_widget); + + ui_common = mmyth_uicommon_new (main_widget, + "Watch TV", "EPG", "Recording"); + + /* Button signals */ + // FIXME + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_watch_tv_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_epg_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_record_button), mmyth_ui); + + return ui_common; + +} + +/****************************************************************************** + * epg GRID VIEW METHODS * + *****************************************************************************/ + +static MMythUiCommon * +create_epg_grid_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + + g_debug ("Creating EPG Grid UI Common"); + + GtkWidget *epg_grid_view = GTK_WIDGET (epg_grid_view_new (mmyth_ui)); + + ui_common = mmyth_uicommon_new (epg_grid_view, + "Play", "Record", + "Close"); + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_record_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_close_button), mmyth_ui); + + return ui_common; +} +/****************************************************************************** + * SCHEDULE VIEW METHODS * + ******************************************************************************/ + +static void +cb_save_new_schedule (GtkButton *button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + if (!(mmyth_ui->schedule_uicommon)) + mmyth_ui->schedule_uicommon = create_schedule_view(mmyth_ui); + + mmyth_schedulerui_save (mmyth_ui->mmyth_schedulerui); + + mmyth_recordui_reload_schedule (mmyth_ui->mmyth_recordui); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->record_uicommon); + +} + +static void +cb_edit_scheduled (GtkTreeView * tree_view, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + GtkTreeSelection *selection; + GtkTreeModel *list_store; + GtkTreeIter iter; + int index; + //gint new_row = 0, record_id = 0; + ScheduleInfo *schedule_info; + GList *schedule_list; + //GtkTreeIter iter; + gint res; + + //gtk_tree_store_clear(recordui->sch_tree_store); + + res = gmyth_scheduler_get_schedule_list(mmyth_ui->mmyth_recordui->scheduler, &(schedule_list)); + if (res < 0) { + g_warning ("[%s] Retrieved NULL list of scheduled data from database", __FUNCTION__); + //return FALSE; + } + printf("\nX %d", res); fflush(stdout); + + selection = + gtk_tree_view_get_selection(GTK_TREE_VIEW(mmyth_ui->mmyth_recordui->sch_treeview)); + + gtk_tree_selection_get_selected(selection, &list_store, &iter); + gtk_tree_model_get(list_store, &iter, 4, &index, -1); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->schedule_uicommon); + + if (!(mmyth_ui->schedule_uicommon)) + mmyth_ui->schedule_uicommon = create_schedule_view(mmyth_ui); + + schedule_list = g_list_nth(schedule_list, atoi(gtk_tree_path_to_string(path))); + schedule_info = (ScheduleInfo*) schedule_list->data; + + printf("\nstarttime: %ld", schedule_info->start_time); fflush(stdout); +} + +static MMythUiCommon * +create_schedule_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + GtkWidget *schedule_widget; + + g_debug ("Creating Schedule UI Common"); + + mmyth_ui->mmyth_schedulerui = mmyth_schedulerui_new (); + if (mmyth_ui->mmyth_schedulerui == NULL) { + g_warning ("[%s] Error while creating scheduler ui", __FUNCTION__); + return NULL; + } + + schedule_widget = mmyth_ui->mmyth_schedulerui->main_widget; + + gtk_widget_show_all (schedule_widget); + g_object_ref (schedule_widget); + + ui_common = mmyth_uicommon_new (schedule_widget, + "Save", "Clear", + "Cancel"); + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_save_new_schedule), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_record_button), mmyth_ui); + + return ui_common; +} +/****************************************************************************** + * RECORD VIEW METHODS * + ******************************************************************************/ +static void +cb_record_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + if (!(mmyth_ui->record_uicommon)) { + mmyth_ui->record_uicommon = create_record_view (mmyth_ui); + mmyth_ui->schedule_uicommon = create_schedule_view (mmyth_ui); + } + + mmyth_recordui_reload_all (mmyth_ui->mmyth_recordui); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->record_uicommon); + +} + +static void +cb_record_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget(mmyth_ui, mmyth_ui->main_uicommon); + + mmyth_recordui_free(mmyth_ui->mmyth_recordui); + + if (mmyth_ui->record_uicommon) { + gtk_widget_destroy (mmyth_ui->record_uicommon->main_widget); + mmyth_uicommon_free(mmyth_ui->record_uicommon); + mmyth_ui->record_uicommon = NULL; + } + + if (mmyth_ui->schedule_uicommon) { + // mmyth_uicommon_free(mmyth_ui->schedule_uicommon); + } +} + + + + +static void +play_selected_recorded (gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + gboolean res = FALSE; + + gchar *path = mmyth_recordui_get_selected_recorded (mmyth_ui->mmyth_recordui); + + if (path == NULL) { + // This should never happens. Play button is just activated when + // a recording is selected. + g_warning ("[%s] Play button pressed while none recorded is selected", __FUNCTION__); + return; + } + + if (!(mmyth_ui->video_uicommon)) + mmyth_ui->video_uicommon = create_video_view (mmyth_ui); + + // Creates the tv player that will retrieve the mythtv content, decode and show it + mmyth_ui->tvplayer = gmyth_tvplayer_new (); + g_debug ("[%s] New TV Player created: %d\n", __FUNCTION__, (int) (mmyth_ui->tvplayer)); + res = gmyth_tvplayer_initialize (mmyth_ui->tvplayer); + if (!res) { + g_warning ("[%s] Could not initialize tvplayer", __FUNCTION__); + + g_object_unref (mmyth_ui->tvplayer); + mmyth_ui->tvplayer = NULL; + + GtkWidget *dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "MMyth found errors while starting TV Player, please check " + "the GStreamer installation"); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return; + } + + res = gmyth_tvplayer_record_setup (mmyth_ui->tvplayer, path); + + if (mmyth_ui && mmyth_ui->tvplayer && res) { + gmyth_tvplayer_set_widget (mmyth_ui->tvplayer, mmyth_ui->videow); + gmyth_tvplayer_start_playing (mmyth_ui->tvplayer); + } else { + // TODO: Show Alert with error description! + g_warning ("[%s] MMythUI can't initialize tv_player", __FUNCTION__); + g_object_unref (mmyth_ui->tvplayer); + mmyth_ui->tvplayer = NULL; + // FIXME: Show the exact error that happened + GtkWidget *dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Error while starting TV Player, please check if the backend" + " is running properly and a tv card is available!"); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + return; + } + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->video_uicommon); +} + +static void +cb_play_clicked_recorded (GtkTreeView * tree_view, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer user_data) +{ + play_selected_recorded (user_data); +} + +static void +cb_play_selected (GtkButton * button, gpointer user_data) +{ + play_selected_recorded (user_data); +} + +static void +cb_schedule_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->schedule_uicommon); +} + +void +cb_switch_page (GtkNotebook *notebook, GtkNotebookPage *page, + guint page_num, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + MMythUiCommon *ui_common; + + assert (mmyth_ui); + assert (mmyth_ui->record_uicommon); + + ui_common = mmyth_ui->record_uicommon; + + if (page_num == 0) { // Switched to Schedule list + gtk_button_set_label (GTK_BUTTON (ui_common->button1), "New"); + g_signal_handlers_disconnect_by_func ( + G_OBJECT (ui_common->button1), G_CALLBACK (cb_play_selected), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_schedule_button), mmyth_ui); + } else if (page_num == 1) { + gtk_button_set_label (GTK_BUTTON (ui_common->button1), "Play"); + g_signal_handlers_disconnect_by_func ( + G_OBJECT (ui_common->button1), G_CALLBACK (cb_schedule_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_play_selected), mmyth_ui); + } +} + + +static MMythUiCommon * +create_record_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + + g_debug ("Creating Record UI Common"); + + mmyth_ui->mmyth_recordui = mmyth_recordui_new (); + + // FIXME: Change MMythRecordUI to a GtkWidget child and avoid this call! + gtk_widget_show_all (mmyth_ui->mmyth_recordui->scrolled_window); + + ui_common = mmyth_uicommon_new (mmyth_ui->mmyth_recordui->scrolled_window, "New", "Delete", "<mmyth_recordui->scrolled_window); + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_schedule_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (mmyth_recordui_delete_selected), mmyth_ui->mmyth_recordui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_record_close_button), mmyth_ui); + g_signal_connect (G_OBJECT (mmyth_ui->mmyth_recordui->notebook), + "switch-page", G_CALLBACK (cb_switch_page), mmyth_ui); + g_signal_connect (G_OBJECT (mmyth_ui->mmyth_recordui->rec_treeview), + "row-activated", G_CALLBACK (cb_play_clicked_recorded), mmyth_ui); + g_signal_connect (G_OBJECT (mmyth_ui->mmyth_recordui->sch_treeview), + "row-activated", G_CALLBACK (cb_edit_scheduled), mmyth_ui); + return ui_common; +} + + +/****************************************************************************** + * GST VIDEO WIDGET METHODS * + *****************************************************************************/ + +static void +cb_video_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + g_debug ("MMythUI video close button pressed"); + + if (mmyth_ui && mmyth_ui->tvplayer) { + gmyth_tvplayer_stop_playing (mmyth_ui->tvplayer); + + g_object_unref (mmyth_ui->tvplayer); + mmyth_ui->tvplayer = NULL; + } else { + g_warning ("cb_video_close_button called with NULL pointer\n"); + } + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + + +static MMythUiCommon * +create_video_view (MMythUi * mmyth_ui) +{ + + MMythUiCommon *ui_common; + + g_debug ("Creating Video UI Common"); + + /* Creates widget to be user by MMythTVPlayer to draw the video */ + mmyth_ui->videow = gtk_drawing_area_new (); + // FIXME: Get the widget size from settings + gtk_widget_set_size_request (mmyth_ui->videow, 300, 240); + + //mmiptv_ui->logo = gdk_pixbuf_new_from_file ("logo.png", NULL); + + // Creates an alignment to place the video widget inside + mmyth_ui->video_alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_hide (mmyth_ui->video_alignment); + + gtk_container_add (GTK_CONTAINER (mmyth_ui->video_alignment), + mmyth_ui->videow); + + /* Add the gst video widget to hbox. It should never be removed. */ + /* FIXME: mmyth_ui->video_alignment == NULL when mmyth_player_init fails */ + if((mmyth_ui->main_hbox != NULL) && (mmyth_ui->video_alignment != NULL)) { + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + mmyth_ui->video_alignment, TRUE, TRUE, 0); + } else { + g_warning ("[%s] Error while adding video_alignment to main widget", __FUNCTION__); + } + + g_object_ref (mmyth_ui->videow); + g_object_ref (mmyth_ui->video_alignment); + + ui_common = mmyth_uicommon_new (mmyth_ui->video_alignment, + " Full\nScreen", "Other\nServices", + "Close"); + + + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_video_close_button), mmyth_ui); + + if (ui_common) + g_debug ("Video UI_Common sucessfull created"); + + return ui_common; +} + + + +GtkWidget* +mmyth_ui_get_video_widget (MMythUi *mmyth_ui) { + + if (mmyth_ui && mmyth_ui->videow) { + + return mmyth_ui->videow; + } + + return NULL; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_ui.c.mine --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_ui.c.mine Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,451 @@ + +#include +#include +#include + +#include "mmyth_ui.h" +#include "mmyth_uicommon.h" +/* FIXME +#include "mmyth_videoplayer.h" +*/ +#include "mmyth_esg_grid_view.h" + +static gint button_press_handler (GtkWidget *widget, GdkEvent *event); + +MMythUiCommon *create_main_view (MMythUi * mmyth_ui); +MMythUiCommon *create_video_view (MMythUi * mmyth_ui); +MMythUiCommon *create_esg_grid_view (MMythUi * mmyth_ui); +static void cb_video_close_button (GtkButton * button, gpointer user_data); + +/* main box from button box separator*/ +static GtkWidget *main_vseparator = NULL; + +GdkPixbuf *icon_sports, *icon_news, + *icon_movies, *icon_shows, *icon_default; + +/* FIXME: UGLY HACK */ +MMythUi *popup_mmyth_ui; + +void +mmyth_ui_initialize_icons () +{ + GError *error = NULL; + +#ifdef MMYTH_DEVEL + icon_sports = + gdk_pixbuf_new_from_file ("../pixmaps/ico_sports.png", &error); +#else + icon_sports = gdk_pixbuf_new_from_file (PIX_DIR "ico_sports.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon sports: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_news = gdk_pixbuf_new_from_file ("../pixmaps/ico_news.png", &error); +#else + icon_news = gdk_pixbuf_new_from_file (PIX_DIR "ico_news.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon news: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_movies = + gdk_pixbuf_new_from_file ("../pixmaps/ico_movies.png", &error); +#else + icon_movies = gdk_pixbuf_new_from_file (PIX_DIR "ico_movies.png", &error); +#endif + if (error) { + g_warning ("Could not load icon movies: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_shows = gdk_pixbuf_new_from_file ("../pixmaps/ico_shows.png", &error); +#else + icon_shows = gdk_pixbuf_new_from_file (PIX_DIR "ico_shows.png", &error); +#endif + if (error) { + g_warning ("Could not load icon shows: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_default = + gdk_pixbuf_new_from_file ("../pixmaps/ico_default.png", &error); +#else + icon_default = gdk_pixbuf_new_from_file (PIX_DIR "ico_default.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon default: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +} + +MMythUi * +mmyth_ui_initialize (GtkWidget * main_window) +{ + MMythUi *mmyth_ui; + + // FIXME: REMOVE ME + //mmyth_settings_load ( ); + + mmyth_ui = g_new0 (MMythUi, 1); + + mmyth_ui->main_window = main_window; + + /* Horizontal box that divides the view into control and video area */ + mmyth_ui->main_hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (mmyth_ui->main_hbox); + g_object_ref (mmyth_ui->main_hbox); + + mmyth_ui_initialize_icons (); + + main_bg_color.red = 65000; + main_bg_color.green = 65000; + main_bg_color.blue = 65000; + + // Main widget is mmyth_ui->main_hbox + mmyth_ui->main_uicommon = create_main_view (mmyth_ui); + mmyth_ui->video_uicommon = create_video_view (mmyth_ui); + mmyth_ui->esg_grid_uicommon = create_esg_grid_view (mmyth_ui); + + /* Popup menu */ + /* FIXME: URGENT ugly, ugly hack */ + popup_mmyth_ui = mmyth_ui; + g_signal_connect (G_OBJECT (mmyth_ui->main_hbox), "event", + G_CALLBACK (button_press_handler), + G_OBJECT (mmyth_ui->main_hbox)); + + gtk_container_add (GTK_CONTAINER (mmyth_ui->main_window), + mmyth_ui->main_hbox); + + /* Add the gst video widget to hbox. It should never be removed. */ + /* FIXME: mmyth_ui->video_alignment == NULL when mmyth_player_init fails */ + if(mmyth_ui->video_alignment != NULL) + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + mmyth_ui->video_alignment, TRUE, TRUE, 0); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); + + return mmyth_ui; +} + +void +mmyth_ui_finalize (MMythUi * mmyth_ui) +{ + if (mmyth_ui != NULL) + g_free (mmyth_ui); + + mmyth_uicommon_unref_all (mmyth_ui->main_uicommon); + mmyth_uicommon_unref_all (mmyth_ui->video_uicommon); + mmyth_uicommon_unref_all (mmyth_ui->esgcurrent_uicommon); +} + +void +mmyth_ui_set_widget (MMythUi * mmyth_ui, MMythUiCommon * new_uicommon) +{ + if (mmyth_ui->current_uicommon) { + if (mmyth_ui->current_uicommon == mmyth_ui->video_uicommon) { + gtk_widget_hide (mmyth_ui->current_uicommon->main_widget); + gtk_widget_hide (mmyth_ui->videow); + } + else { + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->main_widget); + } + + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->event_box); + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + main_vseparator); + + } + + if (new_uicommon->main_widget == mmyth_ui->video_alignment) { + //gst_player_video_show (GST_PLAYER_VIDEO(mmyth_ui->videow)); + gtk_widget_show (mmyth_ui->video_alignment); + gtk_widget_show (mmyth_ui->videow); + } + else { + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->video_alignment != NULL) + gtk_widget_hide (mmyth_ui->video_alignment); + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->videow != NULL) + gtk_widget_hide (mmyth_ui->videow); + + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + new_uicommon->main_widget, TRUE, TRUE, 0); + } + + if(main_vseparator == NULL) { + /* FIXME: should free this variable*/ + main_vseparator = gtk_vseparator_new(); + g_object_ref (main_vseparator); + } + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + main_vseparator, FALSE, FALSE, 0); + gtk_widget_show (main_vseparator); + + gtk_box_pack_end (GTK_BOX (mmyth_ui->main_hbox), new_uicommon->event_box, FALSE, + FALSE, 0); + + mmyth_ui->current_uicommon = new_uicommon; + +} + +/* The close callback is the same for all windows*/ +static void +cb_not_impl_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + GtkWidget *msg_dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "Feature not implemented yet"); + gtk_widget_set_size_request (msg_dialog, 300, 120); + + gtk_dialog_run (GTK_DIALOG (msg_dialog)); + + gtk_widget_destroy(GTK_WIDGET(msg_dialog)); +} + +/****************************************************************************** + * POPUP MENU WIDGET METHODS * + *****************************************************************************/ + +void +detacher (GtkWidget *attach_widget,GtkMenu *menu) +{ +} + +void +menu_item_settings_cb (GtkMenuItem *menuitem, + gpointer user_data) +{ + /* MMythUi *mmyth_ui = (MMythUi *) user_data; */ + + /* FIXME + MMythUi *mmyth_ui = popup_mmyth_ui; + + settings_show_dialog (GTK_WINDOW (mmyth_ui->main_window)); + */ +} + +static void +do_popup_menu (GtkWidget *my_widget, GdkEventButton *event) +{ + GtkWidget *popup; + int button, event_time; + + popup = gtk_menu_new (); + + /* ... add menu items ... */ + GtkWidget *menu_item = gtk_menu_item_new_with_label("Settings"); + gtk_menu_append(popup, menu_item); + + g_signal_connect (G_OBJECT(menu_item), "activate", + G_CALLBACK (menu_item_settings_cb), NULL); + + if (event) + { + button = event->button; + event_time = event->time; + } + else + { + button = 0; + event_time = gtk_get_current_event_time (); + } + + //gtk_menu_attach_to_widget (GTK_MENU (popup), my_widget, detacher); + gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, + button, event_time); + gtk_widget_show_all(popup); +} + +/* Respond to a button-press by posting a menu passed in as widget. + * + * Note that the "widget" argument is the menu being posted, NOT + * the button that was pressed. + */ + +static gint +button_press_handler (GtkWidget *widget, GdkEvent *event) +{ + + if (event->type == GDK_BUTTON_PRESS) { + GdkEventButton *bevent = (GdkEventButton *) event; + /* Ignore double-clicks and triple-clicks */ + if (bevent->button == 3) + { + do_popup_menu (widget, bevent); + return TRUE; + } + } + + /* Tell calling code that we have not handled this event; pass it on. */ + return FALSE; +} + + +/****************************************************************************** + * MAIN APP VIEW METHODS * + *****************************************************************************/ + +/* The close callback is the same for all windows*/ +static void +cb_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + +static void +cb_esg_today_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->esg_grid_uicommon); +} + +MMythUiCommon * +create_main_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + GtkWidget *main_widget; + GtkWidget *image; + + // FIXME: file path +#ifdef MMYTH_DEV + image = gtk_image_new_from_file ("../pixmaps/main_logo.gif"); +#else + image = gtk_image_new_from_file ("../pixmaps/main_logo.gif"); +#endif + + main_widget = gtk_event_box_new(); + + gtk_container_add (GTK_CONTAINER (main_widget), + image); + + + gtk_widget_show_all (main_widget); + g_object_ref (main_widget); + + ui_common = mmyth_uicommon_new (main_widget, + "Channels", "Current", "Today"); + + /* Button signals */ + /* FIXME + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_channels_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_esg_current_button), mmyth_ui); + */ + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_esg_today_button), mmyth_ui); + + return ui_common; + +} + +/****************************************************************************** + * ESG GRID VIEW METHODS * + *****************************************************************************/ + +static void +cb_esg_grid_view_button (GtkButton * button, gpointer user_data) +{ + /* FIXME + MMythUi *mmyth_ui = (MMythUi *) user_data; + guint32 service_id = -1; + + // Retrieves the user selected service ID + DVBHScheduleEvent *schedule = (DVBHScheduleEvent *) mmyth_esg_grid_view_get_selected_schedule(); + + if(schedule != NULL) { + service_id = schedule->service->number; + mmyth_play_channel (mmyth_ui, service_id); + } + */ +} + +MMythUiCommon * +create_esg_grid_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + GtkWidget *esg_grid_view = GTK_WIDGET (esg_grid_view_new (mmyth_ui)); + + + ui_common = mmyth_uicommon_new (esg_grid_view, + "View", "Remind", + "Close"); + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_esg_grid_view_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_close_button), mmyth_ui); + + return ui_common; +} + +/****************************************************************************** + * GST VIDEO WIDGET METHODS * + *****************************************************************************/ + +static void +cb_video_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + /* FIXME + mmyth_player_stop (mmyth_ui); + */ + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + +MMythUiCommon * +create_video_view (MMythUi * mmyth_ui) +{ + + MMythUiCommon *ui_common; + + /* FIXME + mmyth_player_init (mmyth_ui); + */ + + ui_common = mmyth_uicommon_new (mmyth_ui->video_alignment, + " Full\nScreen", "Other\nServices", + "Close"); + + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_video_close_button), mmyth_ui); + + return ui_common; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_ui.c.r2518 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_ui.c.r2518 Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,456 @@ + +#include +#include +#include + +#include "mmyth_ui.h" +#include "mmyth_uicommon.h" +/* FIXME +#include "mmyth_videoplayer.h" +#include "mmyth_esg_grid_view.h" +#include "mmyth_common.h" +*/ + +static gint button_press_handler (GtkWidget *widget, GdkEvent *event); + +MMythUiCommon *create_main_view (MMythUi * mmyth_ui); +MMythUiCommon *create_video_view (MMythUi * mmyth_ui); +MMythUiCommon *create_esg_grid_view (MMythUi * mmyth_ui); +static void cb_video_close_button (GtkButton * button, gpointer user_data); + +/* main box from button box separator*/ +static GtkWidget *main_vseparator = NULL; + +GdkPixbuf *icon_sports, *icon_news, + *icon_movies, *icon_shows, *icon_default; + +/* FIXME: UGLY HACK */ +MMythUi *popup_mmyth_ui; + +void +mmyth_ui_initialize_icons () +{ + GError *error = NULL; + +#ifdef MMYTH_DEVEL + icon_sports = + gdk_pixbuf_new_from_file ("../pixmaps/ico_sports.png", &error); +#else + icon_sports = gdk_pixbuf_new_from_file (PIX_DIR "ico_sports.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon sports: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_news = gdk_pixbuf_new_from_file ("../pixmaps/ico_news.png", &error); +#else + icon_news = gdk_pixbuf_new_from_file (PIX_DIR "ico_news.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon news: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_movies = + gdk_pixbuf_new_from_file ("../pixmaps/ico_movies.png", &error); +#else + icon_movies = gdk_pixbuf_new_from_file (PIX_DIR "ico_movies.png", &error); +#endif + if (error) { + g_warning ("Could not load icon movies: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_shows = gdk_pixbuf_new_from_file ("../pixmaps/ico_shows.png", &error); +#else + icon_shows = gdk_pixbuf_new_from_file (PIX_DIR "ico_shows.png", &error); +#endif + if (error) { + g_warning ("Could not load icon shows: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_default = + gdk_pixbuf_new_from_file ("../pixmaps/ico_default.png", &error); +#else + icon_default = gdk_pixbuf_new_from_file (PIX_DIR "ico_default.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon default: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +} + +MMythUi * +mmyth_ui_initialize (GtkWidget * main_window) +{ + MMythUi *mmyth_ui; + + // FIXME: REMOVE ME + //mmyth_settings_load ( ); + + mmyth_ui = g_new0 (MMythUi, 1); + + mmyth_ui->main_window = main_window; + + /* Horizontal box that divides the view into control and video area */ + mmyth_ui->main_hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (mmyth_ui->main_hbox); + g_object_ref (mmyth_ui->main_hbox); + + mmyth_ui_initialize_icons (); + + main_bg_color.red = 65000; + main_bg_color.green = 65000; + main_bg_color.blue = 65000; + + // Main widget is mmyth_ui->main_hbox + mmyth_ui->main_uicommon = create_main_view (mmyth_ui); + mmyth_ui->video_uicommon = create_video_view (mmyth_ui); + mmyth_ui->esg_grid_uicommon = create_esg_grid_view (mmyth_ui); + + /* Popup menu */ + /* FIXME: URGENT ugly, ugly hack */ + popup_mmyth_ui = mmyth_ui; + g_signal_connect (G_OBJECT (mmyth_ui->main_hbox), "event", + G_CALLBACK (button_press_handler), + G_OBJECT (mmyth_ui->main_hbox)); + + gtk_container_add (GTK_CONTAINER (mmyth_ui->main_window), + mmyth_ui->main_hbox); + + /* Add the gst video widget to hbox. It should never be removed. */ + /* FIXME: mmyth_ui->video_alignment == NULL when mmyth_player_init fails */ + if(mmyth_ui->video_alignment != NULL) + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + mmyth_ui->video_alignment, TRUE, TRUE, 0); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); + + return mmyth_ui; +} + +void +mmyth_ui_finalize (MMythUi * mmyth_ui) +{ + if (mmyth_ui != NULL) + g_free (mmyth_ui); + + mmyth_uicommon_unref_all (mmyth_ui->main_uicommon); + mmyth_uicommon_unref_all (mmyth_ui->video_uicommon); + mmyth_uicommon_unref_all (mmyth_ui->esgcurrent_uicommon); +} + +void +mmyth_ui_set_widget (MMythUi * mmyth_ui, MMythUiCommon * new_uicommon) +{ + if (mmyth_ui->current_uicommon) { + if (mmyth_ui->current_uicommon == mmyth_ui->video_uicommon) { + gtk_widget_hide (mmyth_ui->current_uicommon->main_widget); + gtk_widget_hide (mmyth_ui->videow); + } + else { + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->main_widget); + } + + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->event_box); + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + main_vseparator); + + } + + if (new_uicommon->main_widget == mmyth_ui->video_alignment) { + //gst_player_video_show (GST_PLAYER_VIDEO(mmyth_ui->videow)); + gtk_widget_show (mmyth_ui->video_alignment); + gtk_widget_show (mmyth_ui->videow); + } + else { + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->video_alignment != NULL) + gtk_widget_hide (mmyth_ui->video_alignment); + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->videow != NULL) + gtk_widget_hide (mmyth_ui->videow); + + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + new_uicommon->main_widget, TRUE, TRUE, 0); + } + + if(main_vseparator == NULL) { + /* FIXME: should free this variable*/ + main_vseparator = gtk_vseparator_new(); + g_object_ref (main_vseparator); + } + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + main_vseparator, FALSE, FALSE, 0); + gtk_widget_show (main_vseparator); + + gtk_box_pack_end (GTK_BOX (mmyth_ui->main_hbox), new_uicommon->event_box, FALSE, + FALSE, 0); + + mmyth_ui->current_uicommon = new_uicommon; + +} + +/* The close callback is the same for all windows*/ +static void +cb_not_impl_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + GtkWidget *msg_dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "Feature not implemented yet"); + gtk_widget_set_size_request (msg_dialog, 300, 120); + + gtk_dialog_run (GTK_DIALOG (msg_dialog)); + + gtk_widget_destroy(GTK_WIDGET(msg_dialog)); +} + +/****************************************************************************** + * POPUP MENU WIDGET METHODS * + *****************************************************************************/ + +void +detacher (GtkWidget *attach_widget,GtkMenu *menu) +{ +} + +void +menu_item_settings_cb (GtkMenuItem *menuitem, + gpointer user_data) +{ + /* MMythUi *mmyth_ui = (MMythUi *) user_data; */ + + /* FIXME + MMythUi *mmyth_ui = popup_mmyth_ui; + + settings_show_dialog (GTK_WINDOW (mmyth_ui->main_window)); + */ +} + +static void +do_popup_menu (GtkWidget *my_widget, GdkEventButton *event) +{ + GtkWidget *popup; + int button, event_time; + + popup = gtk_menu_new (); + + /* ... add menu items ... */ + GtkWidget *menu_item = gtk_menu_item_new_with_label("Settings"); + gtk_menu_append(popup, menu_item); + + g_signal_connect (G_OBJECT(menu_item), "activate", + G_CALLBACK (menu_item_settings_cb), NULL); + + if (event) + { + button = event->button; + event_time = event->time; + } + else + { + button = 0; + event_time = gtk_get_current_event_time (); + } + + //gtk_menu_attach_to_widget (GTK_MENU (popup), my_widget, detacher); + gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, + button, event_time); + gtk_widget_show_all(popup); +} + +/* Respond to a button-press by posting a menu passed in as widget. + * + * Note that the "widget" argument is the menu being posted, NOT + * the button that was pressed. + */ + +static gint +button_press_handler (GtkWidget *widget, GdkEvent *event) +{ + + if (event->type == GDK_BUTTON_PRESS) { + GdkEventButton *bevent = (GdkEventButton *) event; + /* Ignore double-clicks and triple-clicks */ + if (bevent->button == 3) + { + do_popup_menu (widget, bevent); + return TRUE; + } + } + + /* Tell calling code that we have not handled this event; pass it on. */ + return FALSE; +} + + +/****************************************************************************** + * MAIN APP VIEW METHODS * + *****************************************************************************/ + +/* The close callback is the same for all windows*/ +static void +cb_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + +/* FIXME +static void +cb_esg_today_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->esg_grid_uicommon); +} +*/ + +MMythUiCommon * +create_main_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + GtkWidget *main_widget; + GtkWidget *image; + + // FIXME: file path +#ifdef MMYTH_DEV + image = gtk_image_new_from_file ("../pixmaps/main_logo.gif"); +#else + image = gtk_image_new_from_file ("../pixmaps/main_logo.gif"); +#endif + + main_widget = gtk_event_box_new(); + + gtk_container_add (GTK_CONTAINER (main_widget), + image); + + + gtk_widget_show_all (main_widget); + g_object_ref (main_widget); + + ui_common = mmyth_uicommon_new (main_widget, + "Channels", "Current", "Today"); + + /* Button signals */ + /* FIXME + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_channels_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_esg_current_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_esg_today_button), mmyth_ui); + */ + + return ui_common; + +} + +/****************************************************************************** + * ESG GRID VIEW METHODS * + *****************************************************************************/ + +static void +cb_esg_grid_view_button (GtkButton * button, gpointer user_data) +{ + /* FIXME + MMythUi *mmyth_ui = (MMythUi *) user_data; + guint32 service_id = -1; + + // Retrieves the user selected service ID + DVBHScheduleEvent *schedule = (DVBHScheduleEvent *) mmyth_esg_grid_view_get_selected_schedule(); + + if(schedule != NULL) { + service_id = schedule->service->number; + mmyth_play_channel (mmyth_ui, service_id); + } + */ +} + +MMythUiCommon * +create_esg_grid_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + /* FIXME + GtkWidget *esg_grid_view = GTK_WIDGET (esg_grid_view_new (mmyth_ui)); + + + ui_common = mmyth_uicommon_new (esg_grid_view, + "View", "Remind", + "Close"); + */ + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_esg_grid_view_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_close_button), mmyth_ui); + + return ui_common; +} + +/****************************************************************************** + * GST VIDEO WIDGET METHODS * + *****************************************************************************/ + +static void +cb_video_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + /* FIXME + mmyth_player_stop (mmyth_ui); + */ + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + +MMythUiCommon * +create_video_view (MMythUi * mmyth_ui) +{ + + MMythUiCommon *ui_common; + + /* FIXME + mmyth_player_init (mmyth_ui); + */ + + ui_common = mmyth_uicommon_new (mmyth_ui->video_alignment, + " Full\nScreen", "Other\nServices", + "Close"); + + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_video_close_button), mmyth_ui); + + return ui_common; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_ui.c.r2535 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_ui.c.r2535 Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,567 @@ +#include +#include +#include + +#include "mmyth_ui.h" +#include "mmyth_uicommon.h" +#include "mmyth_uischedulerecording.h" +#include "mmyth_uirecord.h" +/* FIXME +#include "mmyth_videoplayer.h" +#include "mmyth_esg_grid_view.h" +#include "mmyth_common.h" +*/ + +static gint button_press_handler (GtkWidget *widget, GdkEvent *event); + +MMythUiCommon *create_main_view (MMythUi * mmyth_ui); +MMythUiCommon *create_video_view (MMythUi * mmyth_ui); +MMythUiCommon *create_esg_grid_view (MMythUi * mmyth_ui); +MMythUiCommon *create_record_view (MMythUi * mmyth_ui); +MMythUiCommon *create_schedule_view (MMythUi * mmyth_ui); +static void cb_video_close_button (GtkButton * button, gpointer user_data); +static void cb_record_button (GtkButton * button, gpointer user_data); + +/* main box from button box separator*/ +static GtkWidget *main_vseparator = NULL; + +GdkPixbuf *icon_sports, *icon_news, + *icon_movies, *icon_shows, *icon_default; + +/* FIXME: UGLY HACK */ +MMythUi *popup_mmyth_ui; + +void +mmyth_ui_initialize_icons () +{ + GError *error = NULL; + +#ifdef MMYTH_DEVEL + icon_sports = + gdk_pixbuf_new_from_file ("../pixmaps/ico_sports.png", &error); +#else + icon_sports = gdk_pixbuf_new_from_file (PIX_DIR "ico_sports.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon sports: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_news = gdk_pixbuf_new_from_file ("../pixmaps/ico_news.png", &error); +#else + icon_news = gdk_pixbuf_new_from_file (PIX_DIR "ico_news.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon news: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_movies = + gdk_pixbuf_new_from_file ("../pixmaps/ico_movies.png", &error); +#else + icon_movies = gdk_pixbuf_new_from_file (PIX_DIR "ico_movies.png", &error); +#endif + if (error) { + g_warning ("Could not load icon movies: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_shows = gdk_pixbuf_new_from_file ("../pixmaps/ico_shows.png", &error); +#else + icon_shows = gdk_pixbuf_new_from_file (PIX_DIR "ico_shows.png", &error); +#endif + if (error) { + g_warning ("Could not load icon shows: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +#ifdef MMYTH_DEVEL + icon_default = + gdk_pixbuf_new_from_file ("../pixmaps/ico_default.png", &error); +#else + icon_default = gdk_pixbuf_new_from_file (PIX_DIR "ico_default.png", &error); +#endif + + if (error) { + g_warning ("Could not load icon default: %s\n", error->message); + g_error_free (error); + error = NULL; + } + +} + +MMythUi * +mmyth_ui_initialize (GtkWidget * main_window) +{ + MMythUi *mmyth_ui; + + // FIXME: REMOVE ME + //mmyth_settings_load ( ); + + mmyth_ui = g_new0 (MMythUi, 1); + + mmyth_ui->main_window = main_window; + + /* Horizontal box that divides the view into control and video area */ + mmyth_ui->main_hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (mmyth_ui->main_hbox); + g_object_ref (mmyth_ui->main_hbox); + + mmyth_ui_initialize_icons (); + + main_bg_color.red = 65000; + main_bg_color.green = 65000; + main_bg_color.blue = 65000; + + // Main widget is mmyth_ui->main_hbox + mmyth_ui->main_uicommon = create_main_view (mmyth_ui); + mmyth_ui->video_uicommon = create_video_view (mmyth_ui); + mmyth_ui->esg_grid_uicommon = create_esg_grid_view (mmyth_ui); + mmyth_ui->record_uicommon = create_record_view (mmyth_ui); + mmyth_ui->schedule_uicommon = create_schedule_view (mmyth_ui); + /* Popup menu */ + /* FIXME: URGENT ugly, ugly hack */ + popup_mmyth_ui = mmyth_ui; + g_signal_connect (G_OBJECT (mmyth_ui->main_hbox), "event", + G_CALLBACK (button_press_handler), + G_OBJECT (mmyth_ui->main_hbox)); + + gtk_container_add (GTK_CONTAINER (mmyth_ui->main_window), + mmyth_ui->main_hbox); + + /* Add the gst video widget to hbox. It should never be removed. */ + /* FIXME: mmyth_ui->video_alignment == NULL when mmyth_player_init fails */ + if(mmyth_ui->video_alignment != NULL) + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + mmyth_ui->video_alignment, TRUE, TRUE, 0); + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); + + return mmyth_ui; +} + +void +mmyth_ui_finalize (MMythUi * mmyth_ui) +{ + if (mmyth_ui != NULL) + g_free (mmyth_ui); + + mmyth_uicommon_unref_all (mmyth_ui->main_uicommon); + mmyth_uicommon_unref_all (mmyth_ui->video_uicommon); + mmyth_uicommon_unref_all (mmyth_ui->esgcurrent_uicommon); +} + +void +mmyth_ui_set_widget (MMythUi * mmyth_ui, MMythUiCommon * new_uicommon) +{ + if (mmyth_ui->current_uicommon) { + if (mmyth_ui->current_uicommon == mmyth_ui->video_uicommon) { + gtk_widget_hide (mmyth_ui->current_uicommon->main_widget); + gtk_widget_hide (mmyth_ui->videow); + } + else { + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->main_widget); + } + + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + mmyth_ui->current_uicommon->event_box); + gtk_container_remove (GTK_CONTAINER (mmyth_ui->main_hbox), + main_vseparator); + + } + + if (new_uicommon->main_widget == mmyth_ui->video_alignment) { + //gst_player_video_show (GST_PLAYER_VIDEO(mmyth_ui->videow)); + gtk_widget_show (mmyth_ui->video_alignment); + gtk_widget_show (mmyth_ui->videow); + } + else { + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->video_alignment != NULL) + gtk_widget_hide (mmyth_ui->video_alignment); + /* FIXME: Fst call is NULL when mmyth_player_init fails */ + if(mmyth_ui->videow != NULL) + gtk_widget_hide (mmyth_ui->videow); + + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + new_uicommon->main_widget, TRUE, TRUE, 0); + } + + if(main_vseparator == NULL) { + /* FIXME: should free this variable*/ + main_vseparator = gtk_vseparator_new(); + g_object_ref (main_vseparator); + } + gtk_box_pack_start (GTK_BOX (mmyth_ui->main_hbox), + main_vseparator, FALSE, FALSE, 0); + gtk_widget_show (main_vseparator); + + gtk_box_pack_end (GTK_BOX (mmyth_ui->main_hbox), new_uicommon->event_box, FALSE, + FALSE, 0); + + mmyth_ui->current_uicommon = new_uicommon; + +} + +/* The close callback is the same for all windows*/ +static void +cb_not_impl_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + GtkWidget *msg_dialog = gtk_message_dialog_new ( + GTK_WINDOW(mmyth_ui->main_window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "Feature not implemented yet"); + gtk_widget_set_size_request (msg_dialog, 300, 120); + + gtk_dialog_run (GTK_DIALOG (msg_dialog)); + + gtk_widget_destroy(GTK_WIDGET(msg_dialog)); +} + +/****************************************************************************** + * POPUP MENU WIDGET METHODS * + *****************************************************************************/ + +void +detacher (GtkWidget *attach_widget,GtkMenu *menu) +{ +} + +void +menu_item_settings_cb (GtkMenuItem *menuitem, + gpointer user_data) +{ + /* MMythUi *mmyth_ui = (MMythUi *) user_data; */ + + /* FIXME + MMythUi *mmyth_ui = popup_mmyth_ui; + + settings_show_dialog (GTK_WINDOW (mmyth_ui->main_window)); + */ +} + +static void +do_popup_menu (GtkWidget *my_widget, GdkEventButton *event) +{ + GtkWidget *popup; + int button, event_time; + + popup = gtk_menu_new (); + + /* ... add menu items ... */ + GtkWidget *menu_item = gtk_menu_item_new_with_label("Settings"); + gtk_menu_append(popup, menu_item); + + g_signal_connect (G_OBJECT(menu_item), "activate", + G_CALLBACK (menu_item_settings_cb), NULL); + + if (event) + { + button = event->button; + event_time = event->time; + } + else + { + button = 0; + event_time = gtk_get_current_event_time (); + } + + //gtk_menu_attach_to_widget (GTK_MENU (popup), my_widget, detacher); + gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, + button, event_time); + gtk_widget_show_all(popup); +} + +/* Respond to a button-press by posting a menu passed in as widget. + * + * Note that the "widget" argument is the menu being posted, NOT + * the button that was pressed. + */ + +static gint +button_press_handler (GtkWidget *widget, GdkEvent *event) +{ + + if (event->type == GDK_BUTTON_PRESS) { + GdkEventButton *bevent = (GdkEventButton *) event; + /* Ignore double-clicks and triple-clicks */ + if (bevent->button == 3) + { + do_popup_menu (widget, bevent); + return TRUE; + } + } + + /* Tell calling code that we have not handled this event; pass it on. */ + return FALSE; +} + + +/****************************************************************************** + * MAIN APP VIEW METHODS * + *****************************************************************************/ + +/* The close callback is the same for all windows*/ +static void +cb_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + +// FIXME +//static void +//cb_record_button (GtkButton * button, gpointer user_data) +//{ +// MMythUi *mmyth_ui = (MMythUi *) user_data; +// +// mmyth_ui_set_widget (mmyth_ui, mmyth_ui->record_uicommon); +//} + + +MMythUiCommon * +create_main_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + GtkWidget *main_widget; + GtkWidget *image; + + // FIXME: file path +#ifdef MMYTH_DEV + image = gtk_image_new_from_file ("../pixmaps/main_logo.gif"); +#else + image = gtk_image_new_from_file ("../pixmaps/main_logo.gif"); +#endif + + main_widget = gtk_event_box_new(); + + gtk_container_add (GTK_CONTAINER (main_widget), + image); + + + gtk_widget_show_all (main_widget); + g_object_ref (main_widget); + + ui_common = mmyth_uicommon_new (main_widget, + "Channels", "Current", "Recording"); + + /* Button signals */ + // FIXME + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_record_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_record_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_record_button), mmyth_ui); + + + return ui_common; + +} + +/****************************************************************************** + * ESG GRID VIEW METHODS * + *****************************************************************************/ + +static void +cb_esg_grid_view_button (GtkButton * button, gpointer user_data) +{ + /* FIXME + MMythUi *mmyth_ui = (MMythUi *) user_data; + guint32 service_id = -1; + + // Retrieves the user selected service ID + DVBHScheduleEvent *schedule = (DVBHScheduleEvent *) mmyth_esg_grid_view_get_selected_schedule(); + + if(schedule != NULL) { + service_id = schedule->service->number; + mmyth_play_channel (mmyth_ui, service_id); + } + */ +} + +MMythUiCommon * +create_esg_grid_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + /* FIXME + GtkWidget *esg_grid_view = GTK_WIDGET (esg_grid_view_new (mmyth_ui)); + + + ui_common = mmyth_uicommon_new (esg_grid_view, + "View", "Remind", + "Close"); + */ + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_esg_grid_view_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_close_button), mmyth_ui); + + return ui_common; +} +/****************************************************************************** + * SCHEDULE VIEW METHODS * + ******************************************************************************/ + +static void +cb_schedule_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->schedule_uicommon); + /* FIXME + MMythUi *mmyth_ui = (MMythUi *) user_data; + guint32 service_id = -1; + + // Retrieves the user selected service ID + DVBHScheduleEvent *schedule = (DVBHScheduleEvent *) mmyth_esg_grid_view_get_selected_schedule(); + + if(schedule != NULL) { + service_id = schedule->service->number; + mmyth_play_channel (mmyth_ui, service_id); + } + */ +} + +MMythUiCommon * +create_schedule_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + + GtkWidget *schedule_view = GTK_WIDGET (schedule_view_new ()); + //record_view = gtk_event_box_new(); + + + gtk_widget_show_all (schedule_view); + g_object_ref (schedule_view); + + ui_common = mmyth_uicommon_new (schedule_view, + "Save", "Clear", + "Cancel"); + + //ui-> + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_close_button), mmyth_ui); + + return ui_common; +} +/****************************************************************************** + * RECORD VIEW METHODS * + ******************************************************************************/ + +static void +cb_record_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->record_uicommon); + /* FIXME + MMythUi *mmyth_ui = (MMythUi *) user_data; + guint32 service_id = -1; + + // Retrieves the user selected service ID + DVBHScheduleEvent *schedule = (DVBHScheduleEvent *) mmyth_esg_grid_view_get_selected_schedule(); + + if(schedule != NULL) { + service_id = schedule->service->number; + mmyth_play_channel (mmyth_ui, service_id); + } + */ +} + +MMythUiCommon * +create_record_view (MMythUi * mmyth_ui) +{ + MMythUiCommon *ui_common; + + GtkWidget *record_view = GTK_WIDGET (record_view_new ()); + //record_view = gtk_event_box_new(); + + + + + gtk_widget_show_all (record_view); + g_object_ref (record_view); + + ui_common = mmyth_uicommon_new (record_view, + "Play (!)", "Schedule", + "Delete(!)"); + + //ui-> + + + /* Button signals */ + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_schedule_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_close_button), mmyth_ui); + + return ui_common; +} +/****************************************************************************** + * GST VIDEO WIDGET METHODS * + *****************************************************************************/ + +static void +cb_video_close_button (GtkButton * button, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + /* FIXME + mmyth_player_stop (mmyth_ui); + */ + + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->main_uicommon); +} + +MMythUiCommon * +create_video_view (MMythUi * mmyth_ui) +{ + + MMythUiCommon *ui_common; + + /* FIXME + mmyth_player_init (mmyth_ui); + */ + + ui_common = mmyth_uicommon_new (mmyth_ui->video_alignment, + " Full\nScreen", "Other\nServices", + "Close"); + + g_signal_connect (G_OBJECT (ui_common->button1), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button2), "clicked", + G_CALLBACK (cb_not_impl_button), mmyth_ui); + g_signal_connect (G_OBJECT (ui_common->button3), "clicked", + G_CALLBACK (cb_video_close_button), mmyth_ui); + + return ui_common; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_ui.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_ui.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,75 @@ +#ifndef MMYTH_UI_H_ +#define MMYTH_UI_H_ + +#include +#include + +#include "config.h" + +#ifdef MAEMO_PLATFORM +#include "hildon-widgets/hildon-program.h" +#include "hildon-widgets/hildon-window.h" +#endif + +#include "mmyth_uicommon.h" +#include "mmyth_recordui.h" +#include "mmyth_schedulerui.h" + +/* GMyth library includes */ +#include "gmyth_tvplayer.h" + +typedef struct _MMythUi +{ + + /* The main application window */ + GtkWidget *main_window; + MMythUiCommon *current_uicommon; + + /* Main widget components */ + GtkWidget *main_hbox; + GtkWidget *video_alignment; + GdkPixbuf *logo; + + /* Main widgets grouping */ + MMythUiCommon *main_uicommon; + MMythUiCommon *video_uicommon; + MMythUiCommon *epg_grid_uicommon; + MMythUiCommon *record_uicommon; + MMythUiCommon *schedule_uicommon; + + GtkWidget *videow; + int idle_id; + //GstTagList *tagcache; + + MMythRecordUI *mmyth_recordui; + MMythSchedulerUI *mmyth_schedulerui; + +#ifdef MAEMO_PLATFORM + HildonProgram *program; + GtkMenu *main_menu; + GtkWidget *menu_setup; +#endif + + GMythTVPlayer *tvplayer; + +} MMythUi; + +GdkPixbuf *icon_sports, *icon_news, *icon_movies, *icon_shows; +GdkColor main_bg_color; + +void mmyth_set_main_widget (MMythUi * mmyth_ui, MMythUiCommon * new_ui); +//void mmyth_play_selected(GtkButton * button, gpointer user_data); + +#ifdef MAEMO_PLATFORM +MMythUi *mmyth_ui_initialize (HildonProgram *program, GtkWidget * main_window); +#else +MMythUi *mmyth_ui_initialize (GtkWidget * main_window); +#endif + +void mmyth_ui_finalize (MMythUi * mmyth_ui); + +void mmyth_ui_set_widget (MMythUi * mmyth_ui, MMythUiCommon * new_uicommon); + +GtkWidget* mmyth_ui_get_video_widget (MMythUi *mmyth_ui); + +#endif /* MMYTH_UI_H_ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_uicommon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_uicommon.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,134 @@ + +#include +#include +#include + +#include "mmyth_uicommon.h" +#include "mmyth_ui.h" + +static void +refresh_time_on_screen (GtkWidget *label) +{ + time_t real_time; + struct tm sched_time; + GString *time_showed; + + time_showed = g_string_new(""); + time(&real_time); + + if (localtime_r((time_t *)&real_time, &sched_time) == NULL) { + g_error ("localtime_r error in mmyth_epg_grid_view!\n"); + return NULL; + } + + g_string_printf(time_showed, "%d:%02d:%02d", + sched_time.tm_hour, + sched_time.tm_min, + sched_time.tm_sec); + + gtk_label_set_text (GTK_LABEL(label), time_showed->str); +} + +MMythUiCommon * +mmyth_uicommon_new (GtkWidget * main_widget, const gchar * label1, + const gchar * label2, const gchar * label3) +{ + + MMythUiCommon *ui_common = g_new0 (MMythUiCommon, 1); + + if (!main_widget) { + g_warning ("MMythUICommon created with a NULL main widget\n"); + } + + ui_common->main_widget = main_widget; + + ui_common->event_box = gtk_event_box_new(); + + /* Vertical box that divides the control area into two (buttons + clock) */ + ui_common->vbox = gtk_vbox_new (FALSE, 0); /* spacing */ + gtk_container_set_border_width(GTK_CONTAINER (ui_common->vbox), 4); + + gtk_container_add (GTK_CONTAINER (ui_common->event_box), + ui_common->vbox); + gtk_widget_modify_bg(ui_common->event_box, GTK_STATE_NORMAL, &main_bg_color); + + /* Vertical box that divides the control area into four */ + ui_common->button_vbox = gtk_vbox_new (TRUE, 0); /* spacing */ + + gtk_container_set_border_width (GTK_CONTAINER (ui_common->button_vbox), 0); + + /* The button 1 */ + ui_common->button1 = gtk_button_new_with_label (label1); + gtk_widget_modify_bg(ui_common->button1, GTK_STATE_NORMAL, &main_bg_color); + gtk_widget_set_size_request (ui_common->button1, BUTTON_WIDTH, + BUTTON_HEIGHT); + + /* The button 2 */ + ui_common->button2 = gtk_button_new_with_label (label2); + gtk_widget_modify_bg(ui_common->button2, GTK_STATE_NORMAL, &main_bg_color); + gtk_widget_set_size_request (ui_common->button2, BUTTON_WIDTH, + BUTTON_HEIGHT); + + /* The button 3 */ + ui_common->button3 = gtk_button_new_with_label (label3); + gtk_widget_modify_bg(ui_common->button3, GTK_STATE_NORMAL, &main_bg_color); + gtk_widget_set_size_request (ui_common->button3, BUTTON_WIDTH, + BUTTON_HEIGHT); + + /* The clock label */ + ui_common->label = gtk_label_new ("Starting..."); + gtk_widget_show (ui_common->label); + ui_common->source_id = g_timeout_add(500, (GSourceFunc) refresh_time_on_screen, ui_common->label); + + /* Packing components */ + gtk_box_pack_start (GTK_BOX (ui_common->vbox), + ui_common->button_vbox, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (ui_common->vbox), + ui_common->label, FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (ui_common->button_vbox), + ui_common->button1, FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (ui_common->button_vbox), + ui_common->button2, FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (ui_common->button_vbox), + ui_common->button3, FALSE, FALSE, 0); + + gtk_widget_show_all (ui_common->event_box); + + /* FIXME: mmyth_ui->video_alignment == NULL when mmyth_player_init fails */ + if(ui_common->main_widget != NULL) + g_object_ref (ui_common->main_widget); + + g_object_ref (ui_common->vbox); + g_object_ref (ui_common->button_vbox); + g_object_ref (ui_common->label); + g_object_ref (ui_common->button1); + g_object_ref (ui_common->button2); + g_object_ref (ui_common->button3); + g_object_ref (ui_common->event_box); + return ui_common; +} + +void +mmyth_uicommon_free (MMythUiCommon *ui_common) +{ + g_debug ("[%s] Clean uicommon used memory", __FUNCTION__); + + g_source_remove (ui_common->source_id); + + g_object_unref (ui_common->main_widget); + g_object_unref (ui_common->vbox); + g_object_unref (ui_common->button_vbox); + g_object_unref (ui_common->label); + g_object_unref (ui_common->button1); + g_object_unref (ui_common->button2); + g_object_unref (ui_common->button3); + g_object_unref (ui_common->event_box); + + g_free (ui_common); +} + + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_uicommon.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_uicommon.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,51 @@ +#ifndef MMYTH_UICOMMON_H_ +#define MMYTH_UICOMMON_H_ + +#include "config.h" + +#include +#include + +#ifndef MAEMO_PLATFORM +#define BUTTON_HEIGHT 50 +#define BUTTON_WIDTH 100 +#else +#define BUTTON_HEIGHT 80 +#define BUTTON_WIDTH 150 +#endif + +#define MAIN_WINDOW_WIDTH 550 +#define MAIN_WINDOW_HEIGHT 250 + +#define CHANNELS_DIALOG_WIDTH 300 +#define CHANNELS_DIALOG_HEIGHT 200 + +#define SETTINGS_DIALOG_WIDTH 300 +#define SETTINGS_DIALOG_HEIGHT 120 + +extern GdkColor main_bg_color; + +typedef struct _MMythUiCommon +{ + GtkWidget *main_widget; + + /* event box to set the background color*/ + GtkWidget *event_box; + + GtkWidget *vbox; + GtkWidget *button_vbox; + GtkWidget *label; + + GtkWidget *button1; + GtkWidget *button2; + GtkWidget *button3; + + gint source_id; +} MMythUiCommon; + +MMythUiCommon *mmyth_uicommon_new (GtkWidget * main_widget, + const gchar * label1, const gchar * label2, + const gchar * label3); +void mmyth_uicommon_free (MMythUiCommon *ui_common); + +#endif /* MMYTH_UICOMMON_H_ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_uisettings.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_uisettings.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mmyth_uisettings.h" + +#include "gmyth_context.h" + +static GtkWidget *settings_dialog; +static GtkWidget *entry_hostname; +static GtkWidget *entry_dbname; +static GtkWidget *entry_username; +static GtkWidget *entry_passwd; +static GtkWidget *entry_port; + +static void settings_dialog_update_data (void); +static GtkWidget* add_entry_to_table (GtkWidget *table, GString *init_str, + guint pos_left, guint pos_right, guint pos_top, guint pos_bottom); +static GtkWidget* add_label_to_table (GtkWidget *table, const gchar *str, + guint pos_left, guint pos_right, guint pos_top, guint pos_bottom); + + +gboolean +mmyth_uisettings_run (GtkWindow *main_window) +{ + + GtkWidget *settings_table; + GtkWidget *label_hostname, *label_dbname; + GtkWidget *label_username, *label_passwd, *label_port; + + GMythSettings *msettings = gmyth_context_get_settings(); + + settings_dialog = gtk_dialog_new_with_buttons ("Settings", + main_window, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, + NULL); + + gtk_widget_set_size_request (settings_dialog, 400, 244); + +/* scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow1); + gtk_container_add (GTK_CONTAINER (window1), scrolledwindow1); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); + + viewport1 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport1); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport1), GTK_SHADOW_NONE); +*/ + + // Creates the table and attach it to the settings dialog + settings_table = gtk_table_new (5, 2, FALSE); + gtk_widget_show (settings_table); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(settings_dialog)->vbox), settings_table, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (settings_table), 3); + gtk_table_set_row_spacings (GTK_TABLE (settings_table), 5); + gtk_table_set_col_spacings (GTK_TABLE (settings_table), 10); + + label_hostname = add_label_to_table (settings_table, "Host Name:", 0, 1, 0, 1); + label_dbname = add_label_to_table (settings_table, "Database Name:", 0, 1, 1, 2); + label_username = add_label_to_table (settings_table, "Username:", 0, 1, 2, 3); + label_passwd = add_label_to_table (settings_table, "Password:", 0, 1, 3, 4); + label_port = add_label_to_table (settings_table, "Server port:", 0, 1, 4, 5); + + entry_hostname = add_entry_to_table (settings_table, + gmyth_settings_get_backend_hostname (msettings), + 1, 2, 0, 1); + entry_dbname = add_entry_to_table (settings_table, + gmyth_settings_get_dbname (msettings), + 1, 2, 1, 2 ); + entry_username = add_entry_to_table (settings_table, + gmyth_settings_get_username (msettings), + 1, 2, 2, 3 ); + entry_passwd = add_entry_to_table (settings_table, + gmyth_settings_get_password (msettings), + 1, 2, 3, 4 ); + + GString *str_port = g_string_new (""); + g_string_printf (str_port, "%d", + gmyth_settings_get_backend_port (msettings)); + entry_port = add_entry_to_table (settings_table, str_port, + 1, 2, 4, 5 ); + g_string_free (str_port, TRUE); + + if (gtk_dialog_run (GTK_DIALOG (settings_dialog)) == GTK_RESPONSE_ACCEPT) { + settings_dialog_update_data (); + gtk_widget_destroy (settings_dialog); + return TRUE; + } + + gtk_widget_destroy (settings_dialog); + + return FALSE; + +} + +static GtkWidget* +add_label_to_table (GtkWidget *table, const gchar *str, guint pos_left, guint pos_right, + guint pos_top, guint pos_bottom ) +{ + GtkWidget *tmp_label = gtk_label_new (str); + + gtk_widget_show (tmp_label); + gtk_table_attach (GTK_TABLE (table), tmp_label, + pos_left, pos_right, pos_top, pos_bottom, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (tmp_label), 0, 0.5); + + return tmp_label; +} + +static GtkWidget* +add_entry_to_table (GtkWidget *table, GString *init_str, guint pos_left, guint pos_right, + guint pos_top, guint pos_bottom) +{ + GtkWidget *tmp_entry = gtk_entry_new (); + gtk_widget_show (tmp_entry); + gtk_table_attach (GTK_TABLE (table), tmp_entry, + pos_left, pos_right, pos_top, pos_bottom, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + if (init_str) + gtk_entry_set_text (GTK_ENTRY (tmp_entry), (init_str->str)); + + //gtk_entry_set_invisible_char (GTK_ENTRY (entry_port), 9679); + + return tmp_entry; +} + +static void +settings_dialog_update_data (void) +{ + GString *tmp_entry_text; + GMythSettings *msettings = gmyth_context_get_settings(); + + if (!msettings) { + g_warning ("[%s] Could not get GMythSettings instance from context\n", __FUNCTION__); + return; + } + + tmp_entry_text = g_string_new(""); + g_string_printf(tmp_entry_text, "%s", gtk_entry_get_text( GTK_ENTRY(entry_hostname))); + gmyth_settings_set_backend_hostname(msettings, tmp_entry_text); + + g_string_printf(tmp_entry_text, "%s", gtk_entry_get_text( GTK_ENTRY(entry_dbname))); + gmyth_settings_set_dbname(msettings, tmp_entry_text); + + g_string_printf(tmp_entry_text, "%s", gtk_entry_get_text( GTK_ENTRY(entry_username))); + gmyth_settings_set_username(msettings, tmp_entry_text); + + g_string_printf(tmp_entry_text, "%s", gtk_entry_get_text( GTK_ENTRY(entry_passwd))); + gmyth_settings_set_password(msettings, tmp_entry_text); + + g_string_printf(tmp_entry_text, "%s", gtk_entry_get_text( GTK_ENTRY(entry_port))); + gmyth_settings_set_backend_port(msettings, atoi(tmp_entry_text->str)); + + gmyth_settings_save (msettings); + +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_uisettings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_uisettings.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,6 @@ +#ifndef MMYTH_SETTINGS_H_ +#define MMYTH_SETTINGS_H_ + +gboolean mmyth_uisettings_run (GtkWindow *main_window); + +#endif /*MMYTH_SETTINGS_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_videoplayer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_videoplayer.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,369 @@ + +#include +#include +#include +#include +#include + +#include "mmyth_ui.h" +#include "mmyth_videoplayer.h" +#include "mmyth_sdpreader.h" + +#include "esg_database.h" + +#include "ipd_demux.h" +#include "ipd_network.h" + +#ifdef INDT_IP_DECAPSULATOR +#include +#include +#endif + +/* Global flag/semaphore to control IP decapsulator threads */ +gboolean state_keep_running = 0; + + +typedef struct _GstPlayerWindowStateChange +{ + GstElement *play; + GstState old_state, new_state; + MMythUi *mmyth_ui; +} GstPlayerWindowStateChange; + +typedef struct _GstPlayerWindowTagFound +{ + GstElement *play; + GstTagList *taglist; + MMythUi *mmyth_ui; +} GstPlayerWindowTagFound; + + +GstElement *gst_pipeline, *gst_decoder, *gst_videosink; + +static gboolean idle_state (gpointer data); + +static gboolean +bus_call (GstBus * bus, GstMessage * msg, gpointer data) +{ + MMythUi *mmyth_ui = (MMythUi *) data; + GMainLoop *loop = mmyth_ui->loop; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_EOS: + + if (mmyth_ui->idle_id != 0) { + g_source_remove (mmyth_ui->idle_id); + mmyth_ui->idle_id = 0; + } + + //g_idle_add ((GSourceFunc) idle_eos, data); + gst_element_set_state (GST_ELEMENT (GST_MESSAGE_SRC (msg)), + GST_STATE_READY); + break; + case GST_MESSAGE_ERROR:{ + gchar *debug; + GError *err; + + gst_message_parse_error (msg, &err, &debug); + g_free (debug); + + printf ("Error: %s\n", err->message); + g_error_free (err); + + g_main_loop_quit (loop); + } + break; + case GST_MESSAGE_STATE_CHANGED:{ + GstState oldstate; + GstState newstate; + GstState pending; + GstPlayerWindowStateChange *st = + g_new (GstPlayerWindowStateChange, 1); + + gst_message_parse_state_changed (msg, + &oldstate, + &newstate, &pending); + + st->play = mmyth_ui->play; + gst_object_ref (GST_OBJECT (mmyth_ui->play)); + st->old_state = oldstate; + st->new_state = newstate; + + st->mmyth_ui = mmyth_ui; + + /* State debug messages */ + printf ("oldstate = %s, newstate = %s, pendingstate = %s\n", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate), + gst_element_state_get_name (pending)); + + g_idle_add ((GSourceFunc) idle_state, st); + + } + break; + default: + printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg))); + printf ("\n"); + break; + } + + return TRUE; +} + + +static gboolean +cb_iterate (gpointer data) +{ + MMythUi *mmyth_ui = (MMythUi *) data; + //gboolean res; + + g_main_loop_run (mmyth_ui->loop); +/* + if (!GST_FLAG_IS_SET (mmyth_ui->play, GST_BIN_SELF_SCHEDULABLE)) { + res = gst_bin_iterate (GST_BIN (mmyth_ui->play)); + } else { + g_usleep (100); + res = (gst_element_get_state (mmyth_ui->play) == GST_STATE_PLAYING); + } + + if (!res) + mmyth_ui->idle_id = 0; + + return res; +*/ + return FALSE; + +} + +static gboolean +idle_state (gpointer data) +{ + GstPlayerWindowStateChange *st = data; + + if (st->old_state == GST_STATE_PLAYING) { + if (st->mmyth_ui->idle_id != 0) { + g_source_remove (st->mmyth_ui->idle_id); + st->mmyth_ui->idle_id = 0; + } + } + else if (st->new_state == GST_STATE_PLAYING) { + if (st->mmyth_ui->idle_id != 0) + g_source_remove (st->mmyth_ui->idle_id); + + st->mmyth_ui->idle_id = g_idle_add (cb_iterate, st->mmyth_ui); + } + + /* new movie loaded? */ + if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) { + + /* gboolean have_video = FALSE; */ + + gtk_widget_show (st->mmyth_ui->videow); + + gtk_window_resize (GTK_WINDOW (st->mmyth_ui->main_window), 1, 1); + + } + + /* discarded movie? */ + if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) { + + if (st->mmyth_ui->tagcache) { + gst_tag_list_free (st->mmyth_ui->tagcache); + st->mmyth_ui->tagcache = NULL; + } + } + + gst_object_unref (GST_OBJECT (st->play)); + //g_object_unref (G_OBJECT (st->win)); + g_free (st); + + /* once */ + return FALSE; +} + + + +static gboolean +expose (GtkWidget * widget, GdkEventExpose * event, gpointer user_data) +{ + MMythUi *mmyth_ui = (MMythUi *) user_data; + + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (mmyth_ui->videosink), + GDK_WINDOW_XWINDOW (mmyth_ui->videow-> + window)); + return TRUE; +} + + +void +mmyth_player_init (MMythUi * mmyth_ui) +{ + GstElement *play; + GstElement *source, *parser, *decoder, *videosink; + + play = gst_pipeline_new ("video-player"); + source = gst_element_factory_make ("udpsrc", "file-source"); + parser = gst_element_factory_make ("rtph263pdepay", "rtp-demux"); + decoder = gst_element_factory_make ("ffdec_h263", "mpeg-decoder"); + videosink = gst_element_factory_make ("xvimagesink", "image-output"); + gst_pipeline = play; + gst_decoder = decoder; + gst_videosink = videosink; + + if (!(gst_pipeline && source && parser && decoder && videosink)) { + /* FIXME: hanlde the error correctly */ + /* video_alignment is not being created (below) + and is causing problems to the ui */ + g_print ("GstElement creation error!\n"); + return; + } + + g_object_set (G_OBJECT (videosink), "sync", FALSE, NULL); + + gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (gst_pipeline)), + bus_call, mmyth_ui); + + gst_bin_add_many (GST_BIN (gst_pipeline), source, parser, decoder, + videosink, NULL); + + { + GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL); + gst_element_link_filtered(source, parser, rtpcaps); + } + + gst_element_link_many (/*source,*/ parser, decoder, videosink, NULL); + + /* actual window */ + mmyth_ui->play = play; + mmyth_ui->videosink = videosink; + mmyth_ui->udpsource = source; + + g_object_ref (mmyth_ui->play); + g_object_ref (mmyth_ui->videosink); + + /* video widget */ + //mmyth_ui->videow = gst_player_video_new (videosink, play); + mmyth_ui->videow = gtk_drawing_area_new (); + gtk_widget_set_size_request (mmyth_ui->videow, 300, 240); + + mmyth_ui->logo = gdk_pixbuf_new_from_file ("logo.png", NULL); + + + mmyth_ui->video_alignment = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_hide (mmyth_ui->video_alignment); + + gtk_container_add (GTK_CONTAINER (mmyth_ui->video_alignment), + mmyth_ui->videow); + + g_signal_connect (mmyth_ui->videow, "expose-event", G_CALLBACK (expose), + mmyth_ui); + //g_signal_connect(mmyth_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), mmyth_ui); + + + g_object_ref (mmyth_ui->videow); + g_object_ref (mmyth_ui->video_alignment); + + //gnome_app_set_contents (app, videow); + //gtk_widget_show (mmyth_ui->videow); + +//fail: +// gst_object_unref (GST_OBJECT (play)); +// return NULL; + +} + +void +mmyth_player_stop (MMythUi * mmyth_ui) +{ + gst_element_set_state (mmyth_ui->play, GST_STATE_NULL); + + if(mmyth_ui->videow != NULL) + gtk_widget_hide (mmyth_ui->videow); + + /* Disable IP Decapsulator playing threads */ + state_keep_running = FALSE; + +} + +static gboolean +idle_play (gpointer data) +{ + MMythUi *mmyth_ui = (MMythUi *) data; + + sleep (2); + + gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING); + + return FALSE; +} + + +/* Run IP decapsulator play function in a new thread. The thread is finished setting the + * semaphore "state_keep_running" to FALSE*/ +gpointer +run_ipd(gpointer data) +{ + GString *ip_addr = (GString*) data; + + state_keep_running = TRUE; + + printf("Inside thread\n"); + + ipd_mpe_play_section (ip_addr->str, &state_keep_running); + + return 0; +} + +void +mmyth_play_channel (MMythUi * mmyth_ui, gint service_number) +{ + ESGDatabase *esg_db; + DVBHService *service; + SDPData sdp_data; + GString *service_ip_addr; + + /* First verifies if there is a tuned network */ + if ( !ipd_network_is_tuned() ) { + /* FIXME: show alert and handle this error */ + g_warning ("Play not possible, network not tuned"); + return; + } + + esg_db = esg_database_get_instance(); + /* Gets the service structure */ + service = (DVBHService *) esg_database_get_service_from_number + (esg_db, service_number); + + /* Verifies if sdp fragment exists to this service */ + if ( service->sdp_file == NULL ) { + /* FIXME: Implement error handling */ + g_warning ("SDP fragment not available to access service"); + return; + } + + /* Parses the sdp to get ipv6 address and port */ + mmyth_sdp_parse_file (service->sdp_file->str, &sdp_data); + + /* Sets the gstreamer properties acording to the service access address */ + /* FIXME: Develop sdp_bin in gstreamer to give sdp file as pipeline config */ + g_object_set (G_OBJECT (mmyth_ui->udpsource), "multicast_group", + sdp_data.ip_addr->str, NULL); + g_object_set (G_OBJECT (mmyth_ui->udpsource), "port", sdp_data.video_port, NULL); + + /* Shows the video widget on screen */ + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->video_uicommon); + + gtk_widget_show (mmyth_ui->videow); + gtk_widget_queue_draw (mmyth_ui->videow); + +#ifdef INDT_IP_DECAPSULATOR + /* Will be dealocated in run_ipd */ + service_ip_addr = g_string_new (sdp_data.ip_addr->str); + + /* Requests the IP decapsulator to play the channel stream*/ + g_thread_create (run_ipd, (gpointer) service_ip_addr, FALSE, NULL); +#endif + + //gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING); + g_idle_add (idle_play, mmyth_ui); +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/gui/mmyth_videoplayer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/gui/mmyth_videoplayer.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,12 @@ +#ifndef MMYTH_VIDEOPLAYER_H_ +#define MMYTH_VIDEOPLAYER_H_ + +#include "mmyth_ui.h" + +void mmyth_player_init (MMythUi * mmyth_ui); +void mmyth_player_stop (MMythUi * mmyth_ui); + +void mmyth_play_channel (MMythUi * mmyth_ui, gint service_id); + + +#endif /* MMYTH_VIDEOPLAYER_H_ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/Makefile.am Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,59 @@ +SUBDIRS = . + +lib_LTLIBRARIES = libgmyth.la + +libgmyth_la_SOURCES = \ + gmyth_common.c \ + gmyth_context.c \ + gmyth_epg.c \ + gmyth_remote_encoder.c \ + gmyth_remote_util.c \ + gmyth_settings.c \ + gmyth_tvchain.c \ + gmyth_tvplayer.c \ + gmyth_scheduler.c \ + gmyth_util.c \ + gmyth_query.c \ + gmyth_socket.c \ + gmyth_stringlist.c + +libgmyth_la_CFLAGS = \ + -DDATADIR=\"$(pkgdatadir)\" \ + $(GLIB_CFLAGS) \ + $(GTK_CFLAGS) \ + $(GOBJECT_CFLAGS) \ + $(GST_CFLAGS) \ + $(GSTBASE_CFLAGS) \ + $(MYSQL_CFLAGS) \ + -g3 -O0 + +#libgmyth_la_LIBADD = \ +# $(MYSQL_LIBS) + +libgmyth_la_LDFLAGS = \ + -export-dynamic \ + -lgstinterfaces-0.10 \ + $(MYSQL_LIBS) \ + $(GST_LIBS) \ + $(GSTBASE_LIBS) + +libgmyth_includedir = \ + $(pkgincludedir) + +libgmyth_include_HEADERS = \ + gmyth_common.h \ + gmyth_context.h \ + gmyth_epg.h \ + gmyth_remote_encoder.h \ + gmyth_scheduler.h \ + gmyth_settings.h \ + gmyth_tvchain.h \ + gmyth_tvplayer.h \ + gmyth_util.h \ + gmyth_query.h \ + gmyth_socket.h \ + gmyth_remote_util.h \ + gmyth_stringlist.h + +CLEANFILES = $(BUILT_SOURCES) + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_common.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,85 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_common.c + * + * @brief

This file contains basic common functions for the gmyth library. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Leonardo Sobral Cunha + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 "gmyth_common.h" + +static void free_channel_data(gpointer data, gpointer user_data); +static void free_program_data(gpointer data, gpointer user_data); + +/** Frees the memory allocated to the GMythChannelInfo objects inside list. + * The list memory is also released by g_list_free(). If LIST is NULL it + * simply returns. + * + * @param list the GList containing a list of GMythChannelInfo to free. + */ +void +gmyth_free_channel_list(GList *list) +{ + if (list == NULL) { + g_warning ("%s received null GList as parameter", __FUNCTION__); + return; + } + + g_list_foreach (list, free_channel_data, NULL); + + g_list_free (list); +} + +/** Frees the memory allocated to the GMythProgramInfo objects inside list. + * The list memory is also released by g_list_free(). If list is NULL it + * simply returns. + * + * @param list the GList containing a list of GMythProgramInfo to free. + */ +void +gmyth_free_program_list(GList *list) +{ + if (list == NULL) { + g_warning ("%s received null GList as parameter", __FUNCTION__); + return; + } + + g_list_foreach (list, free_program_data, NULL); + + g_list_free (list); +} + + +static void +free_channel_data(gpointer data, gpointer user_data) +{ + if(data) + g_free((GMythChannelInfo*) data); +} + +static void +free_program_data(gpointer data, gpointer user_data) +{ + if(data) + g_free((GMythProgramInfo*) data); +} + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_common.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,155 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_common.h + * + * @brief

This file contains basic common functions for the gmyth library. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Leonardo Sobral Cunha + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef GMYTH_COMMON_H_ +#define GMYTH_COMMON_H_ + +#include +#include + +/** + * The GMythChannelInfo structure represents the channel information + * stored in the backend database. + */ +typedef struct { + /** The channel ID in backend database */ + int channel_ID; + + /** The channel name in backend database */ + GString *channel_name; + +} GMythChannelInfo; + + +/** + * The GMythProgramInfo structure represents a program information + * stored in the database. It could be a program from the EPG data, + * a program scheduled to be recorded, or a program already recorded. + */ +typedef struct { + + /** The channel unique ID. */ + GString *chanid; + + /** The program start time. */ + time_t startts; + /** The program end time. */ + time_t endts; + /** The recording schedule start time. */ + time_t recstartts; + /** The recording schedule end time */ + time_t recendts; + + /** The program title. */ + GString *title; + /** The program subtitle. */ + GString *subtitle; + /** The program description. */ + GString *description; + /** The program category. */ + GString *category; + + GString *chanstr; + GString *chansign; + /** The associated channel name. */ + GString *channame; + int chancommfree; + GString *chanOutputFilters; + + GString *seriesid; + /** The program unique id. */ + GString *programid; + GString * catType; + + GString * sortTitle; + + /** A flag informing if the program has video or not. */ + gboolean isVideo; + int lenMins; + + GString *year; + double stars; + int repeat; + + time_t originalAirDate; + time_t lastmodified; + time_t lastInUseTime; + + gboolean hasAirDate; + + int spread; + int startCol; + +// enum RecStatusType recstatus; +// enum RecStatusType oldrecstatus; +// enum RecStatusType savedrecstatus; + int recpriority2; + int reactivate; + + int recordid; + int parentid; + //enum RecordingType rectype; + //enum RecordingDupInType dupin; + //enum RecordingDupMethodType dupmethod; + + /** The backend video source id associated to this program.*/ + int sourceid; + /** the backend input id associated to this program.*/ + int inputid; + /** The backend card id associated to this program.*/ + int cardid; + gboolean shareable; + gboolean duplicate; + + GString * schedulerid; + int findid; + + int programflags; + int transcoder; + + //proginfo->spread = -1; + //proginfo->programflags = proginfo->getProgramFlags(); + + GString *recgroup; + GString *playgroup; + int recpriority; + + /** The file size of the recorded program.*/ + long long filesize; + /** The file name of the recorded program.*/ + GString *pathname; + GString *hostname; + + /* AvailableStatusType availableStatus;*/ + +} GMythProgramInfo; + + +void gmyth_free_channel_list(GList *list); +void gmyth_free_program_list(GList *list); + +#endif /* GMYTH_COMMON_H_ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_context.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_context.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,312 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_context.c + * + * @brief

GMythContext class contains general attributes and functions + * that express the connection state of each mythtvfrontend. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 "gmyth_context.h" + +#include +#include +#include +#include +#include +#include + +#include "gmyth_query.h" +#include "gmyth_socket.h" + +static void gmyth_context_class_init (GMythContextClass *klass); +static void gmyth_context_init (GMythContext *object); + +static void gmyth_context_dispose (GObject *object); +static void gmyth_context_finalize (GObject *object); + + +G_DEFINE_TYPE(GMythContext, gmyth_context, G_TYPE_OBJECT) + +static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + +static GMythContext *gcontext = NULL; + +static void +gmyth_context_class_init (GMythContextClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_context_dispose; + gobject_class->finalize = gmyth_context_finalize; +} + +static void +gmyth_context_init (GMythContext *gmyth_context) +{ + +} + +static void +gmyth_context_dispose (GObject *object) +{ + GMythContext *gmyth_context = GMYTH_CONTEXT(object); + + if ( gmyth_context->gmyth_settings != NULL ) { + g_object_unref (gmyth_context->gmyth_settings); + gmyth_context->gmyth_settings = NULL; + } + + if ( gmyth_context->localhostname != NULL ) { + g_string_free ( gmyth_context->localhostname, TRUE ); + gmyth_context->localhostname = NULL; + } + + if (gmyth_context->server_socket != NULL) { + g_object_unref (gmyth_context->server_socket); + gmyth_context->server_socket = NULL; + } + + G_OBJECT_CLASS (gmyth_context_parent_class)->dispose (object); +} + +static void +gmyth_context_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_context_parent_class)->finalize (object); +} + +/** Gets the some important address translation info, + * from the client socket that will open a connection. + * + * @return gint error number + */ +static gint +myth_context_toaddrinfo( gchar *addr, gint port, struct addrinfo **addrInfo ) +{ + struct addrinfo hints; + gchar *portStr = g_strnfill( 32, ' ' ); + gint errorn = EADDRNOTAVAIL; + + memset( &hints, 0, sizeof(hints) ); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + /* hints.ai_flags = AI_NUMERICHOST; */ + if ( port != -1 ) + sprintf(portStr, "%d", port); + else + portStr = NULL; + + g_debug( "[%s] Address: %s, port: %s\n", __FUNCTION__, addr, portStr ); + if ( ( errorn = getaddrinfo(addr, portStr, &hints, addrInfo) ) != 0 ) { + g_printerr( "[%s] Socket ERROR: %s\n", __FUNCTION__, gai_strerror(errorn) ); + } + + return errorn; + +} + +/** Initializes the GMythContext object. It reads local system information + * load gmyth user settings and start connection to the database. + * + * @return TRUE if initialization was successfull, + * FALSE if any error happens. + */ +gboolean +gmyth_context_initialize () +{ + GString *localhost = NULL; + + if (gcontext == NULL) { + gcontext = GMYTH_CONTEXT ( g_object_new (GMYTH_CONTEXT_TYPE, FALSE)); + } + + localhost = gmyth_socket_get_local_hostname( ); + + if (localhost==NULL || localhost->len <=0 ) { + g_warning ("[%s] Could not determine local hostname. Setting to 127.0.0.1", __FUNCTION__); + gcontext->localhostname = g_string_new ("127.0.0.1"); + } else { + gcontext->localhostname = localhost; + } + + if (gcontext->gmyth_settings) { + g_object_unref (gcontext->gmyth_settings); + gcontext->gmyth_settings = NULL; + } + + gcontext->gmyth_settings = gmyth_settings_new (); + if (!gmyth_settings_load (gcontext->gmyth_settings)) { + g_warning ("GMythContext: Settings file not opened!\n"); + } else { + g_debug ("GMythContext: Settings file loaded"); + } + + if (gcontext->server_socket != NULL) { + g_object_unref (gcontext->server_socket); + gcontext->server_socket = NULL; + } + + GString *server_hostname = + gmyth_settings_get_backend_hostname(gcontext->gmyth_settings); + int server_port = gmyth_settings_get_backend_port(gcontext->gmyth_settings); + + gcontext->server_socket = gmyth_socket_new (); + if (!gmyth_socket_connect_to_backend (gcontext->server_socket, + server_hostname->str, server_port, FALSE)) { + g_warning ("[%s] Socket connection to backend error!", __FUNCTION__); + g_object_unref (gcontext->server_socket); + gcontext->server_socket = NULL; + return FALSE; + } + + return TRUE; +} + +/** Formats a Mythtv protocol command based on strlist and sends it to + * the connected backend. The backend response is overwritten into strlist. + * + * @param strlist the string list to be sent, + * and on which the answer will be written. + * @return TRUE if command was sent and an answer was received, FALSE if any + * error happens. + */ +gboolean +gmyth_context_send_receive_stringlist (GMythStringList *strlist) +{ + gint ok = -1; + + if (!gcontext || !(gcontext->server_socket)) { + g_warning ("[%s] GMythContext not initialized", __FUNCTION__); + return FALSE; + } + + //g_static_mutex_lock( &mutex ); + + ok = gmyth_socket_sendreceive_stringlist (gcontext->server_socket, strlist); + + //g_static_mutex_unlock( &mutex ); + + if (!ok) { + g_warning ("Connection to backend server lost"); + } + + return (ok ? TRUE : FALSE); +} + +/** Gets the GMythSettings object associated to this context. + * + * @return The GMythSettings object currently valid or NULL if the settings + * were not opened. + */ +GMythSettings* +gmyth_context_get_settings () +{ + if (!gcontext) { + g_warning ("[%s] GMythContext not initialized\n", __FUNCTION__); + return NULL; + } + + return gcontext->gmyth_settings; +} + +/** Gets the machine local hostname. + * + * @param hostname a valid GString object to be overwritten with the local + * hostname. + * @return true if the hostname was read, false if any error happened. + */ +gboolean +gmyth_context_get_local_hostname (GString *hostname) +{ + if (!hostname) { + g_warning ("[%s] Received null argument", __FUNCTION__); + return FALSE; + } + + g_string_assign (hostname, gcontext->localhostname->str); + + return TRUE; +} + +/** Gets a setting information from the backend mysql database. + * + * @param key The setting key to be retrieved. + * @param host the hostname associated to the desired setting. + * @param default_value the default setting value if could not query from + * backend database. + * @return The setting value loaded from database, or the given default value + * if the query fails. + */ +GString* +gmyth_context_get_setting_onhost (GString *key, GString *host, GString *default_value) +{ + GString *query_str; + + // TODO: Reuse msql query in gmyth_context + GMythQuery *gmyth_query = gmyth_query_new (); + + if (gmyth_query_connect (gmyth_query)) { + MYSQL_RES *msql_res; + MYSQL_ROW msql_row; + + query_str = g_string_new (""); + g_string_printf (query_str, "SELECT data FROM settings WHERE value = \"%s\" " + "AND hostname = \"%s\" ;", key->str, host->str); + + msql_res = gmyth_query_process_statement (gmyth_query, query_str->str); + if (msql_res) { + msql_row = mysql_fetch_row (msql_res); + if (msql_row != NULL) { + return g_string_new (msql_row[0]); + } + } + + g_object_unref (gmyth_query); + } else { + g_warning ("Database not open while trying to load setting: %s", key->str); + } + + + return default_value; +} + +/** Verify if the context is currently connected to a backend. + * + * @return true if connection was opened, false if not. + */ +gboolean +gmyth_context_check_connection () +{ + // FIXME: Check this based on socket states + if (!gcontext) { + g_warning ("[%s] GMythContext not initialized", __FUNCTION__); + return FALSE; + } + + return (gcontext->server_socket != NULL); +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_context.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_context.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,88 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_context.h + * + * @brief

GMythContext class contains general attributes and functions + * that express the connection state of each mythtvfrontend. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef __GMYTH_CONTEXT_H__ +#define __GMYTH_CONTEXT_H__ + +#include + +#include "gmyth_settings.h" +#include "gmyth_socket.h" +#include "gmyth_stringlist.h" + +#define G_BEGIN_DECLS + +#define GMYTH_CONTEXT_TYPE (gmyth_context_get_type ()) +#define GMYTH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_CONTEXT_TYPE, GMythContext)) +#define GMYTH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_CONTEXT_TYPE, GMythContextClass)) +#define IS_GMYTH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_CONTEXT_TYPE)) +#define IS_GMYTH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_CONTEXT_TYPE)) +#define GMYTH_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_CONTEXT_TYPE, GMythContextClass)) + +#define MYTHTV_VERSION_DEFAULT 30 + +typedef struct _GMythContext GMythContext; +typedef struct _GMythContextClass GMythContextClass; + +struct _GMythContextClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythContext +{ + GObject parent; + + GMythSettings *gmyth_settings; + GMythSocket *server_socket; + + GString *localhostname; +}; + + +GType gmyth_context_get_type (void); +void gmyth_context_create(); + +gboolean gmyth_context_initialize (); +gboolean gmyth_context_check_connection (); +GMythSettings* gmyth_context_get_settings (); + +gboolean gmyth_context_send_receive_stringlist (GMythStringList *strlist); + +GString* gmyth_context_get_setting_onhost (GString *key, GString *host, GString *default_value); +gboolean gmyth_context_get_local_hostname (GString *hostname); + +GString* gmyth_context_get_setting_onhost (GString *key, GString *host, GString *default_value); + + +#define G_END_DECLS + +#endif /* __GMYTH_CONTEXT_H__ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_epg.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_epg.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,278 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_epg.c + * + * @brief

GMythEPG class provides access to the program and channel data + * from the Electronic Program Guide (EPG) of the Mythtv backend. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Leonardo Sobral Cunha + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 +#include +#include +#include + +#include "gmyth_epg.h" +#include "gmyth_util.h" + +static void gmyth_epg_class_init (GMythEPGClass *klass); +static void gmyth_epg_init (GMythEPG *object); + +static void gmyth_epg_dispose (GObject *object); +static void gmyth_epg_finalize (GObject *object); + +G_DEFINE_TYPE(GMythEPG, gmyth_epg, G_TYPE_OBJECT) + +static void +gmyth_epg_class_init (GMythEPGClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_epg_dispose; + gobject_class->finalize = gmyth_epg_finalize; +} + +static void +gmyth_epg_init (GMythEPG *gmyth_epg) +{ + gmyth_epg->sqlquery = gmyth_query_new (); +} + +static void +gmyth_epg_dispose (GObject *object) +{ + //GMythEPG *gmyth_epg = GMYTH_EPG(object); + + G_OBJECT_CLASS (gmyth_epg_parent_class)->dispose (object); +} + +static void +gmyth_epg_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_epg_parent_class)->finalize (object); +} + +/** + * Creates a new instance of GMythEPG. + * + * @return a new instance of GMythEPG. + */ +GMythEPG* +gmyth_epg_new () +{ + GMythEPG *epg = GMYTH_EPG (g_object_new(GMYTH_EPG_TYPE, NULL)); + + return epg; +} + +/** Connects to the Mysql database in the backend. The backend address + * is loaded from the GMythSettings instance. + * + * @param gmyth_epg the GMythEPG instance to be connected. + * @return true if connection was success, false if failed. + */ +gboolean +gmyth_epg_connect (GMythEPG *gmyth_epg) +{ + assert(gmyth_epg); + + if (gmyth_epg->sqlquery == NULL) { + g_warning ("[%s] GMythEPG not initialized", __FUNCTION__); + return FALSE; + } + + if (!gmyth_query_connect(gmyth_epg->sqlquery)) { + g_warning ("[%s] Error while connecting to db", __FUNCTION__); + return FALSE; + } + + return TRUE; +} + +/** Disconnects from the Mysql database in the backend. + * + * @param gmyth_epg the GMythEPG instance to be disconnected + * @return true if disconnection was success, false if failed. + */ +gboolean +gmyth_epg_disconnect (GMythEPG *gmyth_epg) +{ + assert(gmyth_epg); + + if (gmyth_epg->sqlquery != NULL) { + g_object_unref (gmyth_epg->sqlquery); + } + + return TRUE; +} + +/** Retrieves the available list of channels from the backend Mysql database. + * + * @param gmyth_epg the GMythEPG instance. + * @param glist_ptr the GList pointer to be filled with the loaded list address. + * @return The amount of channels retrieved from database, or -1 if error. + */ +gint +gmyth_epg_get_channel_list (GMythEPG *gmyth_epg, GList **glist_ptr) +{ + MYSQL_RES *msql_res; + + assert(gmyth_epg); + + msql_res = gmyth_query_process_statement (gmyth_epg->sqlquery, + "SELECT chanid,name FROM channel;"); + + (*glist_ptr) = NULL; + + if (msql_res == NULL) { + g_warning ("[%s] msql query returned NULL MYSQL_RES", __FUNCTION__); + return -1; + } else { + MYSQL_ROW row; + GMythChannelInfo *channel_info; + + while ((row = mysql_fetch_row (msql_res)) != NULL){ + + channel_info = g_new0(GMythChannelInfo, 1); + channel_info->channel_ID = atoi (row[0]); + channel_info->channel_name = g_string_new (row[1]); + + (*glist_ptr) = g_list_append ((*glist_ptr), channel_info); + } + } + mysql_free_result (msql_res); + return (!(*glist_ptr)) ? 0 : g_list_length (*glist_ptr); +} + +/** + * Retrieves the available list of channels from the backend Mysql database. + * + * @param gmyth_epg the GMythEPG instance. + * @param proglist the GList pointer to be filled with the loaded list. + * @param chan_num the channel num on which to search for program. + * @param starttime the start time to search for programs. + * @param endtime the end time to search for programs. + * @return The amount of channels retrieved from database, or -1 if error. + */ +gint +gmyth_epg_get_program_list (GMythEPG *gmyth_epg, GList **proglist, + const gint chan_num, time_t starttime, time_t endtime) +{ + GString *startts = gmyth_util_time_to_string(starttime); + GString *endts = gmyth_util_time_to_string(endtime); + MYSQL_ROW row; + GString *querystr; + + assert(gmyth_epg); + + querystr = g_string_new( + "SELECT DISTINCT program.chanid, program.starttime, program.endtime, " + " program.title, program.subtitle, program.description, " + " program.category, channel.channum, channel.callsign, " + " channel.name, program.previouslyshown, channel.commfree, " + " channel.outputfilters, program.seriesid, program.programid, " + " program.airdate, program.stars, program.originalairdate, " + " program.category_type, oldrecstatus.recordid, " + " oldrecstatus.rectype, oldrecstatus.recstatus, " + " oldrecstatus.findid " + "FROM program " + "LEFT JOIN channel ON program.chanid = channel.chanid " + "LEFT JOIN oldrecorded AS oldrecstatus ON " + " program.title = oldrecstatus.title AND " + " channel.callsign = oldrecstatus.station AND " + " program.starttime = oldrecstatus.starttime " + ); + + g_string_append_printf (querystr, + "WHERE program.chanid = %d " + " AND program.endtime >= '%s' " + " AND program.starttime <= '%s' " + " AND program.manualid = 0 ", + chan_num, startts->str, endts->str); + + if (!g_strrstr(querystr->str, " GROUP BY ")) + querystr = g_string_append(querystr, + " GROUP BY program.starttime, channel.channum, " + " channel.callsign, program.title "); + + if (!g_strrstr(querystr->str, " LIMIT ")) + querystr = g_string_append(querystr, " LIMIT 1000 "); + + MYSQL_RES *res_set = + gmyth_query_process_statement(gmyth_epg->sqlquery, querystr->str); + + if (res_set == NULL) { + g_warning ("[%s] msql query returned NULL MYSQL_RES", __FUNCTION__); + return -1; + } + + (*proglist) = NULL; + while ((row = mysql_fetch_row (res_set)) != NULL) { + + GMythProgramInfo *p = g_new0 (GMythProgramInfo, 1); + p->chanid = g_string_new (row[0]); + + p->startts = gmyth_util_string_to_time (g_string_new (row[1])); + p->endts = gmyth_util_string_to_time (g_string_new (row[2])); + + p->recstartts = p->startts; + p->recendts = p->endts; + p->lastmodified = p->startts; + + p->title = g_string_new (row[3]); + p->subtitle = g_string_new (row[4]); + p->description = g_string_new (row[5]); + p->category = g_string_new (row[6]); + p->chanstr = g_string_new (row[7]); + p->chansign = g_string_new (row[8]); + p->channame = g_string_new (row[9]); + p->repeat = atoi(row[10]); + p->chancommfree = atoi(row[11]); + p->chanOutputFilters = g_string_new (row[12]); + p->seriesid = g_string_new (row[13]); + p->programid = g_string_new (row[14]); + p->year = g_string_new (row[15]); + p->stars = atof(row[16]); + + if (!row[17] || !strcmp(row[17], "")) { + p->originalAirDate = 0; + p->hasAirDate = FALSE; + } else { + p->originalAirDate = gmyth_util_string_to_time (g_string_new (row[17])); + p->hasAirDate = TRUE; + } + + p->catType = g_string_new (row[18]); + + *proglist = g_list_append((*proglist), p); + } + + /* deallocate */ + mysql_free_result (res_set); + g_string_free(querystr, TRUE); + + return TRUE; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_epg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_epg.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,75 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_epg.h + * + * @brief

GMythEPG class provides access to the program and channel data + * from the Electronic Program Guide (EPG) of the Mythtv backend. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Leonardo Sobral Cunha + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef GMYTH_EPG_H_ +#define GMYTH_EPG_H_ + +#include + +#include "gmyth_query.h" +#include "gmyth_common.h" + +#define G_BEGIN_DECLS + +#define GMYTH_EPG_TYPE (gmyth_epg_get_type ()) +#define GMYTH_EPG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_EPG_TYPE, GMythEPG)) +#define GMYTH_EPG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_EPG_TYPE, GMythEPGClass)) +#define IS_GMYTH_EPG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_EPG_TYPE)) +#define IS_GMYTH_EPG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_EPG_TYPE)) +#define GMYTH_EPG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_EPG_TYPE, GMythEPGClass)) + +typedef struct _GMythEPG GMythEPG; +typedef struct _GMythEPGClass GMythEPGClass; + +struct _GMythEPGClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythEPG +{ + GObject parent; + + GMythQuery *sqlquery; +}; + +GType gmyth_epg_get_type (void); + +GMythEPG* gmyth_epg_new (); + +gboolean gmyth_epg_connect (GMythEPG *gmyth_epg); +gboolean gmyth_epg_disconnect (GMythEPG *gmyth_epg); + +gint gmyth_epg_get_channel_list (GMythEPG *gmyth_epg, GList **glist_ptr); +gint gmyth_epg_get_program_list (GMythEPG *gmyth_epg, GList **proglist, + const gint chanNum, time_t starttime, time_t endtime); + +#endif /*GMYTH_EPG_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_query.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_query.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,221 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_query.c + * + * @brief

GMythQuery class provides a wrapper for accessing + * the libmysqlclient funtions. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Leonardo Sobral Cunha + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 +#include +#include + +#include "gmyth_query.h" +#include "gmyth_settings.h" +#include "gmyth_context.h" + +static void gmyth_query_class_init (GMythQueryClass *klass); +static void gmyth_query_init (GMythQuery *object); + +static void gmyth_query_dispose (GObject *object); +static void gmyth_query_finalize (GObject *object); + +static void gmyth_query_print_error (MYSQL *conn, char *message); + +G_DEFINE_TYPE(GMythQuery, gmyth_query, G_TYPE_OBJECT) + +static void +gmyth_query_class_init (GMythQueryClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_query_dispose; + gobject_class->finalize = gmyth_query_finalize; +} + +static void +gmyth_query_init (GMythQuery *gmyth_query) +{ + GMythSettings *gmyth_settings = gmyth_context_get_settings (); + + gmyth_query->opt_host_name = gmyth_settings_get_backend_hostname(gmyth_settings); + gmyth_query->opt_user_name = gmyth_settings_get_username(gmyth_settings); + gmyth_query->opt_password = gmyth_settings_get_password(gmyth_settings); + gmyth_query->opt_db_name = gmyth_settings_get_dbname(gmyth_settings); + + /* initialize connection handler */ + gmyth_query->conn = mysql_init (NULL); + + if (!(gmyth_query->conn)) + g_warning ("[%s] MSQL structure not initialized", __FUNCTION__); + +} + +static void +gmyth_query_dispose (GObject *object) +{ + GMythQuery *gmyth_query = GMYTH_QUERY (object); + + /* disconnect from server */ + gmyth_query_disconnect (gmyth_query); + + G_OBJECT_CLASS (gmyth_query_parent_class)->dispose (object); +} + +static void +gmyth_query_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_query_parent_class)->finalize (object); +} + +/** Creates a new instance of GMythQuery. + * + * @return a new instance of GMythQuery. + */ +GMythQuery* +gmyth_query_new () +{ + GMythQuery *sql_query = GMYTH_QUERY (g_object_new(GMYTH_QUERY_TYPE, NULL)); + + return sql_query; +} + +/** Connects to the Mysql database in the backend. The backend address + * is loaded from the GMythSettings instance. + * + * @param gmyth_query the GMythEPG instance to be connected. + * @return true if connection was success, false if failed. + */ +gboolean +gmyth_query_connect (GMythQuery *gmyth_query) +{ + char *opt_host_name; + char *opt_user_name; + char *opt_password; + char *opt_db_name; + + assert(gmyth_query); + + opt_host_name = (gmyth_query->opt_host_name ? gmyth_query->opt_host_name->str : NULL); + opt_db_name = (gmyth_query->opt_db_name ? gmyth_query->opt_db_name->str : NULL); + opt_user_name = (gmyth_query->opt_user_name ? gmyth_query->opt_user_name->str : NULL); + opt_password = (gmyth_query->opt_password ? gmyth_query->opt_password->str : NULL); + + + if (gmyth_query->conn == NULL) { + gmyth_query_print_error (NULL, "mysql_init() failed (probably out of memory)"); + return FALSE; + } + + /* connect to server */ + if (mysql_real_connect (gmyth_query->conn, opt_host_name, + opt_user_name, opt_password, opt_db_name, + 0, NULL, 0) == NULL) { + + gmyth_query_print_error (gmyth_query->conn, "mysql_real_connect() failed"); + return FALSE; + } + + g_debug ("[%s] Connection to Mysql server succeeded!", __FUNCTION__); + + return TRUE; +} + +/** Disconnects from the Mysql database in the backend. + * + * @param gmyth_query the GMythQuery instance to be disconnected + * @return true if disconnection was success, false if failed. + */ +gboolean +gmyth_query_disconnect (GMythQuery *gmyth_query) +{ + assert(gmyth_query); + + /* TODO: Check how to return error */ + g_debug ("[%s] Closing gmyth_query->conn", __FUNCTION__); + mysql_close (gmyth_query->conn); + + return TRUE; +} + +static void +gmyth_query_print_error (MYSQL *conn, char *message) +{ + fprintf (stderr, "%s\n", message); + + if (conn != NULL) { +#if MYSQL_VERSION_ID >= 40101 + fprintf (stderr, "Error %u (%s): %s\n", + mysql_errno (conn), mysql_sqlstate(conn), mysql_error (conn)); +#else + fprintf (stderr, "Error %u: %s\n", + mysql_errno (conn), mysql_error (conn)); +#endif + } +} + +/** Sends the given query to the backend returning the query result as + * MYSQL_RES pointer. + * + * FIXME: this function is returning NULL whether any error happens + * or no rows are returned (e.g. UPDATE or REPLACE). + * + * @param gmyth_query the GMythQuery instance. + * @param stmt_str the query text. + * @return the MYSQL_RES result pointer or NULL if any error happens. + */ +MYSQL_RES* +gmyth_query_process_statement (GMythQuery *gmyth_query, char *stmt_str) +{ + MYSQL_RES *res_set; + + assert(gmyth_query); + + g_debug ("[%s] Running mysql query %s", __FUNCTION__, stmt_str); + + if (gmyth_query == NULL) + return NULL; + + /* the statement failed */ + if (mysql_query (gmyth_query->conn, stmt_str) != 0) { + gmyth_query_print_error (gmyth_query->conn, "Could not execute statement"); + return NULL; + } + + /* the statement succeeded; determine whether it returned data */ + res_set = mysql_store_result (gmyth_query->conn); + if (res_set) { + return res_set; + } else if (mysql_field_count (gmyth_query->conn) == 0) { + g_debug ("%lu rows affected\n", + (unsigned long) mysql_affected_rows (gmyth_query->conn)); + } else { + gmyth_query_print_error (gmyth_query->conn, "Could not retrieve result set"); + } + + return NULL; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_query.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_query.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,84 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_query.h + * + * @brief

GMythQuery class provides a wrapper for accessing + * the libmysqlclient funtions. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Leonardo Sobral Cunha + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef __GMYTH_QUERY_H__ +#define __GMYTH_QUERY_H__ + +#include + +/* MYSQL includes */ +#include + +#define G_BEGIN_DECLS + +#define GMYTH_QUERY_TYPE (gmyth_query_get_type ()) +#define GMYTH_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_QUERY_TYPE, GMythQuery)) +#define GMYTH_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_QUERY_TYPE, GMythQueryClass)) +#define IS_GMYTH_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_QUERY_TYPE)) +#define IS_GMYTH_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_QUERY_TYPE)) +#define GMYTH_QUERY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_QUERY_TYPE, GMythQueryClass)) + + +typedef struct _GMythQuery GMythQuery; +typedef struct _GMythQueryClass GMythQueryClass; + +struct _GMythQueryClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythQuery +{ + GObject parent; + + GString *opt_host_name; /* server host (default=localhost) */ + GString *opt_user_name; /* username (default=login name) */ + GString *opt_password; /* password (default=none) */ + unsigned int opt_port_num; /* port number (use built-in value) */ + GString *opt_socket_name; /* socket name (use built-in value) */ + GString *opt_db_name; /* database name (default=none) */ + unsigned int opt_flags; /* connection flags (none) */ + MYSQL *conn; /* pointer to connection handler */ +}; + + +GType gmyth_query_get_type (void); + +GMythQuery* gmyth_query_new (); +MYSQL_RES * gmyth_query_process_statement + (GMythQuery *gmyth_query, char *stmt_str); + +gboolean gmyth_query_connect (GMythQuery *gmyth_query); +gboolean gmyth_query_disconnect (GMythQuery *gmyth_query); + +#define G_END_DECLS + +#endif /* __GMYTH_QUERY_H__ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_remote_encoder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_remote_encoder.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,207 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_remote_encoder.c + * + * @brief

GMythRemoteEncoder class defines functions for playing live tv. + * + * The remote encoder is used by gmyth_tvplayer to setup livetv. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 "gmyth_remote_encoder.h" + +#include + +#include "gmyth_stringlist.h" + +static void gmyth_remote_encoder_class_init (GMythRemoteEncoderClass *klass); +static void gmyth_remote_encoder_init (GMythRemoteEncoder *object); + +static void gmyth_remote_encoder_dispose (GObject *object); +static void gmyth_remote_encoder_finalize (GObject *object); + +G_DEFINE_TYPE(GMythRemoteEncoder, gmyth_remote_encoder, G_TYPE_OBJECT) + +static void +gmyth_remote_encoder_class_init (GMythRemoteEncoderClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_remote_encoder_dispose; + gobject_class->finalize = gmyth_remote_encoder_finalize; +} + +static void +gmyth_remote_encoder_init (GMythRemoteEncoder *gmyth_remote_encoder) +{ +} + +static void +gmyth_remote_encoder_dispose (GObject *object) +{ + // GMythRemoteEncoder *gmyth_remote_encoder = GMYTH_REMOTE_ENCODER(object); + + G_OBJECT_CLASS (gmyth_remote_encoder_parent_class)->dispose (object); +} + + +static void +gmyth_remote_encoder_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + GMythRemoteEncoder *remote_encoder = GMYTH_REMOTE_ENCODER(object); + + g_debug ("[%s] Closing control socket", __FUNCTION__); + gmyth_socket_close_connection(remote_encoder->myth_socket); + g_object_unref (remote_encoder->myth_socket); + + G_OBJECT_CLASS (gmyth_remote_encoder_parent_class)->finalize (object); +} + +/** Creates a new instance of GMythRemoteEncoder. + * + * @return a new instance of GMythRemoteEncoder. + */ +GMythRemoteEncoder* +gmyth_remote_encoder_new (int num, GString *hostname, gshort port) +{ + GMythRemoteEncoder *encoder = GMYTH_REMOTE_ENCODER ( g_object_new ( + GMYTH_REMOTE_ENCODER_TYPE, FALSE )); + + encoder->recorder_num = num; + encoder->hostname = g_string_new (hostname->str); + encoder->port = port; + + return encoder; +} + +/** Configures the remote encoder instance connecting it to Mythtv backend. + * + * @param remote_encoder the GMythRemoteEncoder instance. + * @return TRUE if successfull, FALSE if any error happens. + */ +gboolean +gmyth_remote_encoder_setup (GMythRemoteEncoder *remote_encoder) +{ + assert (remote_encoder); + g_debug ("[%s] Creating socket and connecting to backend", __FUNCTION__); + + if (remote_encoder->myth_socket == NULL) { + + remote_encoder->myth_socket = gmyth_socket_new (); + + if (!gmyth_socket_connect_to_backend (remote_encoder->myth_socket, remote_encoder->hostname->str, + remote_encoder->port, TRUE) ) { + g_warning ("GMythRemoteEncoder: Connection to backend failed"); + return FALSE; + } + + } else { + g_warning("Remote encoder socket already created\n"); + } + + return TRUE; +} + +/** Sends the SPAWN_LIVETV command through Mythtv protocol. This command + * requests the backend to start capturing TV content. + * + * @param remote_encoder The GMythRemoteEncoder instance. + * @param tvchain_id The tvchain unique id. + * @return true if success, false if any error happens. + */ +gboolean +gmyth_remote_encoder_spawntv (GMythRemoteEncoder *remote_encoder, GString *tvchain_id) +{ + GMythStringList *str_list; + GString *tmp_str; + + g_debug ("[%s] Spawntv with tvchain_id = %s", __FUNCTION__, tvchain_id->str); + + str_list = gmyth_string_list_new (); + + tmp_str = g_string_new ("QUERY_RECORDER "); + g_string_append_printf (tmp_str, "%d", remote_encoder->recorder_num); + + gmyth_string_list_append_string (str_list, tmp_str); + gmyth_string_list_append_string (str_list, g_string_new ("SPAWN_LIVETV")); + gmyth_string_list_append_string (str_list, tvchain_id); + gmyth_string_list_append_int (str_list, 0); // PIP = FALSE (0) + + gmyth_socket_sendreceive_stringlist (remote_encoder->myth_socket, str_list); + + g_string_free (tmp_str, TRUE); + + tmp_str = gmyth_string_list_get_string (str_list, 0); + if (tmp_str == NULL) { + g_warning ("[%s] Spawntv request returned %s", __FUNCTION__, tmp_str->str); + return FALSE; + } + + if (g_ascii_strncasecmp (tmp_str->str, "ok", 2)) { + g_warning ("[%s] Spawntv request returned %s", __FUNCTION__, tmp_str->str); + g_object_unref (str_list); + return FALSE; + } + + g_object_unref (str_list); + return TRUE; + +} + +/** Sends the command STOP_LIVETV to Mythtv backend. + * + * @param remote_encoder the GMythRemoteEncoder instance. + * @return true if success, false if any error happens. + */ +gboolean +gmyth_remote_encoder_stop_livetv (GMythRemoteEncoder *remote_encoder) +{ + GMythStringList *str_list; + GString *tmp_str; + + g_debug ("[%s]", __FUNCTION__); + + str_list = gmyth_string_list_new (); + + tmp_str = g_string_new ("QUERY_RECORDER "); + g_string_append_printf (tmp_str, "%d", remote_encoder->recorder_num); + gmyth_string_list_append_string (str_list, g_string_new ("STOP_LIVETV")); + + gmyth_socket_sendreceive_stringlist (remote_encoder->myth_socket, str_list); + + g_string_free (tmp_str, TRUE); + + tmp_str = gmyth_string_list_get_string (str_list, 0); + if (g_ascii_strncasecmp (tmp_str->str, "ok", 2)) { + g_warning ("[%s] Stop livetv request returned %s", __FUNCTION__, tmp_str->str); + g_object_unref (str_list); + return FALSE; + } + + g_object_unref (str_list); + return TRUE; + +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_remote_encoder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_remote_encoder.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,89 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_remote_encoder.h + * + * @brief

GMythRemoteEncoder class defines functions for playing live tv. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef __GMYTH_REMOTE_ENCODER_H__ +#define __GMYTH_REMOTE_ENCODER_H__ + +#include + +#include "gmyth_socket.h" + +#include +#include +#include +#include +#include +#include + +#define G_BEGIN_DECLS + +#define GMYTH_REMOTE_ENCODER_TYPE (gmyth_remote_encoder_get_type ()) +#define GMYTH_REMOTE_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_REMOTE_ENCODER_TYPE, GMythRemoteEncoder)) +#define GMYTH_REMOTE_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_REMOTE_ENCODER_TYPE, GMythRemoteEncoderClass)) +#define IS_GMYTH_REMOTE_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_REMOTE_ENCODER_TYPE)) +#define IS_GMYTH_REMOTE_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_REMOTE_ENCODER_TYPE)) +#define GMYTH_REMOTE_ENCODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_REMOTE_ENCODER_TYPE, GMythRemoteEncoderClass)) + + +typedef struct _GMythRemoteEncoder GMythRemoteEncoder; +typedef struct _GMythRemoteEncoderClass GMythRemoteEncoderClass; + +struct _GMythRemoteEncoderClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythRemoteEncoder +{ + GObject parent; + + /* socket descriptor */ + GMythSocket *myth_socket; + + int recorder_num; + GString *hostname; + int port; +}; + + +GType gmyth_remote_encoder_get_type (void); + +GMythRemoteEncoder* gmyth_remote_encoder_new (int num, + GString *hostname, + gshort port); + +gboolean gmyth_remote_encoder_setup (GMythRemoteEncoder *encoder); +gboolean gmyth_remote_encoder_spawntv (GMythRemoteEncoder *remote_encoder, + GString *tvchain_id); +gboolean gmyth_remote_encoder_stop_livetv (GMythRemoteEncoder *remote_encoder); + +#define G_END_DECLS + +#endif /* __GMYTH_REMOTE_ENCODER_H__ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_remote_util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_remote_util.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,70 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_remote_util.c + * + * @brief

This component provides utility functions for accessing remote data. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 "gmyth_remote_util.h" + +#include "gmyth_context.h" +#include "gmyth_remote_encoder.h" +#include "gmyth_stringlist.h" + +/** Requests the Mythtv backend for a free remote recorder. + * + * @param curr The recorder index, or -1 to consider the first one. + * @return the remote encoder instance available, or NULL if any error happens. + */ +GMythRemoteEncoder* +remote_request_next_free_recorder (int curr) +{ + GMythRemoteEncoder *encoder; + GString *hostname; + int num, port; + + GMythStringList *strlist = gmyth_string_list_new(); + + g_debug ("[%s] Request next free recorder in the backend", __FUNCTION__); + + gmyth_string_list_append_char_array (strlist, "GET_NEXT_FREE_RECORDER"); + gmyth_string_list_append_int (strlist, curr); + + if (!gmyth_context_send_receive_stringlist(strlist)) { + g_warning ("GET_NEXT_FREE_RECORDER request error!\n"); + return NULL; + } + + num = gmyth_string_list_get_int (strlist, 0); + hostname = gmyth_string_list_get_string (strlist, 1); + port = gmyth_string_list_get_int (strlist, 2); + + g_debug ("[%s] Free recorder info received: num: %d, hostname: %s, port: %d", + __FUNCTION__, num, hostname->str, port); + + encoder = gmyth_remote_encoder_new (num, hostname, port); + + g_object_unref (strlist); + + return encoder; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_remote_util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_remote_util.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,35 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_remote_util.h + * + * @brief

This component provides utility functions for accessing remote data. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef __REMOTE_UTIL_H__ +#define __REMOTE_UTIL_H__ + +#include "gmyth_remote_encoder.h" + +GMythRemoteEncoder* remote_request_next_free_recorder (int curr); + +#endif diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_scheduler.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_scheduler.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,610 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_scheduler.c + * + * @brief

The scheduler encapsulates all functions for browsing, scheduling + * and modifying the recorded content. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Alexsandro Jose Virginio dos Santos + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + +#include "gmyth_scheduler.h" + +#include "gmyth_context.h" +#include "gmyth_util.h" +#include "gmyth_query.h" + +static void gmyth_scheduler_class_init (GMythSchedulerClass *klass); +static void gmyth_scheduler_init (GMythScheduler *object); + +static void gmyth_scheduler_dispose (GObject *object); +static void gmyth_scheduler_finalize (GObject *object); + +static gint get_record_id_from_database (GMythScheduler *scheduler); +static void update_backend (gint record_id); + +G_DEFINE_TYPE(GMythScheduler, gmyth_scheduler, G_TYPE_OBJECT) + +static void +gmyth_scheduler_class_init (GMythSchedulerClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_scheduler_dispose; + gobject_class->finalize = gmyth_scheduler_finalize; +} + +static void +gmyth_scheduler_init (GMythScheduler *sched) +{ + sched->recordid =0; + sched->type = 0; + sched->search = 0; + sched->profile = g_string_new(""); + + sched->dupin = 0; + sched->dupmethod = 0; + sched->autoexpire = 0; + sched->autotranscode = 0; + sched->transcoder = 0; + + sched->autocommflag = 0; + sched->autouserjob1 = 0; + sched->autouserjob2 = 0; + sched->autouserjob3 = 0; + sched->autouserjob4 = 0; + + sched->startoffset = 0; + sched->endoffset = 0; + sched->maxepisodes = 0; + sched->maxnewest = 0; + + sched->recpriority = 0; + sched->recgroup = 0; + sched->playgroup = 0; + + sched->prefinput = 0; + sched->inactive = 0; + + sched->searchType = g_string_new(""); + sched->searchForWhat = g_string_new(""); + + sched->msqlquery = gmyth_query_new (); +} + +static void +gmyth_scheduler_dispose (GObject *object) +{ + G_OBJECT_CLASS (gmyth_scheduler_parent_class)->dispose (object); +} + +static void +gmyth_scheduler_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_scheduler_parent_class)->finalize (object); +} + +/** Creates a new instance of GMythScheduler. + * + * @return a new instance of GMythScheduler. + */ +GMythScheduler* +gmyth_scheduler_new () +{ + GMythScheduler *scheduler = + GMYTH_SCHEDULER (g_object_new(GMYTH_SCHEDULER_TYPE, NULL)); + + return scheduler; +} + +/** Connects to the Mysql database in the backend. The backend address + * is loaded from the GMythSettings instance. + * + * @param scheduler the GMythScheduler instance to be connected. + * @return true if connection was success, false if failed. + */ +gboolean +gmyth_scheduler_connect (GMythScheduler *scheduler) +{ + assert(scheduler); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] MMythScheduler not initialized", __FUNCTION__); + return FALSE; + } + + if (!gmyth_query_connect(scheduler->msqlquery)) { + g_warning ("[%s] Error while connecting to db", __FUNCTION__); + return FALSE; + } + + return TRUE; +} + +/** Disconnects from the Mysql database in the backend. + * + * @param scheduler the GMythScheduler instance to be disconnected + * @return true if disconnection was success, false if failed. + */ +gboolean +gmyth_scheduler_disconnect (GMythScheduler *scheduler) +{ + assert(scheduler); + + if (scheduler->msqlquery != NULL) { + g_object_unref (scheduler->msqlquery); + } + + return TRUE; +} + +/** Retrieves from the backend Mysql database the list of recording schedules. + * + * @param scheduler The GMythScheduler instance. + * @param schedule_list the GList pointer to be filled with the loaded list of ScheduleInfo items. + * @return The amount of schedules retrieved from database, or -1 if error. + */ +gint +gmyth_scheduler_get_schedule_list ( GMythScheduler *scheduler, GList **schedule_list) +{ + ScheduleInfo *schedule; + MYSQL_RES *msql_res; + GString *query_str = g_string_new (""); + GString *date_time = g_string_new (""); + + assert(scheduler); + + g_string_printf (query_str, + "SELECT recordid,programid,chanid,starttime,startdate," + "endtime,enddate,title,subtitle,description,category FROM record;"); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__); + return -1; + } + msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str); + + if (msql_res == NULL) { + g_warning ("DB retrieval of schedule list failed"); + return -1; + } else { + MYSQL_ROW row; + *schedule_list = NULL; + + while((row = mysql_fetch_row (msql_res)) != NULL) { + schedule = g_new0(ScheduleInfo, 1); + + schedule->record_id = atoi (row[0]); + schedule->program_id = atoi (row[1]); + schedule->channel_id = atoi (row[2]); + + /* generate a time_t from a time and a date db field */ + g_string_printf (date_time, "%s %s", row[4], row[3]); + + schedule->start_time = gmyth_util_string_to_time (date_time); + + /* generate a time_t from a time and a date db field */ + g_string_printf (date_time, "%s %s", row[6], row[5]); + + schedule->end_time = gmyth_util_string_to_time (date_time); + + schedule->title = g_string_new (row[7]); + schedule->subtitle = g_string_new (row[8]); + schedule->description = g_string_new (row[9]); + schedule->category = g_string_new (row[10]); + + (*schedule_list) = g_list_append (*(schedule_list), schedule); + } + } + + mysql_free_result (msql_res); + g_string_free(query_str, TRUE); + g_string_free(date_time, TRUE); + + return (*schedule_list == NULL) ? 0 : g_list_length (*schedule_list); +} + +/** Retrieves from the backend Mysql database the list of recorded programs. + * + * @param scheduler The GMythScheduler instance. + * @param recorded_list the GList pointer to be filled with the loaded RecordInfo items. + * @return The amount of recorded retrieved from database, or -1 if error. + */ +gint +gmyth_scheduler_get_recorded_list (GMythScheduler *scheduler, GList **recorded_list) +{ + RecordedInfo *record; + MYSQL_RES *msql_res; + GString *query_str = g_string_new (""); + GString *date_time = g_string_new (""); + + assert(scheduler); + + g_string_printf (query_str, + "SELECT recordid,programid,chanid,starttime,progstart," + "endtime,progend,title,subtitle,description,category,basename FROM recorded;"); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__); + return -1; + } + + msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str); + + if (msql_res == NULL) { + g_warning ("DB retrieval of recording list failed"); + return -1; + } else { + MYSQL_ROW row; + *recorded_list = NULL; + + while((row = mysql_fetch_row (msql_res))!=NULL){ + record = g_new0(RecordedInfo, 1); + + record->record_id = atoi (row[0]); + record->program_id = atoi (row[1]); + record->channel_id = atoi (row[2]); + + /* the db field time already contains the date. therefore + * we are not using the date field */ + /* generate a time_t from a time and a date db field */ + /* g_string_printf (date_time, "%s %s", row[4], row[3]); */ + g_string_printf (date_time, "%s", row[3]); + + record->start_time = gmyth_util_string_to_time (date_time); + + /* the db field time already contains the date. therefore + * we are not using the date field */ + /* generate a time_t from a time and a date db field */ + /* g_string_printf (date_time, "%s %s", row[6], row[5]); */ + g_string_printf (date_time, "%s", row[5]); + + record->end_time = gmyth_util_string_to_time (date_time); + + record->title = g_string_new (row[7]); + record->subtitle = g_string_new (row[8]); + record->description = g_string_new (row[9]); + record->category = g_string_new (row[10]); + record->basename = g_string_new (row[11]); + + *recorded_list = g_list_append (*recorded_list, record); + } + } + + mysql_free_result (msql_res); + g_string_free(query_str, TRUE); + g_string_free(date_time, TRUE); + + return (*recorded_list == NULL) ? 0 : g_list_length (*recorded_list); +} + +/** Requests the Mysql database in the backend to add a new schedule. + * + * @param scheduler the GMythScheduler instance. + * @param schedule_info the ScheduleInfo with recording schedule information + * to be added. record_id = -1 to add a new schedule, otherwise this + * function will update the schedule in the db + * @return gboolean returns FALSE if some error occurs, TRUE otherwise + */ +gboolean +gmyth_scheduler_add_schedule (GMythScheduler *scheduler, + ScheduleInfo *schedule_info) +{ + struct tm start_tm; + struct tm end_tm; + + MYSQL_RES *msql_res; + GString *query_str = g_string_new (""); + + assert(scheduler); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__); + return 0; + } + + /* manipulating time */ + if(localtime_r(&schedule_info->start_time, &start_tm) == NULL) { + g_warning ("localtime_r error in libgmyth scheduler!\n"); + return FALSE; + } + + if(localtime_r(&schedule_info->end_time, &end_tm) == NULL) { + g_warning ("localtime_r error in libgmyth scheduler!\n"); + return FALSE; + } + + //TODO: verify if this funtion realy does what it should do! + g_string_printf (query_str, "REPLACE INTO record " + "(recordid, type, chanid, starttime, " + "startdate, endtime, enddate, title," + "profile, recpriority, maxnewest, inactive, " + "maxepisodes, autoexpire, startoffset, endoffset, " + "recgroup, dupmethod, dupin, station, " + "autocommflag, findday, findtime, findid, " + "search, autotranscode, transcoder, tsdefault, " + "autouserjob1, autouserjob2, autouserjob3, autouserjob4) " + " values ( %d, 1, %d, \"%02d:%02d:00\"," //recordid, type, chanid, starttime + " \"%d-%02d-%02d\", \"%02d:%02d:00\", \"%04d-%02d-%02d\", \"%s\"," + //startdate, endtime, enddate, title + "DEFAULT, 0, 0, 0, " //profile, recpriority, maxnewest, inactive + "0, 1, 0, 0, " //maxepisodes, autoexpire, startoffset, endoffset + "DEFAULT, 6, 15, %d, " //recgroup, dupmethod, dupin, station + "1, %d, \"%02d:%02d:00\", %d, " //autocommflag, findday, findtime, findid + "5, 0, 29, 1, " //search, autotranscode, transcoder, tsdefault + "0, 0, 0, 0 );", //autouserjob1, autouserjob2, autouserjob3, autouserjob4 + schedule_info->record_id, schedule_info->channel_id, + start_tm.tm_hour, start_tm.tm_min, + start_tm.tm_year+1900, start_tm.tm_mon+1, + start_tm.tm_mday, + end_tm.tm_hour, end_tm.tm_min, + end_tm.tm_year+1900, end_tm.tm_mon+1, + end_tm.tm_mday, schedule_info->title->str, //title + schedule_info->channel_id,//station + start_tm.tm_wday+1, //findday + start_tm.tm_hour, start_tm.tm_min, //findtime + (gint)(schedule_info->start_time/60/60/24 + 719528)//findid + ); + + msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str); + + /* FIXME: currently no way to detect db error in UPDATE, REPLACES! + if (msql_res == NULL) { + g_warning ("DB retrieval of recording list failed"); + return -1; + }*/ + + /* TODO: verify record_id = -1 semantics */ + if (schedule_info->record_id <= 0) + schedule_info->record_id = get_record_id_from_database(scheduler); + + /* Notify the backend of changes */ + update_backend(schedule_info->record_id); + + /* free allocated memory */ + mysql_free_result (msql_res); + g_string_free(query_str, TRUE); + + return 1; +} + +/** Requests the Mysql database in the backend to remove an existing schedule. + * + * @param scheduler the GMythScheduler instance. + * @param record_id The schedule's record id to be removed + * @return gboolean TRUE if success, FALSE if error + */ +gboolean +gmyth_scheduler_delete_schedule (GMythScheduler *scheduler, gint record_id) +{ + + MYSQL_RES *msql_res; + GString *query_str = g_string_new (""); + + assert(scheduler); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__); + return FALSE; + } + + //======================================== + g_string_printf (query_str, + "DELETE FROM record WHERE recordid=%d", record_id); + + msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str); + + if (msql_res == NULL) { + g_warning ("[%s] Error while trying to delete a schedule in the database", __FUNCTION__); + return FALSE; + } + + update_backend(record_id);// Notify the backend of the changes + + mysql_free_result (msql_res); + g_string_free(query_str, TRUE); + + return TRUE; +} + +/** Requests the Mysql database in the backend to remove an existing recorded item. + * + * @param scheduler the GMythScheduler instance. + * @param record_id The recorded item id to be removed + * @return gboolean TRUE if success, FALSE if error + */ +gboolean +gmyth_scheduler_delete_recorded (GMythScheduler *scheduler, gint record_id) +{ + + MYSQL_RES *msql_res; + GString *query_str = g_string_new (""); + + assert(scheduler); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__); + return FALSE; + } + + //======================================== + g_string_printf (query_str, + "DELETE FROM recorded WHERE recordid=%d", record_id); + + msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str); + + update_backend(record_id);// Notify the backend of the changes + + mysql_free_result (msql_res); + g_string_free(query_str, TRUE); + + return TRUE; +} + +/** Retrieves an existing recorded item information from database. The information + * is used to fill the returned GMythProgramInfo. + * + * @param scheduler The GMythScheduler instance. + * @param channel The channel associated to the record + * @param starttime The record start time + * @return A GMythProgramInfo struct with the requested record item + * information, or NULL if error. + */ +GMythProgramInfo* +gmyth_scheduler_get_recorded (GMythScheduler *scheduler, + GString *channel, time_t starttime) +{ + MYSQL_RES *msql_res; + GMythProgramInfo *proginfo = NULL; + GString *query_str = g_string_new(""); + GString *time_str = gmyth_util_time_to_string (starttime); + + assert(scheduler); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__); + return NULL; + } + + g_string_printf (query_str, "SELECT recorded.chanid,starttime,endtime,title, " + "subtitle,description,channel.channum, " + "channel.callsign,channel.name,channel.commfree, " + "channel.outputfilters,seriesid,programid,filesize, " + "lastmodified,stars,previouslyshown,originalairdate, " + "hostname,recordid,transcoder,playgroup, " + "recorded.recpriority,progstart,progend,basename,recgroup " + "FROM recorded " + "LEFT JOIN channel " + "ON recorded.chanid = channel.chanid " + "WHERE recorded.chanid = \"%s\" " + "AND starttime = \"%s\" ;", + channel->str, time_str->str); + + msql_res = gmyth_query_process_statement (scheduler->msqlquery, query_str->str); + + if (msql_res /*&& query.size() > 0*/) { + + MYSQL_ROW msql_row = mysql_fetch_row (msql_res); + if (msql_row) { + + proginfo = g_new0 (GMythProgramInfo, 1); + + proginfo->chanid = g_string_new (msql_row[0]); + proginfo->startts = gmyth_util_string_to_time (g_string_new (msql_row[23])); + proginfo->endts = gmyth_util_string_to_time (g_string_new (msql_row[24])); + proginfo->recstartts = gmyth_util_string_to_time (g_string_new (msql_row[1])); + proginfo->recendts = gmyth_util_string_to_time (g_string_new (msql_row[2])); + proginfo->title = g_string_new (msql_row[3]); + proginfo->subtitle = g_string_new (msql_row[4]); + proginfo->description = g_string_new (msql_row[5]); + + proginfo->chanstr = g_string_new (msql_row[6]); + proginfo->chansign = g_string_new (msql_row[7]); + proginfo->channame = g_string_new (msql_row[0]); + proginfo->chancommfree = atoi (msql_row[9]); + proginfo->chanOutputFilters = g_string_new (msql_row[10]); + proginfo->seriesid = g_string_new (msql_row[11]); + proginfo->programid = g_string_new (msql_row[12]); + proginfo->filesize = atoll (msql_row[13]); + + proginfo->lastmodified = gmyth_util_string_to_time (g_string_new (msql_row[14])); + + proginfo->stars = atof (msql_row[15]); + proginfo->repeat = atoi (msql_row[16]); + + if (msql_row[17] == NULL) { + proginfo->originalAirDate = 0; + proginfo->hasAirDate = FALSE; + } else { + proginfo->originalAirDate = gmyth_util_string_to_time (g_string_new (msql_row[17])); + proginfo->hasAirDate = TRUE; + } + + proginfo->hostname = g_string_new (msql_row[18]); + proginfo->recordid = atoi (msql_row[19]); + proginfo->transcoder = atoi (msql_row[20]); + + //proginfo->spread = -1; + //proginfo->programflags = proginfo->getProgramFlags(); + + proginfo->recgroup = g_string_new (msql_row[26]); + proginfo->playgroup = g_string_new (msql_row[21]); + proginfo->recpriority = atoi (msql_row[22]); + + proginfo->pathname = g_string_new (msql_row[25]); + + g_debug ("One program info loaded from mysql database\n"); + } + } + + mysql_free_result (msql_res); + g_string_free(query_str, TRUE); + g_string_free(time_str, TRUE); + + return proginfo; +} + +/** Retrieves the next record id. + * + * @param scheduler The GMythScheduler instance. + * @return gint record_id if success, -1 otherwise + */ +static gint +get_record_id_from_database (GMythScheduler *scheduler) +{ + gint record_id; + + assert(scheduler); + + if (scheduler->msqlquery == NULL) { + g_warning ("[%s] Scheduler db connection not initialized", __FUNCTION__); + return 0; + } + + record_id = mysql_insert_id (scheduler->msqlquery->conn); + + return record_id; +} + +/** Notifies the backend of an update in the db. + * + * @param record_id the id of the modified recording. + */ +static void +update_backend(gint record_id)//fixme: put void and discovery record_id inside +{ + GMythStringList *strlist = gmyth_string_list_new (); + GString *datastr = g_string_new ("RESCHEDULE_RECORDINGS "); + + g_string_append_printf (datastr, "%d", record_id); + gmyth_string_list_append_string (strlist, datastr); + + gmyth_context_send_receive_stringlist (strlist); + + g_string_free(datastr, TRUE); + g_object_unref(strlist); +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_scheduler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_scheduler.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,156 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_scheduler.h + * + * @brief

The scheduler encapsulates all functions for browsing, scheduling + * and modifying the recorded content. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Alexsandro Jose Virginio dos Santos + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef __GMYTH_SCHEDULER_H__ +#define __GMYTH_SCHEDULER_H__ + +#include +#include + +#include "gmyth_common.h" +#include "gmyth_query.h" + +#define G_BEGIN_DECLS + +#define GMYTH_SCHEDULER_TYPE (gmyth_scheduler_get_type ()) +#define GMYTH_SCHEDULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_SCHEDULER_TYPE, GMythScheduler)) +#define GMYTH_SCHEDULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_SCHEDULER_TYPE, GMythSchedulerClass)) +#define IS_GMYTH_SCHEDULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_SCHEDULER_TYPE)) +#define IS_GMYTH_SCHEDULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_SCHEDULER_TYPE)) +#define GMYTH_SCHEDULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_SCHEDULER_TYPE, GMythSchedulerClass)) + + +typedef struct _GMythScheduler GMythScheduler; +typedef struct _GMythSchedulerClass GMythSchedulerClass; + +struct _GMythSchedulerClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythScheduler +{ + GObject parent; + + unsigned long recordid; + unsigned long type; + unsigned long search; + GString *profile; + + long dupin; + long dupmethod; + long autoexpire; + short int autotranscode; + long transcoder; + + short int autocommflag; + short int autouserjob1; + short int autouserjob2; + short int autouserjob3; + short int autouserjob4; + + long startoffset; + long endoffset; + long maxepisodes; + long maxnewest; + + long recpriority; + GString *recgroup; + GString *playgroup; + + long prefinput; + short int inactive; + + GString *searchType; + GString *searchForWhat; + + GMythQuery *msqlquery; +}; + +typedef struct { + gint record_id; + gint program_id; + gint channel_id; + + time_t start_time; + time_t end_time; + + GString *title; + GString *subtitle; + GString *description; + GString *category; + +} ScheduleInfo; + +typedef struct { + gint record_id; + gint program_id; + gint channel_id; + + time_t start_time; + time_t end_time; + + GString *title; + GString *subtitle; + GString *description; + GString *category; + + GString *basename; + +} RecordedInfo; + + +GType gmyth_scheduler_get_type (void); + +GMythScheduler* gmyth_scheduler_new (); +gboolean gmyth_scheduler_connect (GMythScheduler *scheduler); +gboolean gmyth_scheduler_disconnect (GMythScheduler *scheduler); + +gint gmyth_scheduler_get_schedule_list (GMythScheduler *scheduler, + GList **sched_list); +gint gmyth_scheduler_get_recorded_list (GMythScheduler *scheduler, + GList **rec_list); + +GMythProgramInfo* gmyth_scheduler_get_recorded (GMythScheduler *scheduler, + GString *channel, time_t starttime); + +gint gmyth_scheduler_add_schedule(GMythScheduler *scheduler, + ScheduleInfo *schedule_info); + +gint gmyth_scheduler_delete_schedule (GMythScheduler *scheduler, + gint record_id); +gint gmyth_scheduler_delete_recorded (GMythScheduler *scheduler, + gint record_id); + +#define G_END_DECLS + +#endif /* __GMYTH_SCHEDULER_H__ */ + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_settings.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_settings.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,417 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_settings.c + * + * @brief

This component contains functions acessing and modifying + * user and program settings. + * + * The standard settings file is created in the user home folder, in the + * file ~/.mmyth/settings.dat. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Alexsandro Jose Virginio dos Santos + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 "gmyth_settings.h" + +#include +#include +#include +#include + +#include +#include +#include + +#define GMYTH_SETTINGS_FILE_NAME "settings.dat" +#define GMYTH_SETTINGS_DIR ".mmyth" + +static void gmyth_settings_class_init (GMythSettingsClass *klass); +static void gmyth_settings_init (GMythSettings *object); + +static void gmyth_settings_dispose (GObject *object); +static void gmyth_settings_finalize (GObject *object); + +static void fill_settings_data(GMythSettings *gmyth_settings, char* line); + +G_DEFINE_TYPE(GMythSettings, gmyth_settings, G_TYPE_OBJECT) + +static void +gmyth_settings_class_init (GMythSettingsClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_settings_dispose; + gobject_class->finalize = gmyth_settings_finalize; +} + +static void +gmyth_settings_init (GMythSettings *gmyth_settings) +{ + + gmyth_settings->settings_file = NULL; + + gmyth_settings->backend_hostname = g_string_new("127.0.0.1"); + gmyth_settings->backend_port = 6543; + gmyth_settings->mysql_dbname = g_string_new("mythconverg"); + gmyth_settings->mysql_username = g_string_new("mythtv"); + gmyth_settings->mysql_password = g_string_new("mythtv"); + gmyth_settings->database_type = g_string_new("mysql"); + +} + + +static void +gmyth_settings_dispose (GObject *object) +{ + GMythSettings *gmyth_settings = GMYTH_SETTINGS(object); + + if ( gmyth_settings->backend_hostname != NULL ) + g_string_free( gmyth_settings->backend_hostname, TRUE ); + if ( gmyth_settings->mysql_dbname != NULL ) + g_string_free( gmyth_settings->mysql_dbname, TRUE ); + if ( gmyth_settings->mysql_username != NULL ) + g_string_free( gmyth_settings->mysql_username, TRUE ); + if ( gmyth_settings->mysql_password != NULL ) + g_string_free( gmyth_settings->mysql_password, TRUE ); + if ( gmyth_settings->database_type != NULL ) + g_string_free( gmyth_settings->database_type, TRUE ); + + G_OBJECT_CLASS (gmyth_settings_parent_class)->dispose (object); +} + +static void +gmyth_settings_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_settings_parent_class)->finalize (object); +} + +/** Creates a new instance of GMythSettings. + * + * @return a new instance of GMythSettings. + */ +GMythSettings* +gmyth_settings_new () +{ + GMythSettings *gmyth_settings = GMYTH_SETTINGS (g_object_new(GMYTH_SETTINGS_TYPE, NULL)); + + return gmyth_settings; +} + +static gboolean +gmyth_settings_ensure_dir_exists (const gchar *dir) +{ + + g_debug ("[%s] \tdir = %s\n", __FUNCTION__, dir); + + if (g_file_test (dir, G_FILE_TEST_IS_DIR) == FALSE) { + if (g_file_test (dir, G_FILE_TEST_EXISTS) == TRUE) { + g_warning ("%s exists, please move it out of the way.", dir); + return FALSE; + } + + if (mkdir (dir, 488) != 0) { + g_warning ("Failed to create directory %s.", dir); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +gmyth_settings_ensure_file_exists (const gchar *file_name) { + + int file = 0; + + if ( g_file_test( file_name, G_FILE_TEST_EXISTS ) == FALSE ) { + g_debug ( "\n\tCreating %s file...\n", file_name ); + file = creat( file_name, S_IRWXU | S_IRWXO | S_IRWXG ); + + if ( close( file ) == -1 ) + return FALSE; + } + + return TRUE; +} + +/** Loads the GMyth settings from the given file. + * + * @param gmyth_settings the GMythSettings instance. + * @param filename The desired file to be opened. + * @return TRUE if success, FALSE if error. + */ +gboolean +gmyth_settings_load_from_file (GMythSettings *gmyth_settings, GString *filename) +{ + FILE *file_desc; + char line[100]; + + g_debug ("[%s] Loading GMyth settings file: %s", __FUNCTION__, filename->str); + + file_desc = fopen(filename->str, "r"); + if( file_desc == NULL) { + g_warning ("[%s] Settings file %s could not be opened", __FUNCTION__, filename->str); + return FALSE; + } + + gmyth_settings->settings_file = g_string_new (filename->str); + + while(fgets(line, 100, file_desc)) { + int i; + + /* Removes the new line characters from the end of line */ + for ( i = strlen(line)-1; i >= 0; i--) { + if ( !g_ascii_iscntrl (line[i]) ) { + line[i+1] = '\0'; + break; + } + } + + fill_settings_data(gmyth_settings, line); + } + + fclose (file_desc); + + return TRUE; +} + +/** Loads the GMyth settings from the standard settings file + * (~/.mmyth/settings.dat). + * + * @param gmyth_settings the GMythSettings instance. + * @return TRUE if success, FALSE if error. + */ +gboolean +gmyth_settings_load (GMythSettings *gmyth_settings) +{ + GString* file_full_path = g_string_new( g_build_filename( g_get_home_dir(), + GMYTH_SETTINGS_DIR, GMYTH_SETTINGS_FILE_NAME, NULL ) ); + + gmyth_settings->settings_file = file_full_path; + + gmyth_settings_ensure_dir_exists( g_build_filename( g_get_home_dir(), GMYTH_SETTINGS_DIR, NULL ) ); + + // Verifies if the file already exist + if ( g_file_test( file_full_path->str, G_FILE_TEST_EXISTS ) == FALSE ) { + g_debug ("[%s] Settings file does not exist. A new one will be created.\n", __FUNCTION__); + + if ( gmyth_settings_ensure_file_exists( file_full_path->str ) == FALSE ) + return FALSE; + + // Creates the file with default values (see _init function) + return gmyth_settings_save (gmyth_settings); + + } else { + g_debug ("[%s] Opening settings from file %s", __FUNCTION__, file_full_path->str); + + return gmyth_settings_load_from_file (gmyth_settings, file_full_path); + } +} + +/** Saves the current gmyth_settings to the settings file related to the + * given instance. + * + * @param gmyth_settings the GMythSettings instance. + * @return TRUE if success, FALSE if error. + */ +gboolean +gmyth_settings_save (GMythSettings *gmyth_settings) +{ + FILE *file_desc; + + if (gmyth_settings->settings_file == NULL) { + g_warning ("[%s] Settings were not loaded from file, could not save!", __FUNCTION__); + } + + file_desc = fopen(gmyth_settings->settings_file->str, "w"); + if( file_desc == NULL) { + g_warning ("GMYTH_SETTINGS: settings file %s not found", gmyth_settings->settings_file->str); + return FALSE; + } + + g_fprintf(file_desc, "#Maemo-Myth Settings\n"); + + g_fprintf(file_desc, "#General settings related with mythtv database\n"); + g_fprintf(file_desc, "dbname=%s\n", gmyth_settings->mysql_dbname->str); + g_fprintf(file_desc, "username=%s\n", gmyth_settings->mysql_username->str); + g_fprintf(file_desc, "password=%s\n", gmyth_settings->mysql_password->str); + + g_fprintf(file_desc, "\n#General settings related with mythtv backend\n"); + g_fprintf(file_desc, "hostname=%s\n", gmyth_settings->backend_hostname->str); + g_fprintf(file_desc, "backend_port=%d\n", gmyth_settings->backend_port); + + fclose (file_desc); + + g_debug ("[%s] Settings file saved", __FUNCTION__); + return TRUE; +} + +/** Gets the backend hostname from the settings. + * + * @param gmyth_settings the GMythSettings instance. + * @return The loaded backend hostname, or the default value "127.0.0.1" if settings + * file was not opened. + */ +GString* +gmyth_settings_get_backend_hostname (GMythSettings *gmyth_settings) +{ + return g_string_new (gmyth_settings->backend_hostname->str); +} + +/** Sets the backend hostname to the settings. + * + * @param gmyth_settings the GMythSettings instance. + * @param new_hostname The new hostname. + */ +void +gmyth_settings_set_backend_hostname (GMythSettings *gmyth_settings, GString *new_hostname) +{ + g_string_assign (gmyth_settings->backend_hostname, new_hostname->str); +} + +/** Gets the user name to connect to backend database. + * + * @param gmyth_settings the GMythSettings instance. + * @return The loaded user name, or the default value "mythtv" if settings + * file was not opened. + */ +GString* +gmyth_settings_get_username (GMythSettings *gmyth_settings) +{ + return g_string_new (gmyth_settings->mysql_username->str); +} + +/** Sets the username to connect to backend database. + * + * @param gmyth_settings the GMythSettings instance. + * @param new_username The new username. + */ +void +gmyth_settings_set_username (GMythSettings *gmyth_settings, GString *new_username) +{ + g_string_assign (gmyth_settings->mysql_username, new_username->str); +} + +/** Gets the database password from the settings file. + * + * @param gmyth_settings the GMythSettings instance. + * @return The loaded password, or the default value "mythtv" if settings + * file was not opened. + */ +GString* +gmyth_settings_get_password (GMythSettings *gmyth_settings) +{ + return g_string_new (gmyth_settings->mysql_password->str); +} + +/** Sets the database password. + * + * @param gmyth_settings the GMythSettings instance. + * @param new_password The new password. + */ + +void +gmyth_settings_set_password (GMythSettings *gmyth_settings, GString *new_password) +{ + g_string_assign (gmyth_settings->mysql_password, new_password->str); +} + +/** Gets the backend database name from the settings file. + * + * @param gmyth_settings the GMythSettings instance. + * @return The loaded database name, or the default value "mythconverg" if settings + * file was not opened. + */ +GString* +gmyth_settings_get_dbname (GMythSettings *gmyth_settings) +{ + return g_string_new (gmyth_settings->mysql_dbname->str); +} + +/** Sets the Mythtv database name to the settings. + * + * @param gmyth_settings the GMythSettings instance. + * @param new_dbname The new database name. + */ + +void +gmyth_settings_set_dbname (GMythSettings *gmyth_settings, GString *new_dbname) +{ + g_string_assign (gmyth_settings->mysql_dbname, new_dbname->str); +} + +/** Gets the backend port from the settings. + * + * @param gmyth_settings the GMythSettings instance. + * @return The loaded backend port, or the default value "6543" if settings + * file was not opened. + */ +int +gmyth_settings_get_backend_port (GMythSettings *gmyth_settings) +{ + return gmyth_settings->backend_port; +} + +/** Sets the backend port. + * + * @param gmyth_settings the GMythSettings instance. + * @param new_port The new port. + */ +void +gmyth_settings_set_backend_port (GMythSettings *gmyth_settings, gint new_port) +{ + gmyth_settings->backend_port = new_port; +} + + +static void +fill_settings_data(GMythSettings *gmyth_settings, char* line) +{ + gchar** str_splited; + + GString *gstr_splited; + gstr_splited = g_string_new(""); + str_splited = g_strsplit (line, "=", -1); + + if(!(strcmp(str_splited[0], "hostname"))){ + g_string_assign(gstr_splited, str_splited[1]); + gmyth_settings_set_backend_hostname(gmyth_settings, gstr_splited); + } + else if (!(strcmp(str_splited[0], "dbname"))){ + g_string_assign(gstr_splited, str_splited[1]); + gmyth_settings_set_dbname(gmyth_settings, gstr_splited); + } + else if (!(strcmp(str_splited[0], "username"))){ + g_string_assign(gstr_splited, str_splited[1]); + gmyth_settings_set_username(gmyth_settings, gstr_splited); + } + else if (!(strcmp(str_splited[0], "password"))){ + g_string_assign(gstr_splited, str_splited[1]); + gmyth_settings_set_password(gmyth_settings, gstr_splited); + } + else if (!(strcmp(str_splited[0], "backend_port"))){ + gmyth_settings_set_backend_port(gmyth_settings, atoi(str_splited[1])); + } +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_settings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_settings.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,103 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_settings.h + * + * @brief

This component contains functions acessing and modifying + * user and program settings. + * + * The standard settings file is created in the user home folder, in the + * file ~/.mmyth/settings.dat. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Alexsandro Jose Virginio dos Santos + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef __GMYTH_SETTINGS_H__ +#define __GMYTH_SETTINGS_H__ + +#include + +//#include +//#include +//#include +//#include +//#include +//#include + +#define G_BEGIN_DECLS + +#define GMYTH_SETTINGS_TYPE (gmyth_settings_get_type ()) +#define GMYTH_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_SETTINGS_TYPE, GMythSettings)) +#define GMYTH_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_SETTINGS_TYPE, GMythSettingsClass)) +#define IS_GMYTH_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_SETTINGS_TYPE)) +#define IS_GMYTH_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_SETTINGS_TYPE)) +#define GMYTH_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_SETTINGS_TYPE, GMythSettingsClass)) + + +typedef struct _GMythSettings GMythSettings; +typedef struct _GMythSettingsClass GMythSettingsClass; + +struct _GMythSettingsClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythSettings +{ + GObject parent; + + GString *settings_file; + + GString *backend_hostname; + int backend_port; + + GString *mysql_dbname; + GString *mysql_username; + GString *mysql_password; + // FIXME: Why do we need database_type? Do we intend to support other dbs? + GString *database_type; +}; + + +GType gmyth_settings_get_type (void); + +GMythSettings* gmyth_settings_new (); +gboolean gmyth_settings_load_from_file (GMythSettings *gmyth_settings, GString *filename); +gboolean gmyth_settings_load (GMythSettings *msettings); +gboolean gmyth_settings_save (GMythSettings *gmyth_settings); + +GString* gmyth_settings_get_backend_hostname (GMythSettings *gmyth_settings); +void gmyth_settings_set_backend_hostname (GMythSettings *gmyth_settings, GString *new_hostname); +GString* gmyth_settings_get_username (GMythSettings *gmyth_settings); +void gmyth_settings_set_username (GMythSettings *gmyth_settings, GString *new_username); +GString* gmyth_settings_get_password (GMythSettings *gmyth_settings); +void gmyth_settings_set_password (GMythSettings *gmyth_settings, GString *new_password); +GString* gmyth_settings_get_dbname (GMythSettings *gmyth_settings); +void gmyth_settings_set_dbname (GMythSettings *gmyth_settings, GString *new_dbname); +int gmyth_settings_get_backend_port (GMythSettings *gmyth_settings); +void gmyth_settings_set_backend_port (GMythSettings *gmyth_settings, gint new_port); + + +#define G_END_DECLS + +#endif /* __GMYTH_SETTINGS_H__ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_socket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_socket.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,708 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_socket.c + * + * @brief

MythTV socket implementation, according to the MythTV Project + * (www.mythtv.org). + * + * This component provides basic socket functionalities to interact with + * the Mythtv backend. + *

+ * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Rosfran Lins Borges + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 +#include + +#include +#include +#include +#include +#include +#include + +#include "gmyth_socket.h" +#include "gmyth_stringlist.h" +#include "gmyth_context.h" + +#define BUFLEN 512 +#define MYTH_SEPARATOR "[]:[]" +#define MYTH_PROTOCOL_FIELD_SIZE 8 + +static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + +static void gmyth_socket_class_init (GMythSocketClass *klass); +static void gmyth_socket_init (GMythSocket *object); + +static void gmyth_socket_dispose (GObject *object); +static void gmyth_socket_finalize (GObject *object); + +G_DEFINE_TYPE(GMythSocket, gmyth_socket, G_TYPE_OBJECT) + +static void +gmyth_socket_class_init (GMythSocketClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_socket_dispose; + gobject_class->finalize = gmyth_socket_finalize; +} + +static void +gmyth_socket_init (GMythSocket *gmyth_socket) +{ +} + +/** Gets the some important address translation info, from the client socket + * that will open a connection. + * + * @return gint that represents the error number from getaddrinfo(). + */ +static gint +gmyth_socket_toaddrinfo( gchar *addr, gint port, struct addrinfo **addrInfo ) +{ + struct addrinfo hints; + gchar *portStr = g_strnfill( 32, ' ' ); + gint errorn = EADDRNOTAVAIL; + + memset( &hints, 0, sizeof(hints) ); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + /* hints.ai_flags = AI_NUMERICHOST; */ + if ( port != -1 ) + sprintf(portStr, "%d", port); + else + portStr = NULL; + + g_debug( "[%s] Address: %s, port: %s\n", __FUNCTION__, addr, portStr ); + if ( ( errorn = getaddrinfo(addr, portStr, &hints, addrInfo) ) != 0 ) { + g_printerr( "[%s] Socket ERROR: %s\n", __FUNCTION__, gai_strerror(errorn) ); + } + + return errorn; +} + +/** This function retrieves the local hostname of the + * client machine. + * + * @return GString* get local hostname. + */ +GString * +gmyth_socket_get_local_hostname( ) +{ + GString *str = g_string_new(""); + + gchar *localhostname = g_strnfill( 1024, ' ' ); + gchar *localaddr = g_strdup( "127.0.0.1" ); + + gboolean found_addr = FALSE; + + struct addrinfo* addr_info_data = NULL, *addr_info0 = NULL; + + struct sockaddr_in* sa = NULL; + + g_static_mutex_lock( &mutex ); + + gethostname(localhostname, 1024); + + gint err = gmyth_socket_toaddrinfo( localhostname, -1, &addr_info_data ); + + addr_info0 = addr_info_data; + + while( addr_info0 != NULL && addr_info0->ai_addr != NULL && + ( sa = (struct sockaddr_in*)addr_info0->ai_addr ) != NULL && !found_addr ) { + localaddr = inet_ntoa( sa->sin_addr ); + if ( localaddr != NULL ) + g_print( "[%s] localaddr = %s\n", __FUNCTION__, localaddr ); + + if ( localaddr != NULL && ( g_strrstr( localaddr, "127" ) == NULL ) ) { + g_print( "[%s] Trying the address %s (err = %d).\n", + __FUNCTION__, localaddr, err ); + g_print( "[%s] Found local address %s!\n", __FUNCTION__, localaddr ); + str = g_string_assign( str, g_strdup( localaddr ) ); + found_addr = TRUE; + break; + } + addr_info0 = addr_info0->ai_next; + }; + + if ( found_addr == FALSE ) { + g_warning("[%s] Could not determine the local hostname address. Setting to %s\n", + __FUNCTION__, localaddr ); + if ( localaddr != NULL ) + str = g_string_assign( str, localaddr ); + else + str = g_string_assign( str, "127.0.0.1" ); + } + + g_static_mutex_unlock( &mutex ); + + if (localhostname!=NULL) + g_free( localhostname ); + + return str; +} + +static void +gmyth_socket_dispose (GObject *object) +{ + GMythSocket *gmyth_socket = GMYTH_SOCKET(object); + + gmyth_socket_close_connection (gmyth_socket); + /* disconnect socket */ + G_OBJECT_CLASS (gmyth_socket_parent_class)->dispose (object); +} + +static void +gmyth_socket_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_socket_parent_class)->finalize (object); +} + +/** Creates a new instance of GMythSocket. + * + * @return a new instance of GMythSocket. + */ +GMythSocket* +gmyth_socket_new () +{ + GMythSocket *gmyth_socket = GMYTH_SOCKET (g_object_new(GMYTH_SOCKET_TYPE, NULL)); + + gmyth_socket->sd_io_ch = NULL; + + gmyth_socket->hostname = g_strdup(""); + + gmyth_socket->port = 6543; + + return gmyth_socket; +} + +/** Connects to the backend. + * + * @param gmyth_socket The GMythSocket instance. + * @param hostname The backend hostname or IP address. + * @param port The backend port. + * @return TRUE if success, FALSE if error. + */ +gboolean +gmyth_socket_connect (GMythSocket **gmyth_socket, + gchar *hostname, gint port) +{ + struct addrinfo *addr_info_data = NULL, *addr_info0 = NULL; + gint ret_code = -1; + gint errno; + gboolean ret = TRUE; + + if ( hostname == NULL ) + g_printerr ( "[%s] Invalid hostname parameter!\n", __FUNCTION__ ); + + errno = gmyth_socket_toaddrinfo( hostname, port, &addr_info_data ); + + g_return_val_if_fail( addr_info_data != NULL, FALSE ); + + /* store hostname and port number */ + (*gmyth_socket)->hostname = g_strdup( hostname ); + (*gmyth_socket)->port = port; + + for ( addr_info0 = addr_info_data; addr_info0; addr_info0 = addr_info_data->ai_next ) { + + struct sockaddr_in *sa = (struct sockaddr_in*)addr_info0->ai_addr; + /* init socket descriptor */ + (*gmyth_socket)->sd = socket( addr_info0->ai_family, addr_info0->ai_socktype, + addr_info0->ai_protocol ); + + if ( (*gmyth_socket)->sd < 0 ) + continue; + + g_debug( "[%s] hostname = %s, sock_fd = %d, addr = %s, addr_len = %d, \ + ai_family = %d, ai_protocol = %d\n", + __FUNCTION__, hostname, (*gmyth_socket)->sd, inet_ntoa( sa->sin_addr ), + addr_info0->ai_addrlen, addr_info0->ai_family, addr_info0->ai_protocol ); + + if ( ( ret_code = connect( (*gmyth_socket)->sd, (struct sockaddr *)addr_info0->ai_addr, + addr_info0->ai_addrlen ) ) < 0 ) + { + g_printerr( "[%s] Error connecting to backend!\n", __FUNCTION__ ); + if ( ret_code == ETIMEDOUT ) + g_printerr( "[%s]\tBackend host unreachable!\n", __FUNCTION__ ); + + g_printerr( "ERROR: %s\n", gai_strerror(ret_code) ); + continue; + } + + /* only will be reached if none of the error above occurred */ + break; + + } + + (*gmyth_socket)->sd_io_ch = g_io_channel_unix_new( (*gmyth_socket)->sd ); + + //if (addr_info_data != NULL ) + //freeaddrinfo( addr_info_data ); + + ret = ( ret_code == 0 ) ? TRUE : FALSE ; + + return ret; + +} + +/** Gets the GIOChannel associated to the given GMythSocket. + * + * @param gmyth_socket The GMythSocket instance. + */ +GIOChannel * +gmyth_socket_get_io_channel( GMythSocket *gmyth_socket ) +{ + g_return_val_if_fail( gmyth_socket != NULL, NULL ); + + return gmyth_socket->sd_io_ch; +} + +/** Verifies if the socket is able to read. + * + * @param gmyth_socket The GMythSocket instance. + * @return TRUE if the socket is able to read, FALSE if not. + */ +gboolean +gmyth_socket_is_able_to_read( GMythSocket *gmyth_socket ) +{ + gboolean ret = TRUE; + + /* verify if the input (read) buffer is ready to receive data */ + GIOCondition io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch ); + + if ( ( io_cond & G_IO_IN ) == 0 ) { + g_warning ("[%s] IO channel is not able to send data!\n", __FUNCTION__); + ret = FALSE; + } + + return ret; + +} + +/** Verifies if the socket is able to write. + * + * @param gmyth_socket The GMythSocket instance. + * @return TRUE if the socket is able to write, FALSE if not. + */ +gboolean +gmyth_socket_is_able_to_write( GMythSocket *gmyth_socket ) +{ + gboolean ret = TRUE; + + /* verify if the input (read) buffer is ready to receive data */ + GIOCondition io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch ); + + if ( ( ( io_cond & G_IO_OUT ) == 0 ) || ( ( io_cond & G_IO_HUP ) == 0 ) ) { + g_warning ("[%s] IO channel is not able to send data!\n", __FUNCTION__); + ret = FALSE; + } + + return ret; + +} + +/** Sends a command to the backend. + * + * @param gmyth_socket the GMythSocket instance. + * @param command The string command to be sent. + */ +gboolean +gmyth_socket_send_command(GMythSocket *gmyth_socket, GString *command) +{ + gboolean ret = TRUE; + + GIOStatus io_status = G_IO_STATUS_NORMAL; + //GIOCondition io_cond; + GError* error = NULL; + gchar *buffer = NULL; + + gsize bytes_written = 0; + + if( command == NULL || ( command->len <= 0 ) ) { + g_warning ("[%s] Invalid NULL command parameter!\n", __FUNCTION__); + ret = FALSE; + goto done; + } + + g_static_mutex_lock( &mutex ); + g_debug ("[%s] Sending command to backend: %s\n", __FUNCTION__, command->str); + + /* + io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch ); + + if ( ( io_cond & G_IO_IN ) == 0 ) { + g_warning ("[%s] IO channel is not able to send data!\n", __FUNCTION__); + ret = FALSE; + goto done; + } + */ + + buffer = g_strnfill( BUFLEN, ' ' ); + snprintf( buffer, MYTH_PROTOCOL_FIELD_SIZE+1, "%-8d", command->len); + g_print( "[%s] buffer = [%s]\n", __FUNCTION__, buffer ); + + command = g_string_prepend(command, buffer); + + g_print( "[%s] command = [%s]\n", __FUNCTION__, command->str ); + + /* write bytes to socket */ + io_status = g_io_channel_write_chars( gmyth_socket->sd_io_ch, command->str, + command->len, &bytes_written, &error ); + + + if( (io_status == G_IO_STATUS_ERROR) || ( bytes_written <= 0 ) ) { + g_warning ("[%s] Error while writing to socket", __FUNCTION__); + ret = FALSE; + } else if ( bytes_written < command->len ) { + g_warning ("[%s] Not all data was written socket", __FUNCTION__); + ret = FALSE; + } + + io_status = g_io_channel_flush( gmyth_socket->sd_io_ch, &error ); + + if ( ( bytes_written != command->len ) || ( io_status == G_IO_STATUS_ERROR ) ) + { + g_warning ("[%s] Some problem occurred when sending data to the socket\n", __FUNCTION__); + + ret = TRUE; + } + + g_static_mutex_unlock( &mutex ); +done: + if ( error != NULL ) { + g_printerr( "[%s] Error found reading data from IO channel: (%d, %s)\n", __FUNCTION__, error->code, error->message ); + ret = FALSE; + g_error_free( error ); + } + + if ( buffer!= NULL ) + g_free( buffer ); + + return ret; +} + +/** Starts Mythtv protocol level connection. Checks Mythtv protocol version + * supported by the backend and send the "ANN" command. + * + * @param gmyth_socket the GMythSocket instance. + * @param hostname_backend The backend hostname or IP address. + * @param port The backend port to connect. + * @param blocking_client A flag to choose between blocking and non-blocking + * backend connection. + */ +gboolean +gmyth_socket_connect_to_backend (GMythSocket *gmyth_socket, + gchar *hostname_backend, int port, gboolean blocking_client) +{ + if (!gmyth_socket_connect (&gmyth_socket, hostname_backend, port)) { + g_warning ("[%s] Could not open socket to backend machine", __FUNCTION__); + return FALSE; + } + + if (gmyth_socket_check_protocol_version (gmyth_socket)) { + + GString *result; + GString *base_str = g_string_new(""); + GString *hostname = NULL; + + hostname = gmyth_socket_get_local_hostname(); + + g_string_printf(base_str, "ANN %s %s 0", + (blocking_client ? "Playback" : "Monitor"), + hostname->str); + + g_debug ("[%s] Connection command sent to backend: %s", __FUNCTION__, base_str->str); + + gmyth_socket_send_command (gmyth_socket, base_str); + result = gmyth_socket_receive_response(gmyth_socket); + + if (result != NULL) { + g_debug ("[%s] Response received from backend: %s", __FUNCTION__, result->str); + g_string_free (result, TRUE); + } + + g_string_free (hostname, TRUE); + g_string_free (base_str, TRUE); + + return TRUE; + } else { + g_warning ("[%s] GMythSocket could not connect to the backend", __FUNCTION__); + return FALSE; + } + +} + +/** Closes the socket connection to the backend. + * + * @param gmyth_socket The GMythSocket instance. + */ +void +gmyth_socket_close_connection (GMythSocket *gmyth_socket) +{ + close (gmyth_socket->sd); +} + + +/** Try the MythTV version numbers, and get the version returned by + * the possible REJECT message, in order to contruct a new + * MythTV version request. + * + * @param gmyth_socket The GMythSocket instance. + * @param mythtv_version The Mythtv protocol version to be tested + */ +gboolean +gmyth_socket_check_protocol_version_number (GMythSocket *gmyth_socket, gint mythtv_version) +{ + GString *response; + GString *payload; + gchar *new_version = g_strdup(""); + gboolean res = TRUE; + +try_new_version: + payload = g_string_new ("MYTH_PROTO_VERSION"); + g_string_append_printf( payload, " %d", mythtv_version ); + + gmyth_socket_send_command(gmyth_socket, payload); + response = gmyth_socket_receive_response(gmyth_socket); + + if (response == NULL) { + g_warning ("[%s] Check protocol version error! Not answered!", __FUNCTION__); + res = FALSE; + goto done; + } + + res = g_str_has_prefix (response->str, "ACCEPT"); + if (!res) { + g_warning ("[%s] Protocol version request error: %s", __FUNCTION__, response->str); + /* get the version number returned by the REJECT message */ + if ( ( res = g_str_has_prefix (response->str, "REJECT") ) == TRUE ) { + new_version = g_strrstr( response->str, "]" ); + if (new_version!=NULL) { + ++new_version; /* skip ']' character */ + if ( new_version != NULL ) { + g_print( "[%s] got MythTV version = %s\n", __FUNCTION__, new_version ); + mythtv_version = g_ascii_strtoull( g_strdup( new_version ), NULL, 10 ); + /* do reconnection to the socket (socket is closed if the MythTV version was wrong) */ + gmyth_socket_connect( &gmyth_socket, gmyth_socket->hostname, gmyth_socket->port ); + /* g_free( new_version ); */ + goto try_new_version; + } + } + } + } + +done: + if ( payload != NULL ) + g_string_free (payload, TRUE); + if ( response != NULL ) + g_string_free (response, TRUE); +// if (new_version!=NULL) +// g_free( new_version ); + + return res; +} + +/** Verifies if the Mythtv backend supported the GMyth supported version. + * + * @param gmyth_socket The GMythSocket instance. + * @return TRUE if supports, FALSE if not. + */ +gboolean +gmyth_socket_check_protocol_version (GMythSocket *gmyth_socket) +{ + return gmyth_socket_check_protocol_version_number( gmyth_socket, MYTHTV_VERSION_DEFAULT ); +} + +/** Receives a backend answer after a gmyth_socket_send_command_call (). + * + * @param gmyth_socket The GMythSocket instance. + * @return The response received, or NULL if error or nothing was received. + */ +GString* +gmyth_socket_receive_response(GMythSocket *gmyth_socket) +{ + GIOStatus io_status = G_IO_STATUS_NORMAL; + GError* error = NULL; + gchar *buffer = NULL; + + GString *str = NULL; + + gsize bytes_read = 0; + gint len = 0; + GIOCondition io_cond; + + g_return_val_if_fail( gmyth_socket != NULL, NULL ); + + /* verify if the input (read) buffer is ready to receive data */ + + buffer = g_strnfill( BUFLEN, ' ' ); + + g_static_mutex_lock( &mutex ); + + io_status = g_io_channel_read_chars( gmyth_socket->sd_io_ch, buffer, MYTH_PROTOCOL_FIELD_SIZE, &bytes_read, &error ); + + + /* verify if the input (read) buffer is ready to receive data */ + io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch ); + + g_print ( "[%s] Bytes read = %d\n", __FUNCTION__, bytes_read ); + + if( (io_status == G_IO_STATUS_ERROR) || (bytes_read <= 0) ) { + g_warning ("[%s] Error in mythprotocol response from backend\n", __FUNCTION__); + str = NULL; + //return NULL; + } else { + + io_status = g_io_channel_flush( gmyth_socket->sd_io_ch, &error ); + /* verify if the input (read) buffer is ready to receive data */ + io_cond = g_io_channel_get_buffer_condition( gmyth_socket->sd_io_ch ); + + if ( ( io_cond & G_IO_IN ) != 0 ) { + + snprintf( buffer, MYTH_PROTOCOL_FIELD_SIZE+1, "%-8s", g_strdup(buffer)); + g_print( "[%s] buffer = [%s]\n", __FUNCTION__, buffer ); + + /* removes trailing whitespace */ + buffer = g_strstrip( buffer ); + + len = (gint)strtoull ( buffer, NULL, 10 ); + + bytes_read = 0; + io_status = g_io_channel_read_chars( gmyth_socket->sd_io_ch, buffer, len, &bytes_read, &error ); + buffer[bytes_read] = '\0'; + } + } + + g_static_mutex_unlock( &mutex ); + + g_debug ("[%s] Response received from backend: {%s}\n", __FUNCTION__, buffer); + + if ( ( bytes_read != len ) || ( io_status == G_IO_STATUS_ERROR ) ) + str = NULL; + else + str = g_string_new( buffer ); + + if ( buffer != NULL ) + g_free( buffer ); + + if ( error != NULL ) { + g_printerr( "[%s] Error found receiving response from the IO channel: (%d, %s)\n", __FUNCTION__, error->code, error->message ); + str = NULL; + g_error_free( error ); + } + + return str; +} + +/** Format a Mythtv command from the str_list entries and send it to backend. + * + * @param gmyth_socket The GMythSocket instance. + * @param str_list The string list to form the command + * @return TRUE if command was sent, FALSE if any error happens. + */ +gboolean +gmyth_socket_write_stringlist(GMythSocket *gmyth_socket, GMythStringList* str_list) +{ + + GList *tmp_list; + GPtrArray *ptr_array; + gchar *str_array; + + g_static_mutex_lock( &mutex ); + + ptr_array = g_ptr_array_sized_new(g_list_length(str_list->glist)); + + g_print( "[%s] Number of parameters = %d\n", __FUNCTION__, g_list_length(str_list->glist) ); + + // FIXME: change this implementation! + tmp_list = str_list->glist; + for(; tmp_list; tmp_list = tmp_list->next) { + if ( tmp_list->data != NULL ) + g_ptr_array_add(ptr_array, ((GString*)tmp_list->data)->str); + } + g_ptr_array_add(ptr_array, NULL); // g_str_joinv() needs a NULL terminated string + + str_array = g_strjoinv (MYTH_SEPARATOR, (gchar **) (ptr_array->pdata)); + + g_static_mutex_unlock( &mutex ); + + // Sends message to backend + // TODO: implement looping to send remaining data, and add timeout testing! + gmyth_socket_send_command(gmyth_socket, g_string_new(str_array)); + + g_free (str_array); + g_ptr_array_free (ptr_array, TRUE); + + return TRUE; +} + +/* Receives a backend command response and split it into the given string list. + * + * @param gmyth_socket The GMythSocket instance. + * @param str_list the string list to be filled. + * @return The number of received strings. + */ +gint +gmyth_socket_read_stringlist (GMythSocket *gmyth_socket, GMythStringList* str_list) +{ + GString *response; + gchar **str_array; + gint i; + + response = gmyth_socket_receive_response(gmyth_socket); + g_static_mutex_lock( &mutex ); + + gmyth_string_list_clear_all (str_list); + str_array = g_strsplit (response->str, MYTH_SEPARATOR, -1); + + for (i=0; i< g_strv_length (str_array); i++) { + gmyth_string_list_append_string (str_list, g_string_new (str_array[i])); + } + g_static_mutex_unlock( &mutex ); + + g_string_free (response, TRUE); + g_strfreev (str_array); + + return gmyth_string_list_length (str_list); +} + +/** Formats a Mythtv protocol command based on str_list and sends it to + * the connected backend. The backend response is overwritten into str_list. + * + * @param gmyth_socket The GMythSocket instance. + * @param str_list The string list to be sent, and on which the answer + * will be written. + * @return TRUE if command was sent and an answer was received, FALSE if any + * error happens. + */ +gint +gmyth_socket_sendreceive_stringlist (GMythSocket *gmyth_socket, GMythStringList *str_list) +{ + gmyth_socket_write_stringlist (gmyth_socket, str_list); + + return gmyth_socket_read_stringlist (gmyth_socket, str_list); +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_socket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_socket.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,116 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_socket.h + * + * @brief

MythTV socket implementation, according to the MythTV Project + * (www.mythtv.org). + * + * This component provides basic socket functionalities to interact with + * the Mythtv backend. + *

+ * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Rosfran Lins Borges + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef __GMYTH_SOCKET_H__ +#define __GMYTH_SOCKET_H__ + +#include + +#include +#include +#include +#include +#include + +#include "gmyth_stringlist.h" + +#define G_BEGIN_DECLS + +#define GMYTH_SOCKET_TYPE (gmyth_socket_get_type ()) +#define GMYTH_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_SOCKET_TYPE, GMythSocket)) +#define GMYTH_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_SOCKET_TYPE, GMythSocketClass)) +#define IS_GMYTH_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_SOCKET_TYPE)) +#define IS_GMYTH_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_SOCKET_TYPE)) +#define GMYTH_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_SOCKET_TYPE, GMythSocketClass)) + + +typedef struct _GMythSocket GMythSocket; +typedef struct _GMythSocketClass GMythSocketClass; + +struct _GMythSocketClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythSocket +{ + GObject parent; + + /* socket descriptor */ + int sd; + GIOChannel *sd_io_ch; + + gchar *hostname; + gint port; +}; + + +GType gmyth_socket_get_type (void); + +GMythSocket * gmyth_socket_new (); + +GIOChannel * gmyth_socket_get_io_channel (GMythSocket *gmyth_socket ); + +gboolean gmyth_socket_is_able_to_read (GMythSocket *gmyth_socket ); +gboolean gmyth_socket_is_able_to_write (GMythSocket *gmyth_socket ); + +gboolean gmyth_socket_send_command (GMythSocket *gmyth_socket, + GString *command); +GString * gmyth_socket_receive_response (GMythSocket *gmyth_socket); +int gmyth_socket_sendreceive_stringlist (GMythSocket * gmyth_socket, + GMythStringList *str_list); + +gboolean gmyth_socket_connect (GMythSocket **gmyth_socket, + gchar *hostname, gint port); +gboolean gmyth_socket_connect_to_backend (GMythSocket *gmyth_socket, + gchar *hostname_backend, int port, + gboolean blocking_client); + +GString * gmyth_socket_get_local_hostname (); + +void gmyth_socket_close_connection (GMythSocket *gmyth_socket); + +gboolean gmyth_socket_check_protocol_version (GMythSocket *gmyth_socket); +gboolean gmyth_socket_check_protocol_version_number (GMythSocket *gmyth_socket, + gint mythtv_version); + +gboolean gmyth_socket_write_stringlist(GMythSocket *gmyth_socket, + GMythStringList* str_list); +int gmyth_socket_read_stringlist(GMythSocket *gmyth_socket, + GMythStringList* str_list); + +#define G_END_DECLS + +#endif /* __GMYTH_SOCKET_H__ */ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_stringlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_stringlist.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,272 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_stringlist.c + * + * @brief

This component contains functions for dealing with the stringlist + * format of the mythprotocol. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 "gmyth_stringlist.h" + +static void gmyth_string_list_class_init (GMythStringListClass *klass); +static void gmyth_string_list_init (GMythStringList *object); + +static void gmyth_string_list_dispose (GObject *object); +static void gmyth_string_list_finalize (GObject *object); + +G_DEFINE_TYPE(GMythStringList, gmyth_string_list, G_TYPE_OBJECT) + +static void +gmyth_string_list_class_init (GMythStringListClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_string_list_dispose; + gobject_class->finalize = gmyth_string_list_finalize; +} + +static void +gmyth_string_list_init (GMythStringList *gmyth_string_list) +{ + gmyth_string_list->glist = NULL; +} + +static void +gmyth_string_list_dispose (GObject *object) +{ + GMythStringList *gmyth_string_list = GMYTH_STRING_LIST(object); + + if (gmyth_string_list->glist) + gmyth_string_list_clear_all(gmyth_string_list); + + G_OBJECT_CLASS (gmyth_string_list_parent_class)->dispose (object); +} + +static void +gmyth_string_list_finalize (GObject *object) +{ + //GMythStringList *gmyth_string_list = GMYTH_STRING_LIST(object); + + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_string_list_parent_class)->finalize (object); +} + +/** Creates a new instance of GStringList. + * + * @return a new instance of GStringList. + */ +GMythStringList * +gmyth_string_list_new () +{ + GMythStringList *gmyth_string_list = GMYTH_STRING_LIST (g_object_new(GMYTH_STRING_LIST_TYPE, NULL)); + + return gmyth_string_list; +} + +/** Appends a guint64 to the string list. + * + * @param strlist The GMythStringList instance. + * @param value The guint64 to be appended. + * + * @return The appended guint64 converted to a GString object. + */ +GString* +gmyth_string_list_append_int ( GMythStringList *strlist, const gint value ) +{ + GString *tmp_str = g_string_new (""); + + g_string_printf (tmp_str, "%d", value); + + gmyth_string_list_append_string (strlist, tmp_str); + + return tmp_str; +} + +/** Appends a guint64 to the string list. + * + * @param strlist The GMythStringList instance. + * @param value The guint64 to be appended. + * + * @return The appended guint64 converted to a GString object. + */ +GString* +gmyth_string_list_append_uint64 ( GMythStringList *strlist, const guint64 value) +{ + GString *tmp_str = g_string_new (""); + + glong l2 = ( (guint64)(value) & 0xffffffffLL ); + glong l1 = ( ((guint64)(value) >> 32 ) & 0xffffffffLL ); + + /* high order part of guint64 value */ + g_string_printf (tmp_str, "%ld", l1); + + g_debug( "[%s] uint64 (high) = %s\n", __FUNCTION__, tmp_str->str ); + + gmyth_string_list_append_string (strlist, tmp_str); + + /* low order part of guint64 value */ + g_string_printf (tmp_str, "%ld", l2); + + g_debug( "[%s] uint64 (low) = %s\n", __FUNCTION__, tmp_str->str ); + + gmyth_string_list_append_string (strlist, tmp_str); + + return tmp_str; +} + +/** Appends a char array to the string list. + * + * @param strlist The GMythStringList instance. + * @param value The char array to be appended. + * + * @return The appended char array converted to a GString object. + */ +GString* +gmyth_string_list_append_char_array ( GMythStringList *strlist, const gchar* value ) +{ + GString *tmp_str = NULL; + + g_return_val_if_fail( strlist != NULL, NULL ); + + tmp_str = g_string_new (value); + + g_return_val_if_fail( tmp_str != NULL, NULL ); + + gmyth_string_list_append_string (strlist, tmp_str); + + return tmp_str; +} + +/** Appends a string to the string list. + * + * @param strlist The GMythStringList instance. + * @param value The string to be appended. + * + * @return The appended string itself. + */ +GString* +gmyth_string_list_append_string ( GMythStringList *strlist, GString *value ) +{ + g_return_val_if_fail( strlist != NULL, NULL ); + + strlist->glist = g_list_append (strlist->glist, value); + + return value; +} + +/** Gets an integer value from the string list at the given position. + * + * @param strlist The GMythStringList instance. + * @param index the integer position in the list, starting with zero. + * @return The integer value. + */ +gint +gmyth_string_list_get_int ( GMythStringList *strlist, const gint index ) +{ + //TODO: Create static method check_index() + GString *tmp_str = NULL; + + g_return_val_if_fail( strlist != NULL, 0 ); + + tmp_str = (GString *) g_list_nth_data (strlist->glist, index); + + g_return_val_if_fail( tmp_str != NULL && tmp_str->str != NULL, 0 ); + + return (int) ( 0x00000000ffffffffL & g_ascii_strtoull ( tmp_str->str, NULL, 0 ) ); +} + +/** Gets a guint64 value from the string list at the given position. + * According to the Mythtv protocol, the 64 bits value is formed by + * two strings. + * + * @param strlist The GMythStringList instance. + * @param index the index of the first string forming the 64 bits value. + * Index starts with zero. + * @return The guint64 value. + */ +guint64 +gmyth_string_list_get_uint64 ( GMythStringList *strlist, const gint index ) +{ + //TODO: Create static method check_index() + guint64 ret_value = 0; + + g_return_val_if_fail( strlist != NULL, 0 ); + + const GString *tmp_str1 = (GString *) g_list_nth_data (strlist->glist, index); + const GString *tmp_str2 = (GString *) g_list_nth_data (strlist->glist, index+1); + + glong l1 = (glong)g_ascii_strtoull (tmp_str1->str, NULL, 10); + glong l2 = (glong)g_ascii_strtoull (tmp_str2->str, NULL, 10); + + ret_value = ((guint64)(l2) & 0xffffffffLL) | ((guint64)(l1) << 32); + + g_debug( "[%s] returning uint64 value = %llu\n", __FUNCTION__, ret_value ); + + return ret_value; +} + +/** Gets a string from the string list at the given position. + * + * @param strlist The GMythStringList instance. + * @param index the string position in the list, starting with zero. + * @return A pointer to the string data. + */ +GString* +gmyth_string_list_get_string ( GMythStringList *strlist, const gint index ) +{ + if (!strlist || !(strlist->glist)) { + g_warning ("%s received Null arguments", __FUNCTION__); + return NULL; + } + + return (GString *) g_list_nth_data (strlist->glist, index); +} + +/** Removes all strings from the string list. + * + * @param strlist The GMythStringList instance. + */ +void +gmyth_string_list_clear_all ( GMythStringList *strlist ) +{ + if ( strlist != NULL && strlist->glist ) { + g_list_free (strlist->glist); + strlist->glist = NULL; + } +} + +/** Retrieves the number of elements in the string list. + * + * @param strlist The GMythStringList instance. + * @return the string list length. + */ +gint +gmyth_string_list_length ( GMythStringList *strlist ) +{ + g_return_val_if_fail( strlist != NULL && strlist->glist != NULL, 0 ); + + return g_list_length (strlist->glist); +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_stringlist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_stringlist.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,97 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_stringlist.h + * + * @brief

This component contains functions for dealing with the stringlist + * format of the mythprotocol. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef GMYTH_STRING_LIST_H_ +#define GMYTH_STRING_LIST_H_ + +#include + +#include +#include +#include +#include +#include +#include + +#define G_BEGIN_DECLS + +#define GMYTH_STRING_LIST_TYPE (gmyth_string_list_get_type ()) +#define GMYTH_STRING_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_STRING_LIST_TYPE, GMythStringList)) +#define GMYTH_STRING_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_STRING_LIST_TYPE, GMythStringListClass)) +#define IS_GMYTH_STRING_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_STRING_LIST_TYPE)) +#define IS_GMYTH_STRING_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_STRING_LIST_TYPE)) +#define GMYTH_STRING_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_STRING_LIST_TYPE, GMythStringListClass)) + + +typedef struct _GMythStringList GMythStringList; +typedef struct _GMythStringListClass GMythStringListClass; + +struct _GMythStringListClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythStringList +{ + GObject parent; + + /* string list */ + GList *glist; +}; + + +GType gmyth_string_list_get_type (void); + +GMythStringList * gmyth_string_list_new (); + +void gmyth_string_list_clear_all (GMythStringList *strlist); +int gmyth_string_list_length (GMythStringList *strlist); + +GString * gmyth_string_list_append_int (GMythStringList *strlist, + const gint value); +GString * gmyth_string_list_append_uint64 (GMythStringList *strlist, + const guint64 value); + +GString * gmyth_string_list_append_char_array (GMythStringList *strlist, + const char* value); +GString * gmyth_string_list_append_string (GMythStringList *strlist, + GString *value); + +int gmyth_string_list_get_int (GMythStringList *strlist, const gint index); +guint64 gmyth_string_list_get_uint64 (GMythStringList *strlist, const gint index); +GString * gmyth_string_list_get_string (GMythStringList *strlist, const gint index); + +#define gmyth_string_list_get_char_array(strlist, index) \ + (gmyth_string_list_get_string(strlist, index))->str + +#define G_END_DECLS + +#endif /*GMYTH_STRING_LIST_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_tvchain.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_tvchain.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,324 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_tvchain.c + * + * @brief

This component contains functions for creating and accessing + * the tvchain functions for live tv playback. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 +#include +#include +#include + +#include "gmyth_epg.h" +#include "gmyth_tvchain.h" +#include "gmyth_util.h" +#include "gmyth_query.h" +#include "gmyth_scheduler.h" + +static void gmyth_tvchain_class_init (GMythTVChainClass *klass); +static void gmyth_tvchain_init (GMythTVChain *object); + +static void gmyth_tvchain_dispose (GObject *object); +static void gmyth_tvchain_finalize (GObject *object); + +G_DEFINE_TYPE(GMythTVChain, gmyth_tvchain, G_TYPE_OBJECT) + +static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + +static void +gmyth_tvchain_class_init (GMythTVChainClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_tvchain_dispose; + gobject_class->finalize = gmyth_tvchain_finalize; +} + +static void +gmyth_tvchain_init (GMythTVChain *tvchain) +{ + tvchain->tvchain_id = NULL; + + tvchain->cur_chanid = g_string_new (""); + tvchain->cur_startts = 0; +} + +static void +gmyth_tvchain_dispose (GObject *object) +{ + //GMythTVChain *tvchain = GMYTH_TVCHAIN(object); + + G_OBJECT_CLASS (gmyth_tvchain_parent_class)->dispose (object); +} + +static void +gmyth_tvchain_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (gmyth_tvchain_parent_class)->finalize (object); +} + +/** Initializes the tvchain and generates the tvchain id. + * + * @param tvchain The GMythTVChain instance. + * @param hostname The local hostname used to generate the tvchain id. + */ +void +gmyth_tvchain_initialize (GMythTVChain *tvchain, GString *hostname) +{ + if (tvchain->tvchain_id == NULL) { + GString *isodate; + time_t cur_time; + + time(&cur_time); + isodate = gmyth_util_time_to_isoformat (cur_time); + + tvchain->tvchain_id = g_string_sized_new(7 + hostname->len + isodate->len); + g_string_printf(tvchain->tvchain_id, + "live-%s-%s", hostname->str, isodate->str); + + g_print("tv_chain_id: %s\n", tvchain->tvchain_id->str); + + g_string_free(isodate, TRUE); + + } else { + g_warning ("[%s] TVchain already initialized", __FUNCTION__); + } +} + +/** Gets the tvchain id. + * + * @param tvchain The GMythTVChain instance. + * @return The tvchain id. + */ +GString* +gmyth_tvchain_get_id (GMythTVChain *tvchain) +{ + return g_string_new (tvchain->tvchain_id->str); +} + +/** Reloads all tvchain entries in the database. + * + * @param tvchain The GMythTVChain instance. + * @return TRUE if success, or FALSE if error. + */ +gboolean +gmyth_tvchain_reload_all (GMythTVChain *tvchain) +{ + MYSQL_ROW msql_row; + MYSQL_RES *msql_res; + GMythQuery *gmyth_query; + + GString *stmt_str; + + g_static_mutex_lock( &mutex ); + + guint prev_size = g_list_length (tvchain->tvchain_list); + + g_debug ("[%s] chainid: %s", __FUNCTION__, tvchain->tvchain_id->str); + + g_list_free (tvchain->tvchain_list); + tvchain->tvchain_list = NULL; + + // TODO: Reuse gmyth_query already connected from context + gmyth_query = gmyth_query_new (); + if (!gmyth_query_connect (gmyth_query)) { + g_warning ("[%s] Could not connect to db", __FUNCTION__); + g_static_mutex_unlock( &mutex ); + + return FALSE; + } + + stmt_str = g_string_new (""); + g_string_printf (stmt_str, + "SELECT chanid, starttime, endtime, discontinuity, " + "chainpos, hostprefix, cardtype, channame, input " + "FROM tvchain " + "WHERE chainid = \"%s\" ORDER BY chainpos;", + tvchain->tvchain_id->str); + + msql_res = gmyth_query_process_statement(gmyth_query, stmt_str->str); + if (msql_res != NULL) { + + while ((msql_row = mysql_fetch_row (msql_res)) != NULL) { + struct LiveTVChainEntry *entry = g_new0 (struct LiveTVChainEntry, 1); + entry->chanid = g_string_new (msql_row[0]); + entry->starttime = gmyth_util_string_to_time (g_string_new ((gchar*)msql_row[1])); + entry->endtime = gmyth_util_string_to_time (g_string_new (msql_row[2])); + entry->discontinuity = atoi (msql_row[3]) != 0; + entry->hostprefix = g_string_new (msql_row[5]); + entry->cardtype = g_string_new (msql_row[6]); + entry->channum = g_string_new (msql_row[7]); + entry->inputname = g_string_new (msql_row[8]); + + //m_maxpos = query.value(4).toInt() + 1; + + tvchain->tvchain_list = g_list_append (tvchain->tvchain_list, entry); + } + } else { + g_warning ("gmyth_tvchain_reload_all query error!\n"); + g_static_mutex_unlock( &mutex ); + + return FALSE; + } + + g_static_mutex_unlock( &mutex ); + + tvchain->cur_pos = gmyth_tvchain_program_is_at (tvchain, tvchain->cur_chanid, tvchain->cur_startts); + + if (tvchain->cur_pos < 0) + tvchain->cur_pos = 0; + + // if (m_switchid >= 0) + // m_switchid = ProgramIsAt(m_switchentry.chanid,m_switchentry.starttime); + + if (prev_size != g_list_length (tvchain->tvchain_list)) { + g_debug ("[%s] Added new recording", __FUNCTION__); + } + + g_string_free (stmt_str, TRUE); + + mysql_free_result (msql_res); + + g_object_unref (gmyth_query); + + return TRUE; +} + +/** Returns the internal index for the TV chain related to the given + * channel and start time. + * + * @param tvchain The GMythTVChain instance. + * @param chanid The channel id. + * @param startts The program start time. + */ +int +gmyth_tvchain_program_is_at (GMythTVChain *tvchain, GString *chanid, time_t startts) +{ + int count = 0; + struct LiveTVChainEntry *entry; + GList *tmp_list = tvchain->tvchain_list; + + g_static_mutex_lock( &mutex ); + + for (; tmp_list; tmp_list = tvchain->tvchain_list->next, ++count) + { + entry = (struct LiveTVChainEntry*) tmp_list->data; + if (!g_strncasecmp (entry->chanid->str, chanid->str, chanid->len) + && entry->starttime == startts) + { + g_static_mutex_unlock( &mutex ); + return count; + } + } + g_static_mutex_unlock( &mutex ); + + return -1; +} + +/** Get the program info associated to the tvchain. + * + * @param tvchain The GMythTVChain instance. + * @param index The tvchain index. + * @return The program info structure. + */ +GMythProgramInfo* +gmyth_tvchain_get_program_at (GMythTVChain *tvchain, int index) +{ + struct LiveTVChainEntry *entry; + + entry = gmyth_tvchain_get_entry_at (tvchain, index); + + if (entry) + return gmyth_tvchain_entry_to_program (tvchain, entry); + + return NULL; +} + +/** Gets a LiveTVChainEntry associated to the tvchain by its index. + * + * @param tvchain The GMythTVChain instance. + * @param index The tvchain entry index + * @return The LiveTVchainEntry structure. + */ +struct LiveTVChainEntry* +gmyth_tvchain_get_entry_at (GMythTVChain *tvchain, int index) +{ + struct LiveTVChainEntry* chain_entry = NULL; + + g_static_mutex_lock( &mutex ); + + int size = g_list_length (tvchain->tvchain_list); + int new_index = (index < 0 || index >= size) ? size - 1 : index; + + if (new_index >= 0) + chain_entry = (struct LiveTVChainEntry*) g_list_nth_data (tvchain->tvchain_list, new_index); + + g_static_mutex_unlock( &mutex ); + + if ( chain_entry != NULL ) { + g_debug ("[%s] Got TV Chain entry at %d.\n", __FUNCTION__, new_index ); + + } else { + g_warning ("[%s] failed to get entry at index %d", __FUNCTION__, index); + } + + return chain_entry; +} + +/** Gets the program info from backend database associated to the tv chain entry. + * + * @param tvchain The GMythTVChain instance. + * @param entry the LiveTVChainEntry to be converted. + * @return The progrma info. + */ +GMythProgramInfo* +gmyth_tvchain_entry_to_program (GMythTVChain *tvchain, struct LiveTVChainEntry *entry) +{ + GMythProgramInfo *proginfo = NULL; + + if (!entry || !tvchain) { + g_warning ("gmyth_tvchain_entry_to_program() received NULL argument"); + return NULL; + } + + GMythScheduler *scheduler = gmyth_scheduler_new (); + + gmyth_scheduler_connect( scheduler ); + proginfo = gmyth_scheduler_get_recorded (scheduler, + entry->chanid, entry->starttime); + gmyth_scheduler_disconnect( scheduler ); + + if (proginfo) { + proginfo->pathname = g_string_prepend (proginfo->pathname, entry->hostprefix->str); + } else { + g_warning ("tvchain_entry_to_program(%s, %ld) failed!", entry->chanid->str, entry->starttime); + } + + return proginfo; +} diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_tvchain.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_tvchain.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,105 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_tvchain.h + * + * @brief

This component contains functions for creating and accessing + * the tvchain functions for live tv playback. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef LIVETVCHAIN_H_ +#define LIVETVCHAIN_H_ + +#include +#include + +#include "gmyth_common.h" + +#define G_BEGIN_DECLS + +#define GMYTH_TVCHAIN_TYPE (gmyth_tvchain_get_type ()) +#define GMYTH_TVCHAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_TVCHAIN_TYPE, GMythTVChain)) +#define GMYTH_TVCHAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_TVCHAIN_TYPE, GMythTVChainClass)) +#define IS_GMYTH_TVCHAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_TVCHAIN_TYPE)) +#define IS_GMYTH_TVCHAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_TVCHAIN_TYPE)) +#define GMYTH_TVCHAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_TVCHAIN_TYPE, GMythTVChainClass)) + + +typedef struct _GMythTVChain GMythTVChain; +typedef struct _GMythTVChainClass GMythTVChainClass; + + +struct LiveTVChainEntry +{ + GString *chanid; + + time_t starttime; + time_t endtime; + + gboolean discontinuity; // if true, can't play smooth from last entry + GString *hostprefix; + GString *cardtype; + GString *channum; + GString *inputname; +}; + + +struct _GMythTVChainClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythTVChain +{ + GObject parent; + + GString *tvchain_id; + GList *tvchain_list; + + time_t cur_startts; + GString *cur_chanid; + int cur_pos; +}; + + +GType gmyth_tvchain_get_type (void); + +void gmyth_tvchain_initialize (GMythTVChain *tvchain, + GString *hostname); +gboolean gmyth_tvchain_reload_all (GMythTVChain *tvchain); +GString* gmyth_tvchain_get_id (GMythTVChain *tvchain); +int gmyth_tvchain_program_is_at (GMythTVChain *tvchain, + GString *chanid, time_t startts); + +struct LiveTVChainEntry* gmyth_tvchain_get_entry_at (GMythTVChain *tvchain, + gint index); + +GMythProgramInfo* gmyth_tvchain_entry_to_program (GMythTVChain *tvchain, + struct LiveTVChainEntry *entry); +GMythProgramInfo* gmyth_tvchain_get_program_at (GMythTVChain *tvchain, gint index); + +#define G_END_DECLS + +#endif /*LIVETVCHAIN_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_tvplayer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_tvplayer.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,719 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_tvplayer.c + * + * @brief

This component provides playback of the remote A/V using + * GStreamer. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 "gmyth_tvplayer.h" + +#include + +#include "gmyth_context.h" +#include "gmyth_remote_util.h" + +typedef struct _GstPlayerWindowStateChange +{ + GstElement *play; + GstState old_state, new_state; + GMythTVPlayer *tvplayer; +} GstPlayerWindowStateChange; + +typedef struct _GstPlayerWindowTagFound +{ + GstElement *play; + GstTagList *taglist; + GMythTVPlayer *tvplayer; +} GstPlayerWindowTagFound; + +/* +static gboolean idle_state (gpointer data); +static gboolean bus_call (GstBus * bus, GstMessage * msg, gpointer data); +*/ + +static void gmyth_tvplayer_class_init (GMythTVPlayerClass *klass); +static void gmyth_tvplayer_init (GMythTVPlayer *object); + +static void gmyth_tvplayer_dispose (GObject *object); +static void gmyth_tvplayer_finalize (GObject *object); + +G_DEFINE_TYPE(GMythTVPlayer, gmyth_tvplayer, G_TYPE_OBJECT) + +static gboolean gmyth_tvplayer_create_pipeline (GMythTVPlayer* tvplayer); +static void new_pad_cb (GstElement *element, + GstPad *pad, gpointer data); + +static gboolean expose_cb (GtkWidget * widget, + GdkEventExpose * event, + gpointer user_data); + +static void +gmyth_tvplayer_class_init (GMythTVPlayerClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gmyth_tvplayer_dispose; + gobject_class->finalize = gmyth_tvplayer_finalize; +} + +static void +new_pad_cb (GstElement *element, GstPad *pad, gpointer data) +{ + GMythTVPlayer *tvplayer = GMYTH_TVPLAYER (data); + GstPadLinkReturn ret; + char *s; + + s = gst_caps_to_string (pad->caps); + + if ( s[0] == 'a') { + ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->audioqueue, "sink")); + } else { + ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->videoqueue, "sink")); + } + + g_free(s); +} + +static gboolean +expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer user_data) +{ + GMythTVPlayer *tvplayer = GMYTH_TVPLAYER (user_data); + + if (tvplayer && tvplayer->videow) { + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (tvplayer->gst_videosink), + GDK_WINDOW_XWINDOW (widget->window)); + return TRUE; + } + + g_warning ("GMythTVPlayer expose called before setting video window\n"); + + return FALSE; +} + +static void +gmyth_tvplayer_init (GMythTVPlayer *tvplayer) +{ + tvplayer->gst_pipeline = NULL; + tvplayer->gst_source = NULL; + tvplayer->gst_videodec = NULL; + tvplayer->gst_videosink = NULL; + tvplayer->videoqueue = NULL; + tvplayer->audioqueue = NULL; + + /* GTKWidget for rendering the video */ + tvplayer->videow = NULL; + tvplayer->expose_handler = 0; + + tvplayer->backend_hostname = NULL; + tvplayer->backend_port = 0; + tvplayer->local_hostname = NULL; + + tvplayer->remote_encoder = NULL; + tvplayer->tvchain = NULL; + tvplayer->proginfo = NULL; +} + +static void +gmyth_tvplayer_dispose (GObject *object) +{ + + G_OBJECT_CLASS (gmyth_tvplayer_parent_class)->dispose (object); +} + +static void +gmyth_tvplayer_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + GMythTVPlayer *tvplayer = GMYTH_TVPLAYER (object); + + g_debug ("[%s] Finalizing tvplayer", __FUNCTION__); + + if (tvplayer->videow != NULL) { + if (g_signal_handler_is_connected (tvplayer->videow, + tvplayer->expose_handler)) { + g_signal_handler_disconnect (tvplayer->videow, + tvplayer->expose_handler); + } + g_object_unref (tvplayer->videow); + } + + if ( tvplayer->remote_encoder != NULL ) + g_object_unref (tvplayer->remote_encoder); + if ( tvplayer->tvchain != NULL ) + g_object_unref (tvplayer->tvchain); + if ( tvplayer->proginfo != NULL ) + g_object_unref (tvplayer->proginfo); + + // Release Gstreamer elements + if ( tvplayer->gst_pipeline != NULL ) + g_object_unref (tvplayer->gst_pipeline); + if ( tvplayer->gst_source != NULL ) + g_object_unref (tvplayer->gst_source); + if ( tvplayer->gst_videodec != NULL ) + g_object_unref (tvplayer->gst_videodec); + if ( tvplayer->gst_videosink != NULL ) + g_object_unref (tvplayer->gst_videosink); + if ( tvplayer->videoqueue != NULL ) + g_object_unref (tvplayer->videoqueue); + if ( tvplayer->audioqueue != NULL ) + g_object_unref (tvplayer->audioqueue); + + G_OBJECT_CLASS (gmyth_tvplayer_parent_class)->finalize (object); +} + +/** Creates a new instance of GMythTVPlayer. + * + * @return a new instance of GMythTVPlayer. + */ +GMythTVPlayer * +gmyth_tvplayer_new () +{ + GMythTVPlayer *tvplayer = + GMYTH_TVPLAYER (g_object_new(GMYTH_TVPLAYER_TYPE, NULL)); + + return tvplayer; +} + +/** Initializes the tv player. + * + * @param tvplayer the object instance. + * @return gboolean TRUE if the pipeline was created + * successfully, FALSE otherwise. + */ +gboolean +gmyth_tvplayer_initialize (GMythTVPlayer *tvplayer) +{ + + if (!gmyth_tvplayer_create_pipeline (tvplayer)) { + g_warning ("[%s] Error while creating pipeline. TV Player not initialized", __FUNCTION__); + return FALSE; + } else { + g_debug ("[%s] GStreamer pipeline created", __FUNCTION__); + } + + return TRUE; +} + +/** Creates the GStreamer pipeline used by the player. + * + * @param tvplayer the object instance. + * @return gboolean TRUE if the pipeline was created + * successfully, FALSE otherwise. + */ +static gboolean +gmyth_tvplayer_create_pipeline (GMythTVPlayer* tvplayer) +{ + GstElement *pipeline; + GstElement *source, *parser; + GstElement *videodec, *videosink; +#ifndef MAEMO_PLATFORM + GstElement *audiodec, *audioconv; +#endif + GstElement *audiosink; + GstElement *videoqueue, *audioqueue; + + g_debug ("GMythTVPlayer: Setting the Gstreamer pipeline\n"); + + pipeline = gst_pipeline_new ("video-player"); + source = gst_element_factory_make ("mythtvsrc", "myth-source"); + parser = gst_element_factory_make ("ffdemux_nuv", "nuv-demux"); + + /* Gstreamer Video elements */ + videoqueue = gst_element_factory_make ("queue", "video-queue"); + videodec = gst_element_factory_make ("ffdec_mpeg4", "video-decoder"); +#ifdef MAEMO_PLATFORM + videosink = gst_element_factory_make ("sdlvideosink", "image-output"); +#else + videosink = gst_element_factory_make ("xvimagesink", "image-output"); +#endif + + /* Gstreamer Audio elements */ + audioqueue = gst_element_factory_make ("queue", "audio-queue"); +#ifdef MAEMO_PLATFORM + audiosink = gst_element_factory_make ("dspmp3sink", "audio-output"); +#else + audiodec = gst_element_factory_make ("ffdec_mp3", "audio-decoder"); + audioconv = gst_element_factory_make ("audioconvert", "audio-converter"); + audiosink = gst_element_factory_make ("alsasink", "audio-output"); +#endif + + if (!(pipeline && source && parser && videodec && videosink) || + !(videoqueue && audioqueue && audiosink)) { + /* FIXME: hanlde the error correctly */ + /* video_alignment is not being created (below) + and is causing problems to the ui */ + + tvplayer->gst_pipeline = NULL; + tvplayer->gst_videodec = NULL; + tvplayer->gst_videosink = NULL; + + g_warning ("GstElement creation error!\n"); + return FALSE; + } + +#ifndef MAEMO_PLATFORM + if (!(audiodec && audioconv)) { + g_warning ("GstElement for audio stream creation error!"); + return FALSE; + } +#endif + + + tvplayer->gst_pipeline = pipeline; + tvplayer->gst_source = source; + tvplayer->gst_videodec = videodec; + tvplayer->gst_videosink = videosink; + g_object_ref (tvplayer->gst_pipeline); + g_object_ref (tvplayer->gst_source); + g_object_ref (tvplayer->gst_videodec); + g_object_ref (tvplayer->gst_videosink); + + tvplayer->videoqueue = videoqueue; + tvplayer->audioqueue = audioqueue; + g_object_ref (tvplayer->videoqueue); + g_object_ref (tvplayer->audioqueue); + + g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL); + g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL); + +// gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (tvplayer->gst_pipeline)), +// bus_call, tvplayer); + + gst_bin_add_many (GST_BIN (pipeline), source, parser, videoqueue, + videodec, videosink, audioqueue, audiodec, audioconv, audiosink, NULL); + + { +// GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL); +// gst_element_link_filtered(source, parser, rtpcaps); + } + + gst_element_link (source, parser); + gst_element_link_many (videoqueue, videodec, videosink, NULL); + gst_element_link_many (audioqueue, audiodec, audioconv, audiosink, NULL); + + g_signal_connect (parser, "pad-added", G_CALLBACK (new_pad_cb), tvplayer); + + return TRUE; +} + +/** Configures the backend and the tv player + * for playing the recorded content A/V. + * + * FIXME: Change filename to program info or other structure about the recorded + * + * @param tvplayer the object instance. + * @param filename the file uri of the recorded content to be played. + * @return TRUE if successfull, FALSE if any error happens. + */ +gboolean +gmyth_tvplayer_record_setup (GMythTVPlayer *tvplayer, gchar *filename) +{ + GMythSettings *msettings = gmyth_context_get_settings(); + + // FIXME: we should receive the uri instead of filename + GString *hostname = gmyth_settings_get_backend_hostname (msettings); + int port = gmyth_settings_get_backend_port(msettings); + + GString *fullpath = g_string_new ("myth://"); + g_string_append_printf (fullpath, "%s:%d/%s", hostname->str, port, filename); + + tvplayer->is_livetv = FALSE; + + g_debug ("[%s] Setting record uri to gstreamer pipeline to %s", __FUNCTION__, fullpath->str); + + g_object_set (G_OBJECT (tvplayer->gst_source), "location", + fullpath->str, NULL); + + return TRUE; +} + +/** Configures the backend and the tv player + * for playing the live tv. + * + * @param tvplayer the object instance. + * @return TRUE if successfull, FALSE if any error happens. + */ +gboolean +gmyth_tvplayer_livetv_setup (GMythTVPlayer *tvplayer) +{ + GMythSettings *msettings = gmyth_context_get_settings (); + gboolean res = TRUE; + + res = gmyth_context_check_connection(); + if (!res) { + g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__); + res = FALSE; + goto error; + } + + tvplayer->backend_hostname = gmyth_settings_get_backend_hostname(msettings); + tvplayer->backend_port = gmyth_settings_get_backend_port (msettings); + + tvplayer->local_hostname = g_string_new(""); + gmyth_context_get_local_hostname (tvplayer->local_hostname); + + if ( tvplayer->local_hostname == NULL ) { + res = FALSE; + goto error; + } + + // Gets the remote encoder num + tvplayer->remote_encoder = remote_request_next_free_recorder (-1); + + if ( tvplayer->remote_encoder == NULL ) { + g_warning ("[%s] None remote encoder available", __FUNCTION__); + res = FALSE; + goto error; + } + + // Creates livetv chain handler + tvplayer->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) ); + gmyth_tvchain_initialize ( tvplayer->tvchain, tvplayer->local_hostname ); + + if ( tvplayer->tvchain == NULL || tvplayer->tvchain->tvchain_id == NULL ) { + res = FALSE; + goto error; + } + + // Init remote encoder. Opens its control socket. + res = gmyth_remote_encoder_setup(tvplayer->remote_encoder); + if ( !res ) { + g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__); + res = FALSE; + goto error; + } + // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly) + res = gmyth_remote_encoder_spawntv ( tvplayer->remote_encoder, + gmyth_tvchain_get_id(tvplayer->tvchain) ); + if (!res) { + g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__); + res = FALSE; + goto error; + } + + // Reload all TV chain from Mysql database. + gmyth_tvchain_reload_all (tvplayer->tvchain); + + if ( tvplayer->tvchain == NULL ) { + res = FALSE; + goto error; + } + + // Get program info from database using chanid and starttime + tvplayer->proginfo = gmyth_tvchain_get_program_at (tvplayer->tvchain, -1); + if ( tvplayer->proginfo == NULL ) { + g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ ); + res = FALSE; + goto error; + } else { + g_debug ("[%s] MythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ ); + } + + return res; + +error: + if ( tvplayer->backend_hostname != NULL ) { + g_string_free( tvplayer->backend_hostname, TRUE ); + res = FALSE; + } + + if ( tvplayer->local_hostname != NULL ) { + g_string_free( tvplayer->local_hostname, TRUE ); + res = FALSE; + } + + if ( tvplayer->remote_encoder != NULL ) { + g_object_unref (tvplayer->remote_encoder); + tvplayer->remote_encoder = NULL; + } + + if ( tvplayer->tvchain != NULL ) { + g_object_unref (tvplayer->tvchain); + tvplayer->tvchain = NULL; + } + + if ( tvplayer->proginfo != NULL ) { + g_object_unref (tvplayer->proginfo); + tvplayer->proginfo = NULL; + } + + return res; + +} + +/** Sets the GTK video widget for the tv player. + * + * @param tvplayer the object instance. + * @param videow the GTK video window. + * @return TRUE if successfull, FALSE if any error happens. + */ +gboolean +gmyth_tvplayer_set_widget (GMythTVPlayer *tvplayer, GtkWidget *videow) +{ + tvplayer->videow = videow; + g_object_ref (videow); + + g_debug ("[%s] Setting widget for tv player render", __FUNCTION__); + + tvplayer->expose_handler = g_signal_connect (tvplayer->videow, "expose-event", + G_CALLBACK (expose_cb), tvplayer); + + //g_signal_connect(miptv_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), miptv_ui); + + return TRUE; +} + +#if 0 +static gboolean +bus_call (GstBus * bus, GstMessage * msg, gpointer data) +{ + GMythTVPlayer *tvplayer = GMYTH_TVPLAYER ( data ); + GMainLoop *loop = tvplayer->loop; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_EOS: + printf ("End of stream\n"); +/* if (miptv_ui->idle_id != 0) { + g_source_remove (miptv_ui->idle_id); + miptv_ui->idle_id = 0; + }*/ + + //g_idle_add ((GSourceFunc) idle_eos, data); + gst_element_set_state (GST_ELEMENT (GST_MESSAGE_SRC (msg)), + GST_STATE_READY); + break; + case GST_MESSAGE_ERROR: + { + gchar *debug; + GError *err; + + gst_message_parse_error (msg, &err, &debug); + g_free (debug); + + printf ("Error: %s\n", err->message); + g_error_free (err); + + g_main_loop_quit (loop); + } + break; + case GST_MESSAGE_STATE_CHANGED:{ + GstState oldstate; + GstState newstate; + GstState pending; + GstPlayerWindowStateChange *st = + g_new (GstPlayerWindowStateChange, 1); + + gst_message_parse_state_changed (msg, + &oldstate, + &newstate, &pending); + + st->play = tvplayer->gst_pipeline; + gst_object_ref (GST_OBJECT (tvplayer->gst_pipeline)); + st->old_state = oldstate; + st->new_state = newstate; + + st->tvplayer = tvplayer; + + /* State debug messages */ + printf ("oldstate = %s, newstate = %s, pendingstate = %s\n", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate), + gst_element_state_get_name (pending)); + + //g_idle_add ((GSourceFunc) idle_state, st); + + } + break; + default: + printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg))); + printf ("\n"); + break; + } + + return TRUE; +} +#endif + + +#if 0 +static gboolean +idle_state (gpointer data) +{ + GstPlayerWindowStateChange *st = data; + + if (st->old_state == GST_STATE_PLAYING) { + if (st->miptv_ui->idle_id != 0) { + g_source_remove (st->miptv_ui->idle_id); + st->miptv_ui->idle_id = 0; + } + } + else if (st->new_state == GST_STATE_PLAYING) { + if (st->miptv_ui->idle_id != 0) + g_source_remove (st->miptv_ui->idle_id); + + st->miptv_ui->idle_id = g_idle_add (cb_iterate, st->miptv_ui); + } + + /* new movie loaded? */ + if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) { + + /* gboolean have_video = FALSE; */ + + gtk_widget_show (st->miptv_ui->videow); + + gtk_window_resize (GTK_WINDOW (st->miptv_ui->main_window), 1, 1); + + } + + /* discarded movie? */ + if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) { + + if (st->miptv_ui->tagcache) { + gst_tag_list_free (st->miptv_ui->tagcache); + st->miptv_ui->tagcache = NULL; + } + } + + gst_object_unref (GST_OBJECT (st->play)); + //g_object_unref (G_OBJECT (st->win)); + g_free (st); + + /* once */ + return FALSE; +} + +#endif + +/** Stops playing the current A/V. + * + * FIXME: How to proceed differently between livetv + * and recorded content? + * + * @param tvplayer the object instance. + * @return void + */ +void +gmyth_tvplayer_stop_playing (GMythTVPlayer *tvplayer) +{ + g_debug ("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__); + + gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_NULL); + + if (tvplayer->is_livetv) { + if (!gmyth_remote_encoder_stop_livetv (tvplayer->remote_encoder)) { + g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__); + } + } +} + +/** Queries if the tvplayer is active playing A/V content. + * + * @param tvplayer the object instance. + * @return TRUE if the tvplayer is active, FALSE otherwise. + */ +gboolean +gmyth_tvplayer_is_playing (GMythTVPlayer *tvplayer) +{ + return (GST_STATE (tvplayer->gst_pipeline) == GST_STATE_PLAYING); +} + +/** Static function that sets the tvplayer state to PLAYING. + * + * @param tvplayer the object instance. + * @return TRUE if the tvplayer is active, FALSE otherwise. + */ +static gboolean +idle_play (gpointer data) +{ + GMythTVPlayer *tvplayer = GMYTH_TVPLAYER (data); + + g_debug ("GMythTVPlayer: Setting pipeline state to PLAYING\n"); + + gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_PLAYING); + + return FALSE; +} + +/** Start playing A/V with the tvplayer attributes. + * + * @param tvplayer the object instance. + */ +void +gmyth_tvplayer_start_playing (GMythTVPlayer *tvplayer) +{ + + // FIXME: Move this to livetv_setup?? + if (tvplayer->is_livetv) { + + #if 0 + if (!tvplayer || !(tvplayer->proginfo) || !(tvplayer->local_hostname) + || !(tvplayer->gst_source)) { + g_warning ("GMythtvPlayer not ready to start playing\n"); + } + + if (!(tvplayer->proginfo->pathname)) { + g_warning ("[%s] Playback url is null, could not play the myth content", __FUNCTION__); + return; + } + + g_debug ("GMythTVPlayer: Start playing %s", tvplayer->proginfo->pathname->str); +#endif + g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live", + TRUE, NULL); +#if 0 + if ( tvplayer->tvchain != NULL ) { + GString *str_chainid = gmyth_tvchain_get_id(tvplayer->tvchain); + g_print( "[%s]\tCHAIN ID: %s\n", __FUNCTION__, str_chainid->str ); + + g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-chainid", + g_strdup( str_chainid->str ), NULL); + if ( str_chainid!=NULL) + g_string_free( str_chainid, FALSE ); + } + + if ( tvplayer->remote_encoder != NULL ) + g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-id", + tvplayer->remote_encoder->recorder_num, NULL ); + g_debug ("[%s] Setting location to %s", __FUNCTION__, + tvplayer->proginfo->pathname->str); + + /* Sets the gstreamer properties acording to the service access address */ + g_object_set (G_OBJECT (tvplayer->gst_source), "location", + tvplayer->proginfo->pathname->str, NULL); +#endif + } + + g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-version", + MYTHTV_VERSION_DEFAULT, NULL); + + g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-debug", + TRUE, NULL); + + g_idle_add (idle_play, tvplayer); + +} + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_tvplayer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_tvplayer.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,112 @@ +/** + * GMyth Library + * + * @file gmyth/gmyth_tvplayer.h + * + * @brief

This component provides playback of the remote A/V using + * GStreamer. + * + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. + * @author Hallyson Luiz de Morais Melo + * + *//* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Lesser 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 + */ + +#ifndef GMYTH_TVPLAYER_H_ +#define GMYTH_TVPLAYER_H_ + +#include +#include + +/* GStreamer includes */ +#include +#include + +#include "gmyth_remote_encoder.h" +#include "gmyth_tvchain.h" +#include "gmyth_common.h" + +#define G_BEGIN_DECLS + +#define GMYTH_TVPLAYER_TYPE (gmyth_tvplayer_get_type ()) +#define GMYTH_TVPLAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_TVPLAYER_TYPE, GMythTVPlayer)) +#define GMYTH_TVPLAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_TVPLAYER_TYPE, GMythTVPlayerClass)) +#define IS_GMYTH_TVPLAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMYTH_TVPLAYER_TYPE)) +#define IS_GMYTH_TVPLAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMYTH_TVPLAYER_TYPE)) +#define GMYTH_TVPLAYER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMYTH_TVPLAYER_TYPE, GMythTVPlayerClass)) + + +typedef struct _GMythTVPlayer GMythTVPlayer; +typedef struct _GMythTVPlayerClass GMythTVPlayerClass; + +struct _GMythTVPlayerClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _GMythTVPlayer +{ + GObject parent; + + GstElement *gst_pipeline; + GstElement *gst_source; + GstElement *gst_videodec; + GstElement *gst_videosink; + GstElement *videoqueue; + GstElement *audioqueue; + + gulong expose_handler; +// GMainLoop *loop; + + GtkWidget *videow; + + /* Backend connection related variables */ + GString *backend_hostname; + gint backend_port; + GString *local_hostname; + + GMythRemoteEncoder *remote_encoder; + GMythTVChain *tvchain; + GMythProgramInfo *proginfo; + + gboolean is_livetv; +}; + + +GType gmyth_tvplayer_get_type (void); + +GMythTVPlayer* gmyth_tvplayer_new (); +gboolean gmyth_tvplayer_initialize (GMythTVPlayer *tvplayer); + +void gmyth_tvplayer_start_playing (GMythTVPlayer *tvplayer); +void gmyth_tvplayer_stop_playing (GMythTVPlayer *tvplayer); + +gboolean gmyth_tvplayer_set_widget (GMythTVPlayer *tvplayer, + GtkWidget *videow); + +gboolean gmyth_tvplayer_is_playing (GMythTVPlayer *tvplayer); + +gboolean gmyth_tvplayer_record_setup (GMythTVPlayer *tvplayer, + gchar *filename); +gboolean gmyth_tvplayer_livetv_setup (GMythTVPlayer *tvplayer); + +#define G_END_DECLS + +#endif /*GMYTH_TVPLAYER_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_util.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,138 @@ +/** +* GMyth Library +* +* @file gmyth/gmyth_util.c +* +* @brief

This component provides utility functions. +* +* Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. +* @author Hallyson Luiz de Morais Melo +* +*//* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This 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 Lesser 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 "gmyth_util.h" + +#include +#include + +/** Converts a time_t struct in a GString at ISO standard format + * (e.g. 2006-07-20T09:56:41). + * + * The returned GString memory should be deallocated from + * the calling function. + * + * @param time_value the time value to be converted + * @return GString* the converted isoformat string + */ +GString* +gmyth_util_time_to_isoformat (time_t time_value) +{ + struct tm tm_time; + GString *result; + + if (localtime_r(&time_value, &tm_time) == NULL) { + g_warning ("gmyth_util_time_to_isoformat convertion error!\n"); + return NULL; + } + + result = g_string_sized_new(20); + g_string_printf(result, "%04d-%02d-%02dT%02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + + return result; +} + +/** Converts a time_t struct in a GString to the following + * format (e.g. 2006-07-20 09:56:41). + * + * The returned GString memory should be deallocated from + * the calling function. + * + * @param time_value the time value to be converted + * @return GString* the converted string + */ +GString* +gmyth_util_time_to_string (time_t time_value) +{ + GString *result = gmyth_util_time_to_isoformat (time_value); + result->str[10] = ' '; + + return result; +} + +/** Converts a GString in the following format + * (e.g. 2006-07-20 09:56:41) to a time_t struct. + * + * @param time_str the string to be converted + * @return time_t the time converted value + */ +time_t +gmyth_util_string_to_time (GString* time_str) +{ + int year, month, day, hour, min, sec; + + g_debug( "[%s] time_str = %s.\n", __FUNCTION__, time_str != NULL ? time_str->str : "[time string is NULL!]" ); + + if (sscanf (time_str->str, "%04d-%02d-%02d %02d:%02d:%02d", + &year, &month, &day, &hour, &min, &sec) < 3) { /* At least date */ + g_warning ("GMythUtil: isoformat_to_time converter error!\n"); + return 0; + } else { + struct tm tm_time; + tm_time.tm_year = year - 1900; + tm_time.tm_mon = month - 1; + tm_time.tm_mday = day; + tm_time.tm_hour = hour; + tm_time.tm_min = min; + tm_time.tm_sec = sec; + + return mktime (&tm_time); + } +} + +/** Decodes a long long variable from the string list + * format of the myhtprotocol. + * + * @param strlist the string list of mythprotocol values + * @param offset the list node offset of the long long variable + * @return guint64 the long long converted value + */ +guint64 +gmyth_util_decode_long_long(GMythStringList *strlist, guint offset) +{ + + guint64 ret_value = 0LL; + + g_return_val_if_fail( strlist != NULL, ret_value ); + + if ( offset < gmyth_string_list_length( strlist )) + g_printerr( "[%s] Offset is lower than the Stringlist (offset = %d)!\n", + __FUNCTION__, offset ); + + g_return_val_if_fail( offset < gmyth_string_list_length( strlist ), ret_value ); + + gint l1 = gmyth_string_list_get_int( strlist, offset ); + gint l2 = gmyth_string_list_get_int( strlist, offset + 1 ); + + ret_value = ((guint64)(l2) & 0xffffffffLL) | ((guint64)(l1) << 32); + + return ret_value; + +} + diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/libgmyth/gmyth_util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/libgmyth/gmyth_util.h Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,42 @@ +/** +* GMyth Library +* +* @file gmyth/gmyth_util.h +* +* @brief

This component provides utility functions. +* +* Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. +* @author Hallyson Luiz de Morais Melo +* +*//* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This 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 Lesser 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 +*/ + +#ifndef GMYTH_UTIL_H_ +#define GMYTH_UTIL_H_ + +#include +#include + +#include "gmyth_stringlist.h" + +GString * gmyth_util_time_to_isoformat(time_t time_value); +GString * gmyth_util_time_to_string (time_t time_value); +time_t gmyth_util_string_to_time (GString* time_str); +guint64 gmyth_util_decode_long_long (GMythStringList *strlist, + guint offset); + +#endif /*GMYTH_UTIL_H_*/ diff -r 20b1f3062855 -r ffdf467315ec gmyth/src/mmyth_main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gmyth/src/mmyth_main.c Wed Sep 20 23:45:35 2006 +0100 @@ -0,0 +1,103 @@ + +#include + +#include "config.h" + +#ifdef MAEMO_PLATFORM +#include "hildon-widgets/hildon-program.h" +#include "hildon-widgets/hildon-window.h" +#endif + +#include "gmyth_remote_encoder.h" +#include "gmyth_settings.h" +#include "gmyth_context.h" +#include "gmyth_tvchain.h" +#include "gmyth_tvplayer.h" +#include "gmyth_remote_util.h" + +#include "mmyth_ui.h" + +static void +cb_destroy (GtkWidget * widget, gpointer data) +{ + MMythUi *mmyth_ui = (MMythUi *) data; + + if (mmyth_ui->tvplayer != NULL) { + if (gmyth_tvplayer_is_playing (mmyth_ui->tvplayer) ) + gmyth_tvplayer_stop_playing (mmyth_ui->tvplayer); + } + + mmyth_ui_finalize (mmyth_ui); + + gtk_main_quit (); +} + +#ifdef NDEBUG +static void +debug_error_func( const gchar*log_domain, GLogLevelFlags log_level, const gchar *message, + gpointer user_data ) + +{ + /* leave this with NO print out messages, once you need to disable debug messages! */ + //g_print ( "[%s] DEBUG messages disabled!\n", __FUNCTION__ ); +} +#endif + +gint +main (gint argc, gchar * argv[]) +{ + GtkWidget *window; + MMythUi *mmyth_ui; +#ifdef MAEMO_PLATFORM + HildonProgram *program = NULL; +#endif + + /* init threads */ + g_thread_init (NULL); + + /* Initializes GTK */ + gtk_init (&argc, &argv); + gst_init (&argc, &argv); +#ifdef NDEBUG + g_log_set_default_handler( debug_error_func, NULL ); +#endif + + /* Init libmmyth context */ + gmyth_context_initialize (); + +#ifndef MAEMO_PLATFORM + /* create the main window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request (window, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT); + gtk_window_set_title (GTK_WINDOW (window), "Mythtv Frontend"); +#else + /* Creating Hildonized main view */ + program = HILDON_PROGRAM(hildon_program_get_instance()); + window = hildon_window_new(); + + //g_signal_connect(G_OBJECT(window), "delete_event", gtk_main_quit, NULL); + + hildon_program_add_window(program, HILDON_WINDOW (window)); + g_set_application_name("Maemo Mythtv"); +#endif + + /* Initializes MMyth Widgets */ +#ifdef MAEMO_PLATFORM + mmyth_ui = mmyth_ui_initialize (program, window); +#else + mmyth_ui = mmyth_ui_initialize (window); +#endif + + //mmyth_ui->loop = g_main_loop_new (NULL, FALSE); + + /* Connect destroy signal handling */ + g_signal_connect (window, "destroy", G_CALLBACK (cb_destroy), mmyth_ui); + + /* Shows main window and start gtk loop */ + gtk_widget_show (window); + + gtk_main (); + + return 0; +} +